[pypy-commit] pypy default: merge upstream
snus_mumrik
noreply at buildbot.pypy.org
Mon Jun 13 09:44:26 CEST 2011
Author: Ilya Osadchiy <osadchiy.ilya at gmail.com>
Branch:
Changeset: r44899:6b6f75812436
Date: 2011-06-03 00:11 +0300
http://bitbucket.org/pypy/pypy/changeset/6b6f75812436/
Log: merge upstream
diff --git a/pypy/annotation/annrpython.py b/pypy/annotation/annrpython.py
--- a/pypy/annotation/annrpython.py
+++ b/pypy/annotation/annrpython.py
@@ -228,7 +228,7 @@
# graph -- it's already low-level operations!
for a, s_newarg in zip(graph.getargs(), cells):
s_oldarg = self.binding(a)
- assert s_oldarg.contains(s_newarg)
+ assert annmodel.unionof(s_oldarg, s_newarg) == s_oldarg
else:
assert not self.frozen
for a in cells:
diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py
--- a/pypy/jit/backend/llsupport/regalloc.py
+++ b/pypy/jit/backend/llsupport/regalloc.py
@@ -213,6 +213,15 @@
self.reg_bindings[v] = loc
return loc
+ def force_spill_var(self, var):
+ self._sync_var(var)
+ try:
+ loc = self.reg_bindings[var]
+ del self.reg_bindings[var]
+ self.free_regs.append(loc)
+ except KeyError:
+ pass # 'var' is already not in a register
+
def loc(self, box):
""" Return the location of 'box'.
"""
diff --git a/pypy/jit/backend/test/calling_convention_test.py b/pypy/jit/backend/test/calling_convention_test.py
--- a/pypy/jit/backend/test/calling_convention_test.py
+++ b/pypy/jit/backend/test/calling_convention_test.py
@@ -23,6 +23,7 @@
def constfloat(x):
return ConstFloat(longlong.getfloatstorage(x))
+
class FakeStats(object):
pass
class TestCallingConv(Runner):
@@ -30,15 +31,131 @@
Ptr = lltype.Ptr
FuncType = lltype.FuncType
- def __init__(self):
- self.cpu = getcpuclass()(rtyper=None, stats=FakeStats())
- self.cpu.setup_once()
+ def setup_class(cls):
+ cls.cpu = getcpuclass()(rtyper=None, stats=FakeStats())
+ cls.cpu.setup_once()
+
+ def _prepare_args(self, args, floats, ints):
+ local_floats = list(floats)
+ local_ints = list(ints)
+ expected_result = 0.0
+ for i in range(len(args)):
+ x = args[i]
+ if x[0] == 'f':
+ x = local_floats.pop()
+ t = longlong.getfloatstorage(x)
+ self.cpu.set_future_value_float(i, t)
+ else:
+ x = local_ints.pop()
+ self.cpu.set_future_value_int(i, x)
+ expected_result += x
+ return expected_result
@classmethod
def get_funcbox(cls, cpu, func_ptr):
addr = llmemory.cast_ptr_to_adr(func_ptr)
return ConstInt(heaptracker.adr2int(addr))
+ def test_call_aligned_with_spilled_values(self):
+ from pypy.rlib.libffi import types
+ cpu = self.cpu
+ if not cpu.supports_floats:
+ py.test.skip('requires floats')
+
+
+ def func(*args):
+ return float(sum(args))
+
+ F = lltype.Float
+ I = lltype.Signed
+ floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
+ ints = [7, 11, 23, 13, -42, 1111, 95, 1]
+ for case in range(256):
+ local_floats = list(floats)
+ local_ints = list(ints)
+ args = []
+ spills = []
+ funcargs = []
+ float_count = 0
+ int_count = 0
+ for i in range(8):
+ if case & (1<<i):
+ args.append('f%d' % float_count)
+ spills.append('force_spill(f%d)' % float_count)
+ float_count += 1
+ funcargs.append(F)
+ else:
+ args.append('i%d' % int_count)
+ spills.append('force_spill(i%d)' % int_count)
+ int_count += 1
+ funcargs.append(I)
+
+ arguments = ', '.join(args)
+ spill_ops = '\n'.join(spills)
+
+ FUNC = self.FuncType(funcargs, F)
+ FPTR = self.Ptr(FUNC)
+ func_ptr = llhelper(FPTR, func)
+ calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+ funcbox = self.get_funcbox(cpu, func_ptr)
+
+ ops = '[%s]\n' % arguments
+ ops += '%s\n' % spill_ops
+ ops += 'f99 = call(ConstClass(func_ptr), %s, descr=calldescr)\n' % arguments
+ ops += 'finish(f99, %s)\n' % arguments
+
+ loop = parse(ops, namespace=locals())
+ looptoken = LoopToken()
+ done_number = self.cpu.get_fail_descr_number(loop.operations[-1].getdescr())
+ self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+ expected_result = self._prepare_args(args, floats, ints)
+
+ res = self.cpu.execute_token(looptoken)
+ x = longlong.getrealfloat(cpu.get_latest_value_float(0))
+ assert abs(x - expected_result) < 0.0001
+
+ def test_call_aligned_with_imm_values(self):
+ from pypy.rlib.libffi import types
+ cpu = self.cpu
+ if not cpu.supports_floats:
+ py.test.skip('requires floats')
+
+
+ def func(*args):
+ return float(sum(args))
+
+ F = lltype.Float
+ I = lltype.Signed
+ floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
+ ints = [7, 11, 23, 13, -42, 1111, 95, 1]
+ for case in range(256):
+ result = 0.0
+ args = []
+ argslist = []
+ local_floats = list(floats)
+ local_ints = list(ints)
+ for i in range(8):
+ if case & (1<<i):
+ args.append(F)
+ arg = local_floats.pop()
+ result += arg
+ argslist.append(constfloat(arg))
+ else:
+ args.append(I)
+ arg = local_ints.pop()
+ result += arg
+ argslist.append(ConstInt(arg))
+ FUNC = self.FuncType(args, F)
+ FPTR = self.Ptr(FUNC)
+ func_ptr = llhelper(FPTR, func)
+ calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+ funcbox = self.get_funcbox(cpu, func_ptr)
+
+ res = self.execute_operation(rop.CALL,
+ [funcbox] + argslist,
+ 'float', descr=calldescr)
+ assert abs(res.getfloat() - result) < 0.0001
+
def test_call_aligned_with_args_on_the_stack(self):
from pypy.rlib.libffi import types
cpu = self.cpu
@@ -104,21 +221,6 @@
floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56]
ints = [7, 11, 23, 42, -42, 1111, 95, 1]
- def _prepare_args(args):
- local_floats = list(floats)
- local_ints = list(ints)
- expected_result = 0.0
- for i in range(len(args)):
- x = args[i]
- if x[0] == 'f':
- x = local_floats.pop()
- t = longlong.getfloatstorage(x)
- cpu.set_future_value_float(i, t)
- else:
- x = local_ints.pop()
- cpu.set_future_value_int(i, x)
- expected_result += x
- return expected_result
for case in range(256):
float_count = 0
@@ -152,7 +254,7 @@
done_number = self.cpu.get_fail_descr_number(called_loop.operations[-1].getdescr())
self.cpu.compile_loop(called_loop.inputargs, called_loop.operations, called_looptoken)
- expected_result = _prepare_args(args)
+ expected_result = self._prepare_args(args, floats, ints)
res = cpu.execute_token(called_looptoken)
assert res.identifier == 3
t = longlong.getrealfloat(cpu.get_latest_value_float(0))
@@ -181,7 +283,7 @@
self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
# prepare call to called_loop
- _prepare_args(args)
+ self._prepare_args(args, floats, ints)
res = cpu.execute_token(othertoken)
x = longlong.getrealfloat(cpu.get_latest_value_float(0))
assert res.identifier == 4
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -268,6 +268,12 @@
return self.rm.force_allocate_reg(var, forbidden_vars,
selected_reg, need_lower_byte)
+ def force_spill_var(self, var):
+ if var.type == FLOAT:
+ return self.xrm.force_spill_var(var)
+ else:
+ return self.rm.force_spill_var(var)
+
def load_xmm_aligned_16_bytes(self, var, forbidden_vars=[]):
# Load 'var' in a register; but if it is a constant, we can return
# a 16-bytes-aligned ConstFloatLoc.
@@ -418,6 +424,8 @@
if self.can_merge_with_next_guard(op, i, operations):
oplist_with_guard[op.getopnum()](self, op, operations[i + 1])
i += 1
+ elif not we_are_translated() and op.getopnum() == -124:
+ self._consider_force_spill(op)
else:
oplist[op.getopnum()](self, op)
if op.result is not None:
@@ -1293,6 +1301,10 @@
def consider_jit_debug(self, op):
pass
+ def _consider_force_spill(self, op):
+ # This operation is used only for testing
+ self.force_spill_var(op.getarg(0))
+
def get_mark_gc_roots(self, gcrootmap, use_copy_area=False):
shape = gcrootmap.get_basic_shape(IS_X86_64)
for v, val in self.fm.frame_bindings.items():
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -124,18 +124,21 @@
return old_loop_token
if loop.preamble.operations is not None:
- send_loop_to_backend(metainterp_sd, loop, "loop")
+ send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop,
+ "loop")
record_loop_or_bridge(metainterp_sd, loop)
token = loop.preamble.token
if full_preamble_needed:
- send_loop_to_backend(metainterp_sd, loop.preamble, "entry bridge")
+ send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd,
+ loop.preamble, "entry bridge")
insert_loop_token(old_loop_tokens, loop.preamble.token)
jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
greenkey, loop.preamble.token)
record_loop_or_bridge(metainterp_sd, loop.preamble)
return token
else:
- send_loop_to_backend(metainterp_sd, loop, "loop")
+ send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop,
+ "loop")
insert_loop_token(old_loop_tokens, loop_token)
jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
greenkey, loop.token)
@@ -150,7 +153,9 @@
# XXX do we still need a list?
old_loop_tokens.append(loop_token)
-def send_loop_to_backend(metainterp_sd, loop, type):
+def send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, type):
+ jitdriver_sd.on_compile(metainterp_sd.logger_ops, loop.token,
+ loop.operations, type, greenkey)
globaldata = metainterp_sd.globaldata
loop_token = loop.token
loop_token.number = n = globaldata.loopnumbering
@@ -186,8 +191,11 @@
if metainterp_sd.warmrunnerdesc is not None: # for tests
metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(loop.token)
-def send_bridge_to_backend(metainterp_sd, faildescr, inputargs, operations,
- original_loop_token):
+def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs,
+ operations, original_loop_token):
+ n = metainterp_sd.cpu.get_fail_descr_number(faildescr)
+ jitdriver_sd.on_compile_bridge(metainterp_sd.logger_ops,
+ original_loop_token, operations, n)
if not we_are_translated():
show_loop(metainterp_sd)
TreeLoop.check_consistency_of(inputargs, operations)
@@ -204,7 +212,6 @@
metainterp_sd.stats.compiled()
metainterp_sd.log("compiled new bridge")
#
- n = metainterp_sd.cpu.get_fail_descr_number(faildescr)
metainterp_sd.logger_ops.log_bridge(inputargs, operations, n, ops_offset)
#
if metainterp_sd.warmrunnerdesc is not None: # for tests
@@ -390,8 +397,9 @@
inputargs = metainterp.history.inputargs
if not we_are_translated():
self._debug_suboperations = new_loop.operations
- send_bridge_to_backend(metainterp.staticdata, self, inputargs,
- new_loop.operations, new_loop.token)
+ send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata,
+ self, inputargs, new_loop.operations,
+ new_loop.token)
def copy_all_attributes_into(self, res):
# XXX a bit ugly to have to list them all here
@@ -570,7 +578,8 @@
# to every guard in the loop.
new_loop_token = make_loop_token(len(redargs), jitdriver_sd)
new_loop.token = new_loop_token
- send_loop_to_backend(metainterp_sd, new_loop, "entry bridge")
+ send_loop_to_backend(self.original_greenkey, metainterp.jitdriver_sd,
+ metainterp_sd, new_loop, "entry bridge")
# send the new_loop to warmspot.py, to be called directly the next time
jitdriver_sd.warmstate.attach_unoptimized_bridge_from_interp(
self.original_greenkey,
diff --git a/pypy/jit/metainterp/jitdriver.py b/pypy/jit/metainterp/jitdriver.py
--- a/pypy/jit/metainterp/jitdriver.py
+++ b/pypy/jit/metainterp/jitdriver.py
@@ -20,6 +20,7 @@
# self.portal_finishtoken... pypy.jit.metainterp.pyjitpl
# self.index ... pypy.jit.codewriter.call
# self.mainjitcode ... pypy.jit.codewriter.call
+ # self.on_compile ... pypy.jit.metainterp.warmstate
# These attributes are read by the backend in CALL_ASSEMBLER:
# self.assembler_helper_adr
diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py
--- a/pypy/jit/metainterp/logger.py
+++ b/pypy/jit/metainterp/logger.py
@@ -75,6 +75,40 @@
else:
return '?'
+ def repr_of_resop(self, memo, op, ops_offset=None):
+ if op.getopnum() == rop.DEBUG_MERGE_POINT:
+ loc = op.getarg(0)._get_str()
+ reclev = op.getarg(1).getint()
+ return "debug_merge_point('%s', %s)" % (loc, reclev)
+ if ops_offset is None:
+ offset = -1
+ else:
+ offset = ops_offset.get(op, -1)
+ if offset == -1:
+ s_offset = ""
+ else:
+ s_offset = "+%d: " % offset
+ args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())])
+ if op.result is not None:
+ res = self.repr_of_arg(memo, op.result) + " = "
+ else:
+ res = ""
+ is_guard = op.is_guard()
+ if op.getdescr() is not None:
+ descr = op.getdescr()
+ if is_guard and self.guard_number:
+ index = self.metainterp_sd.cpu.get_fail_descr_number(descr)
+ r = "<Guard%d>" % index
+ else:
+ r = self.repr_of_descr(descr)
+ args += ', descr=' + r
+ if is_guard and op.getfailargs() is not None:
+ fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg)
+ for arg in op.getfailargs()]) + ']'
+ else:
+ fail_args = ''
+ return s_offset + res + op.getopname() + '(' + args + ')' + fail_args
+
def _log_operations(self, inputargs, operations, ops_offset):
if not have_debug_prints():
return
@@ -86,37 +120,7 @@
debug_print('[' + args + ']')
for i in range(len(operations)):
op = operations[i]
- if op.getopnum() == rop.DEBUG_MERGE_POINT:
- loc = op.getarg(0)._get_str()
- reclev = op.getarg(1).getint()
- debug_print("debug_merge_point('%s', %s)" % (loc, reclev))
- continue
- offset = ops_offset.get(op, -1)
- if offset == -1:
- s_offset = ""
- else:
- s_offset = "+%d: " % offset
- args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())])
- if op.result is not None:
- res = self.repr_of_arg(memo, op.result) + " = "
- else:
- res = ""
- is_guard = op.is_guard()
- if op.getdescr() is not None:
- descr = op.getdescr()
- if is_guard and self.guard_number:
- index = self.metainterp_sd.cpu.get_fail_descr_number(descr)
- r = "<Guard%d>" % index
- else:
- r = self.repr_of_descr(descr)
- args += ', descr=' + r
- if is_guard and op.getfailargs() is not None:
- fail_args = ' [' + ", ".join([self.repr_of_arg(memo, arg)
- for arg in op.getfailargs()]) + ']'
- else:
- fail_args = ''
- debug_print(s_offset + res + op.getopname() +
- '(' + args + ')' + fail_args)
+ debug_print(self.repr_of_resop(memo, operations[i], ops_offset))
if ops_offset and None in ops_offset:
offset = ops_offset[None]
debug_print("+%d: --end of the loop--" % offset)
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -867,7 +867,6 @@
any_operation = len(self.metainterp.history.operations) > 0
jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
self.verify_green_args(jitdriver_sd, greenboxes)
- # xxx we may disable the following line in some context later
self.debug_merge_point(jitdriver_sd, self.metainterp.in_recursion,
greenboxes)
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
--- a/pypy/jit/metainterp/test/support.py
+++ b/pypy/jit/metainterp/test/support.py
@@ -51,6 +51,8 @@
greenfield_info = None
result_type = result_kind
portal_runner_ptr = "???"
+ on_compile = lambda *args: None
+ on_compile_bridge = lambda *args: None
stats = history.Stats()
cpu = CPUClass(rtyper, stats, None, False)
diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py
--- a/pypy/jit/metainterp/test/test_jitdriver.py
+++ b/pypy/jit/metainterp/test/test_jitdriver.py
@@ -10,8 +10,59 @@
def getloc2(g):
return "in jitdriver2, with g=%d" % g
+class JitDriverTests(object):
+ def test_on_compile(self):
+ called = {}
+
+ class MyJitDriver(JitDriver):
+ def on_compile(self, logger, looptoken, operations, type, n, m):
+ called[(m, n, type)] = looptoken
-class MultipleJitDriversTests:
+ driver = MyJitDriver(greens = ['n', 'm'], reds = ['i'])
+
+ def loop(n, m):
+ i = 0
+ while i < n + m:
+ driver.can_enter_jit(n=n, m=m, i=i)
+ driver.jit_merge_point(n=n, m=m, i=i)
+ i += 1
+
+ self.meta_interp(loop, [1, 4])
+ assert sorted(called.keys()) == [(4, 1, "entry bridge"), (4, 1, "loop")]
+ self.meta_interp(loop, [2, 4])
+ assert sorted(called.keys()) == [(4, 1, "entry bridge"), (4, 1, "loop"),
+ (4, 2, "entry bridge"), (4, 2, "loop")]
+
+ def test_on_compile_bridge(self):
+ called = {}
+
+ class MyJitDriver(JitDriver):
+ def on_compile(self, logger, looptoken, operations, type, n, m):
+ called[(m, n, type)] = loop
+ def on_compile_bridge(self, logger, orig_token, operations, n):
+ assert 'bridge' not in called
+ called['bridge'] = orig_token
+
+ driver = MyJitDriver(greens = ['n', 'm'], reds = ['i'])
+
+ def loop(n, m):
+ i = 0
+ while i < n + m:
+ driver.can_enter_jit(n=n, m=m, i=i)
+ driver.jit_merge_point(n=n, m=m, i=i)
+ if i >= 4:
+ i += 2
+ i += 1
+
+ self.meta_interp(loop, [1, 10])
+ assert sorted(called.keys()) == ['bridge', (10, 1, "entry bridge"),
+ (10, 1, "loop")]
+
+
+class TestLLtypeSingle(JitDriverTests, LLJitMixin):
+ pass
+
+class MultipleJitDriversTests(object):
def test_simple(self):
myjitdriver1 = JitDriver(greens=[], reds=['n', 'm'],
diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py
--- a/pypy/jit/metainterp/warmstate.py
+++ b/pypy/jit/metainterp/warmstate.py
@@ -566,6 +566,19 @@
return can_inline_greenargs(*greenargs)
self.can_inline_greenargs = can_inline_greenargs
self.can_inline_callable = can_inline_callable
+ if hasattr(jd.jitdriver, 'on_compile'):
+ def on_compile(logger, token, operations, type, greenkey):
+ greenargs = unwrap_greenkey(greenkey)
+ return jd.jitdriver.on_compile(logger, token, operations, type,
+ *greenargs)
+ def on_compile_bridge(logger, orig_token, operations, n):
+ return jd.jitdriver.on_compile_bridge(logger, orig_token,
+ operations, n)
+ jd.on_compile = on_compile
+ jd.on_compile_bridge = on_compile_bridge
+ else:
+ jd.on_compile = lambda *args: None
+ jd.on_compile_bridge = lambda *args: None
def get_assembler_token(greenkey, redboxes):
# 'redboxes' is only used to know the types of red arguments
diff --git a/pypy/jit/tl/tinyframe/test/test_tinyframe.py b/pypy/jit/tl/tinyframe/test/test_tinyframe.py
--- a/pypy/jit/tl/tinyframe/test/test_tinyframe.py
+++ b/pypy/jit/tl/tinyframe/test/test_tinyframe.py
@@ -96,11 +96,12 @@
RETURN r1
''')
s = StringIO()
+ prev = sys.stdout
sys.stdout = s
try:
interpret(code)
finally:
- sys.stdout = sys.__stdout__
+ sys.stdout = prev
lines = s.getvalue().splitlines()
assert lines == [
'0',
diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py
--- a/pypy/jit/tool/oparser.py
+++ b/pypy/jit/tool/oparser.py
@@ -6,7 +6,9 @@
from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\
ConstObj, ConstPtr, Box, BasicFailDescr, BoxFloat, ConstFloat,\
LoopToken, get_const_ptr_for_string, get_const_ptr_for_unicode
-from pypy.jit.metainterp.resoperation import rop, ResOperation, ResOpWithDescr, N_aryOp
+from pypy.jit.metainterp.resoperation import rop, ResOperation, \
+ ResOpWithDescr, N_aryOp, \
+ UnaryOp, PlainResOp
from pypy.jit.metainterp.typesystem import llhelper
from pypy.jit.codewriter.heaptracker import adr2int
from pypy.jit.codewriter import longlong
@@ -35,6 +37,23 @@
def clone(self):
return ESCAPE_OP(self.OPNUM, self.getarglist()[:], self.result, self.getdescr())
+class FORCE_SPILL(UnaryOp, PlainResOp):
+
+ OPNUM = -124
+
+ def __init__(self, opnum, args, result=None, descr=None):
+ assert result is None
+ assert descr is None
+ assert opnum == self.OPNUM
+ self.result = result
+ self.initarglist(args)
+
+ def getopnum(self):
+ return self.OPNUM
+
+ def clone(self):
+ return FORCE_SPILL(self.OPNUM, self.getarglist()[:])
+
class ExtendedTreeLoop(TreeLoop):
def getboxes(self):
@@ -220,6 +239,8 @@
except AttributeError:
if opname == 'escape':
opnum = ESCAPE_OP.OPNUM
+ elif opname == 'force_spill':
+ opnum = FORCE_SPILL.OPNUM
else:
raise ParseError("unknown op: %s" % opname)
endnum = line.rfind(')')
@@ -261,6 +282,8 @@
def create_op(self, opnum, args, result, descr):
if opnum == ESCAPE_OP.OPNUM:
return ESCAPE_OP(opnum, args, result, descr)
+ if opnum == FORCE_SPILL.OPNUM:
+ return FORCE_SPILL(opnum, args, result, descr)
else:
return ResOperation(opnum, args, result, descr)
diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -349,11 +349,11 @@
may be returned, even if no size parameter was given.""")
_decl(locals(), "readline",
- """readlines([size]) -> list of strings, each a line from the file.
+ """readline([size]) -> next line from the file, as a string.
-Call readline() repeatedly and return a list of the lines so read.
-The optional size argument, if given, is an approximate bound on the
-total number of bytes in the lines returned.""")
+Retain newline. A non-negative size argument limits the maximum
+number of bytes to return (an incomplete line may be returned then).
+Return an empty string at EOF.""")
_decl(locals(), "readlines",
"""readlines([size]) -> list of strings, each a line from the file.
diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py
--- a/pypy/module/bz2/interp_bz2.py
+++ b/pypy/module/bz2/interp_bz2.py
@@ -363,42 +363,44 @@
def seek(self, offset, whence):
READMAX = 2**18 # 256KB
- if whence == 1:
- if offset >= 0:
- read = r_longlong(0)
- while read < offset:
- count = offset - read
- if count < READMAX:
- count = intmask(count)
- else:
- count = READMAX
- read += len(self.read(count))
- else:
- pos = self.readlength + offset
- self.seek(pos, 0)
+
+ # Make offset relative to the start of the file
+ if whence == 2:
+ # Read everything to arrive at the end
+ while len(self.read(READMAX)) > 0:
+ pass
+ offset += self.readlength
+ elif whence == 1:
+ offset += self.readlength
elif whence == 0:
+ pass
+ else:
+ raise operationerrfmt(self.space.w_ValueError,
+ "Invalid value for whence: %d", whence)
+
+ # Make offset relative to the current pos
+ # Rewind iff necessary
+ if offset < self.readlength:
self.stream.seek(0, 0)
self.decompressor = W_BZ2Decompressor(self.space)
self.readlength = r_longlong(0)
self.buffer = ""
self.finished = False
- read = 0
- while read < offset:
- count = offset - read
- if count < READMAX:
- count = intmask(count)
- else:
- count = READMAX
- length = len(self.read(count))
- read += length
- if not length:
- break
else:
- # first measure the length by reading everything left
- while len(self.read(READMAX)) > 0:
- pass
- pos = self.readlength + offset
- self.seek(pos, 0)
+ offset -= self.readlength
+
+ # Seek
+ read = r_longlong(0)
+ while read < offset:
+ count = offset - read
+ if count < READMAX:
+ count = intmask(count)
+ else:
+ count = READMAX
+ length = len(self.read(count))
+ if not length:
+ break
+ read += length
def readall(self):
w_result = self.decompressor.decompress(self.stream.readall())
diff --git a/pypy/module/cpyext/test/test_sysmodule.py b/pypy/module/cpyext/test/test_sysmodule.py
--- a/pypy/module/cpyext/test/test_sysmodule.py
+++ b/pypy/module/cpyext/test/test_sysmodule.py
@@ -22,12 +22,13 @@
Py_RETURN_NONE;
""")])
import sys, StringIO
+ prev = sys.stdout
sys.stdout = StringIO.StringIO()
try:
module.writestdout()
assert sys.stdout.getvalue() == "format: 42\n"
finally:
- sys.stdout = sys.__stdout__
+ sys.stdout = prev
class TestSysModule(BaseApiTest):
def test_sysmodule(self, space, api):
diff --git a/pypy/module/oracle/__init__.py b/pypy/module/oracle/__init__.py
--- a/pypy/module/oracle/__init__.py
+++ b/pypy/module/oracle/__init__.py
@@ -28,6 +28,7 @@
appleveldefs = {
'version': 'app_oracle.version',
+ 'paramstyle': 'app_oracle.paramstyle',
'makedsn': 'app_oracle.makedsn',
'TimestampFromTicks': 'app_oracle.TimestampFromTicks',
}
diff --git a/pypy/module/oracle/app_oracle.py b/pypy/module/oracle/app_oracle.py
--- a/pypy/module/oracle/app_oracle.py
+++ b/pypy/module/oracle/app_oracle.py
@@ -1,4 +1,5 @@
version = '5.0.0'
+paramstyle = 'named'
class Warning(StandardError):
pass
diff --git a/pypy/module/oracle/interp_connect.py b/pypy/module/oracle/interp_connect.py
--- a/pypy/module/oracle/interp_connect.py
+++ b/pypy/module/oracle/interp_connect.py
@@ -159,9 +159,20 @@
# set the internal and external names; these are needed for global
# transactions but are limited in terms of the lengths of the strings
if twophase:
- raise OperationError(
- interp_error.get(space).w_NotSupportedError,
- space.wrap("XXX write me"))
+ status = roci.OCIAttrSet(
+ self.serverHandle, roci.OCI_HTYPE_SERVER,
+ "cx_Oracle", 0,
+ roci.OCI_ATTR_INTERNAL_NAME,
+ self.environment.errorHandle)
+ self.environment.checkForError(
+ status, "Connection_Connect(): set internal name")
+ status = roci.OCIAttrSet(
+ self.serverHandle, roci.OCI_HTYPE_SERVER,
+ "cx_Oracle", 0,
+ roci.OCI_ATTR_EXTERNAL_NAME,
+ self.environment.errorHandle)
+ self.environment.checkForError(
+ status, "Connection_Connect(): set external name")
# allocate the session handle
handleptr = lltype.malloc(rffi.CArrayPtr(roci.OCISession).TO,
diff --git a/pypy/module/oracle/roci.py b/pypy/module/oracle/roci.py
--- a/pypy/module/oracle/roci.py
+++ b/pypy/module/oracle/roci.py
@@ -73,7 +73,8 @@
defines = '''
OCI_ATTR_SERVER OCI_ATTR_SESSION OCI_ATTR_USERNAME OCI_ATTR_PASSWORD
OCI_ATTR_STMT_TYPE OCI_ATTR_PARAM OCI_ATTR_PARAM_COUNT OCI_ATTR_ROW_COUNT
- OCI_ATTR_NAME OCI_ATTR_SCALE OCI_ATTR_PRECISION OCI_ATTR_IS_NULL
+ OCI_ATTR_NAME OCI_ATTR_INTERNAL_NAME OCI_ATTR_EXTERNAL_NAME
+ OCI_ATTR_SCALE OCI_ATTR_PRECISION OCI_ATTR_IS_NULL
OCI_ATTR_DATA_SIZE OCI_ATTR_DATA_TYPE OCI_ATTR_REF_TDO
OCI_ATTR_SCHEMA_NAME OCI_ATTR_TYPE_NAME OCI_ATTR_TYPECODE
OCI_ATTR_NUM_TYPE_ATTRS OCI_ATTR_LIST_TYPE_ATTRS
diff --git a/pypy/module/oracle/test/test_connect.py b/pypy/module/oracle/test/test_connect.py
--- a/pypy/module/oracle/test/test_connect.py
+++ b/pypy/module/oracle/test/test_connect.py
@@ -41,6 +41,10 @@
if hasattr(self, 'cnx'):
self.cnx.close()
+ def test_constants(self):
+ assert '.' in oracle.version
+ assert oracle.paramstyle == 'named'
+
def test_connect(self):
self.cnx = oracle.connect(self.username, self.password,
self.tnsentry, threaded=True)
@@ -49,6 +53,13 @@
assert self.cnx.tnsentry == self.tnsentry
assert isinstance(self.cnx.version, str)
+ def test_connect_twophase(self):
+ self.cnx = oracle.connect(self.username, self.password,
+ self.tnsentry, twophase=True)
+ assert self.cnx.username == self.username
+ assert self.cnx.password == self.password
+ assert self.cnx.tnsentry == self.tnsentry
+
def test_singleArg(self):
self.cnx = oracle.connect("%s/%s@%s" % (self.username, self.password,
self.tnsentry))
diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py
--- a/pypy/module/pypyjit/__init__.py
+++ b/pypy/module/pypyjit/__init__.py
@@ -7,13 +7,15 @@
interpleveldefs = {
'set_param': 'interp_jit.set_param',
'residual_call': 'interp_jit.residual_call',
+ 'set_compile_hook': 'interp_jit.set_compile_hook',
}
def setup_after_space_initialization(self):
# force the __extend__ hacks to occur early
- import pypy.module.pypyjit.interp_jit
+ from pypy.module.pypyjit.interp_jit import pypyjitdriver
# add the 'defaults' attribute
from pypy.rlib.jit import PARAMETERS
space = self.space
+ pypyjitdriver.space = space
w_obj = space.wrap(PARAMETERS)
space.setattr(space.wrap(self), space.wrap('defaults'), w_obj)
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -12,6 +12,8 @@
from pypy.interpreter.pycode import PyCode, CO_GENERATOR
from pypy.interpreter.pyframe import PyFrame
from pypy.interpreter.pyopcode import ExitFrame
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.interpreter.baseobjspace import ObjSpace, W_Root
from opcode import opmap
from pypy.rlib.objectmodel import we_are_translated
@@ -49,6 +51,44 @@
greens = ['next_instr', 'is_being_profiled', 'pycode']
virtualizables = ['frame']
+ def on_compile(self, logger, looptoken, operations, type, next_instr,
+ is_being_profiled, ll_pycode):
+ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
+
+ space = self.space
+ cache = space.fromcache(Cache)
+ if space.is_true(cache.w_compile_hook):
+ memo = {}
+ list_w = [space.wrap(logger.repr_of_resop(memo, op))
+ for op in operations]
+ pycode = cast_base_ptr_to_instance(PyCode, ll_pycode)
+ try:
+ space.call_function(cache.w_compile_hook,
+ space.wrap('main'),
+ space.wrap(type),
+ space.newtuple([pycode,
+ space.wrap(next_instr),
+ space.wrap(is_being_profiled)]),
+ space.newlist(list_w))
+ except OperationError, e:
+ e.write_unraisable(space, "jit hook ", cache.w_compile_hook)
+
+ def on_compile_bridge(self, logger, orig_looptoken, operations, n):
+ space = self.space
+ cache = space.fromcache(Cache)
+ if space.is_true(cache.w_compile_hook):
+ memo = {}
+ list_w = [space.wrap(logger.repr_of_resop(memo, op))
+ for op in operations]
+ try:
+ space.call_function(cache.w_compile_hook,
+ space.wrap('main'),
+ space.wrap('bridge'),
+ space.wrap(n),
+ space.newlist(list_w))
+ except OperationError, e:
+ e.write_unraisable(space, "jit hook ", cache.w_compile_hook)
+
pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location,
get_jitcell_at = get_jitcell_at,
set_jitcell_at = set_jitcell_at,
@@ -149,3 +189,28 @@
'''For testing. Invokes callable(...), but without letting
the JIT follow the call.'''
return space.call_args(w_callable, __args__)
+
+class Cache(object):
+ def __init__(self, space):
+ self.w_compile_hook = space.w_None
+
+ at unwrap_spec(ObjSpace, W_Root)
+def set_compile_hook(space, w_hook):
+ """ set_compile_hook(hook)
+
+ Set a compiling hook that will be called each time a loop is compiled.
+ The hook will be called with the following signature:
+ hook(merge_point_type, loop_type, greenkey or guard_number, operations)
+
+ for now merge point type is always `main`
+
+ loop_type can be either `loop` `entry_bridge` or `bridge`
+ in case loop is not `bridge`, greenkey will be a set of constants
+ for jit merge point. in case it's `main` it'll be a tuple
+ (code, offset, is_being_profiled)
+
+ XXX write down what else
+ """
+ cache = space.fromcache(Cache)
+ cache.w_compile_hook = w_hook
+ return space.w_None
diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypyjit/test/test_jit_hook.py
@@ -0,0 +1,89 @@
+
+import py
+from pypy.conftest import gettestobjspace, option
+from pypy.interpreter.pycode import PyCode
+from pypy.interpreter.gateway import interp2app
+from pypy.jit.metainterp.history import LoopToken
+from pypy.jit.metainterp.resoperation import ResOperation, rop
+from pypy.jit.metainterp.logger import Logger
+from pypy.rpython.annlowlevel import (cast_instance_to_base_ptr,
+ cast_base_ptr_to_instance)
+from pypy.module.pypyjit.interp_jit import pypyjitdriver
+from pypy.jit.tool.oparser import parse
+from pypy.jit.metainterp.typesystem import llhelper
+
+class MockSD(object):
+ class cpu:
+ ts = llhelper
+
+class AppTestJitHook(object):
+ def setup_class(cls):
+ if option.runappdirect:
+ py.test.skip("Can't run this test with -A")
+ space = gettestobjspace(usemodules=('pypyjit',))
+ cls.space = space
+ w_f = space.appexec([], """():
+ def f():
+ pass
+ return f
+ """)
+ ll_code = cast_instance_to_base_ptr(w_f.code)
+ logger = Logger(MockSD())
+
+ oplist = parse("""
+ [i1, i2]
+ i3 = int_add(i1, i2)
+ guard_true(i3) []
+ """).operations
+
+ def interp_on_compile():
+ pypyjitdriver.on_compile(logger, LoopToken(), oplist, 'loop',
+ 0, False, ll_code)
+
+ def interp_on_compile_bridge():
+ pypyjitdriver.on_compile_bridge(logger, LoopToken(), oplist, 0)
+
+ cls.w_on_compile = space.wrap(interp2app(interp_on_compile))
+ cls.w_on_compile_bridge = space.wrap(interp2app(interp_on_compile_bridge))
+
+ def test_on_compile(self):
+ import pypyjit
+ all = []
+
+ def hook(*args):
+ assert args[0] == 'main'
+ assert args[1] in ['loop', 'bridge']
+ all.append(args[2:])
+
+ self.on_compile()
+ pypyjit.set_compile_hook(hook)
+ assert not all
+ self.on_compile()
+ assert len(all) == 1
+ assert all[0][0][0].co_name == 'f'
+ assert all[0][0][1] == 0
+ assert all[0][0][2] == False
+ assert len(all[0][1]) == 2
+ assert 'int_add' in all[0][1][0]
+ self.on_compile_bridge()
+ assert len(all) == 2
+ pypyjit.set_compile_hook(None)
+ self.on_compile()
+ assert len(all) == 2
+
+ def test_on_compile_exception(self):
+ import pypyjit, sys, cStringIO
+
+ def hook(*args):
+ 1/0
+
+ pypyjit.set_compile_hook(hook)
+ s = cStringIO.StringIO()
+ prev = sys.stderr
+ sys.stderr = s
+ try:
+ self.on_compile()
+ finally:
+ sys.stderr = prev
+ assert 'jit hook' in s.getvalue()
+ assert 'ZeroDivisionError' in s.getvalue()
diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py
--- a/pypy/objspace/std/test/test_floatobject.py
+++ b/pypy/objspace/std/test/test_floatobject.py
@@ -63,6 +63,19 @@
def setup_class(cls):
cls.w_py26 = cls.space.wrap(sys.version_info >= (2, 6))
+ def test_conjugate(self):
+ assert (1.).conjugate() == 1.
+ assert (-1.).conjugate() == -1.
+
+ class F(float):
+ pass
+ assert F(1.).conjugate() == 1.
+
+ class F(float):
+ def __pos__(self):
+ return 42.
+ assert F(1.).conjugate() == 1.
+
def test_negatives(self):
assert -1.1 < 0
assert -0.1 < 0
diff --git a/pypy/objspace/std/test/test_intobject.py b/pypy/objspace/std/test/test_intobject.py
--- a/pypy/objspace/std/test/test_intobject.py
+++ b/pypy/objspace/std/test/test_intobject.py
@@ -285,6 +285,19 @@
class AppTestInt:
+ def test_conjugate(self):
+ assert (1).conjugate() == 1
+ assert (-1).conjugate() == -1
+
+ class I(int):
+ pass
+ assert I(1).conjugate() == 1
+
+ class I(int):
+ def __pos__(self):
+ return 42
+ assert I(1).conjugate() == 1
+
def test_trunc(self):
import math
assert math.trunc(1) == 1
diff --git a/pypy/objspace/std/test/test_longobject.py b/pypy/objspace/std/test/test_longobject.py
--- a/pypy/objspace/std/test/test_longobject.py
+++ b/pypy/objspace/std/test/test_longobject.py
@@ -300,6 +300,11 @@
assert type(L(7).conjugate()) is long
+ class L(long):
+ def __pos__(self):
+ return 43
+ assert L(7).conjugate() == 7L
+
def test_bit_length(self):
assert 8L.bit_length() == 4
assert (-1<<40).bit_length() == 41
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -370,6 +370,24 @@
raise
set_user_param._annspecialcase_ = 'specialize:arg(0)'
+
+ def on_compile(self, logger, looptoken, operations, type, *greenargs):
+ """ A hook called when loop is compiled. Overwrite
+ for your own jitdriver if you want to do something special, like
+ call applevel code
+ """
+
+ def on_compile_bridge(self, logger, orig_looptoken, operations, n):
+ """ A hook called when a bridge is compiled. Overwrite
+ for your own jitdriver if you want to do something special
+ """
+
+ # note: if you overwrite this functions with the above signature it'll
+ # work, but the *greenargs is different for each jitdriver, so we
+ # can't share the same methods
+ del on_compile
+ del on_compile_bridge
+
def _make_extregistryentries(self):
# workaround: we cannot declare ExtRegistryEntries for functions
# used as methods of a frozen object, but we can attach the
diff --git a/pypy/rlib/rsre/rsre_core.py b/pypy/rlib/rsre/rsre_core.py
--- a/pypy/rlib/rsre/rsre_core.py
+++ b/pypy/rlib/rsre/rsre_core.py
@@ -759,17 +759,27 @@
@specializectx
def find_repetition_end(ctx, ppos, ptr, maxcount):
end = ctx.end
- if maxcount <= 1:
- if maxcount == 1 and ptr < end:
- # Relatively common case: maxcount == 1. If we are not at the
- # end of the string, it's done by a single direct check.
- op = ctx.pat(ppos)
- for op1, checkerfn in unroll_char_checker:
- if op1 == op:
- if checkerfn(ctx, ptr, ppos):
- return ptr + 1
+ ptrp1 = ptr + 1
+ # First get rid of the cases where we don't have room for any match.
+ if maxcount <= 0 or ptrp1 > end:
return ptr
- elif maxcount != 65535:
+ # Check the first character directly. If it doesn't match, we are done.
+ # The idea is to be fast for cases like re.search("b+"), where we expect
+ # the common case to be a non-match. It's much faster with the JIT to
+ # have the non-match inlined here rather than detect it in the fre() call.
+ op = ctx.pat(ppos)
+ for op1, checkerfn in unroll_char_checker:
+ if op1 == op:
+ if checkerfn(ctx, ptr, ppos):
+ break
+ else:
+ return ptr
+ # It matches at least once. If maxcount == 1 (relatively common),
+ # then we are done.
+ if maxcount == 1:
+ return ptrp1
+ # Else we really need to count how many times it matches.
+ if maxcount != 65535:
# adjust end
end1 = ptr + maxcount
if end1 <= end:
@@ -777,7 +787,7 @@
op = ctx.pat(ppos)
for op1, fre in unroll_fre_checker:
if op1 == op:
- return fre(ctx, ptr, end, ppos)
+ return fre(ctx, ptrp1, end, ppos)
raise Error("rsre.find_repetition_end[%d]" % op)
@specializectx
diff --git a/pypy/rlib/rsre/test/test_zjit.py b/pypy/rlib/rsre/test/test_zjit.py
--- a/pypy/rlib/rsre/test/test_zjit.py
+++ b/pypy/rlib/rsre/test/test_zjit.py
@@ -160,3 +160,9 @@
res = self.meta_interp_match(r"<[\S ]+>", "<..a .. aa>")
assert res == 13
self.check_enter_count(1)
+
+
+ def test_find_repetition_end_fastpath(self):
+ res = self.meta_interp_search(r"b+", "a"*30 + "b")
+ assert res == 30
+ self.check_loops(call=0)
diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py
--- a/pypy/rlib/test/test_jit.py
+++ b/pypy/rlib/test/test_jit.py
@@ -52,9 +52,12 @@
import sys
s = StringIO()
+ prev = sys.stdout
sys.stdout = s
- dis.dis(g)
- sys.stdout = sys.__stdout__
+ try:
+ dis.dis(g)
+ finally:
+ sys.stdout = prev
x = s.getvalue().find('CALL_FUNCTION')
assert x != -1
x = s.getvalue().find('CALL_FUNCTION', x)
More information about the pypy-commit
mailing list