aboutsummaryrefslogtreecommitdiff
path: root/pypy/jit
diff options
context:
space:
mode:
authorHakan Ardo <hakan@debian.org>2010-11-17 19:41:25 +0000
committerHakan Ardo <hakan@debian.org>2010-11-17 19:41:25 +0000
commitbaf678c574081d15f0e409eb8d004c76e87b95c2 (patch)
tree1b7f8e03b86f24a6c8a44ece82fcdb6e5602fce4 /pypy/jit
parentBetter name (diff)
downloadpypy-baf678c574081d15f0e409eb8d004c76e87b95c2.tar.gz
pypy-baf678c574081d15f0e409eb8d004c76e87b95c2.tar.bz2
pypy-baf678c574081d15f0e409eb8d004c76e87b95c2.zip
svn merge -r78744:HEAD svn+ssh://hakanardo@codespeak.net/svn/pypy/trunk
Diffstat (limited to 'pypy/jit')
-rw-r--r--pypy/jit/backend/detect_cpu.py12
-rw-r--r--pypy/jit/backend/llgraph/llimpl.py4
-rw-r--r--pypy/jit/backend/llsupport/descr.py21
-rw-r--r--pypy/jit/backend/llsupport/gc.py40
-rw-r--r--pypy/jit/backend/llsupport/test/test_descr.py13
-rw-r--r--pypy/jit/backend/llsupport/test/test_gc.py88
-rw-r--r--pypy/jit/backend/test/runner_test.py12
-rw-r--r--pypy/jit/backend/x86/assembler.py72
-rw-r--r--pypy/jit/backend/x86/test/test_runner.py23
-rw-r--r--pypy/jit/backend/x86/test/test_zrpy_gc.py26
-rw-r--r--pypy/jit/backend/x86/test/test_ztranslation.py8
-rwxr-xr-xpypy/jit/backend/x86/tool/viewcode.py2
-rw-r--r--pypy/jit/codewriter/assembler.py5
-rw-r--r--pypy/jit/codewriter/call.py3
-rw-r--r--pypy/jit/codewriter/codewriter.py2
-rw-r--r--pypy/jit/codewriter/effectinfo.py68
-rw-r--r--pypy/jit/codewriter/jtransform.py11
-rw-r--r--pypy/jit/codewriter/test/test_jtransform.py32
-rw-r--r--pypy/jit/metainterp/blackhole.py4
-rw-r--r--pypy/jit/metainterp/compile.py30
-rw-r--r--pypy/jit/metainterp/logger.py3
-rw-r--r--pypy/jit/metainterp/optimizeopt/optimizer.py6
-rw-r--r--pypy/jit/metainterp/optimizeopt/string.py5
-rw-r--r--pypy/jit/metainterp/pyjitpl.py39
-rw-r--r--pypy/jit/metainterp/resoperation.py20
-rw-r--r--pypy/jit/metainterp/resume.py125
-rw-r--r--pypy/jit/metainterp/test/test_basic.py26
-rw-r--r--pypy/jit/metainterp/test/test_compile.py4
-rw-r--r--pypy/jit/metainterp/test/test_del.py9
-rw-r--r--pypy/jit/metainterp/test/test_logger.py2
-rw-r--r--pypy/jit/metainterp/test/test_optimizeopt.py128
-rw-r--r--pypy/jit/metainterp/test/test_resoperation.py7
-rw-r--r--pypy/jit/metainterp/test/test_resume.py65
-rw-r--r--pypy/jit/metainterp/test/test_virtualref.py6
-rw-r--r--pypy/jit/metainterp/test/test_ztranslation.py4
-rw-r--r--pypy/jit/metainterp/virtualizable.py18
-rw-r--r--pypy/jit/metainterp/warmspot.py3
-rw-r--r--pypy/jit/tool/loopcounter.py44
-rw-r--r--pypy/jit/tool/oparser.py2
-rw-r--r--pypy/jit/tool/pypytrace-mode.el2
-rw-r--r--pypy/jit/tool/pypytrace.vim6
-rw-r--r--pypy/jit/tool/test/test_oparser.py (renamed from pypy/jit/metainterp/test/test_oparser.py)10
-rw-r--r--pypy/jit/tool/test/test_traceviewer.py4
43 files changed, 713 insertions, 301 deletions
diff --git a/pypy/jit/backend/detect_cpu.py b/pypy/jit/backend/detect_cpu.py
index ada7c3428f..9ea8e843bb 100644
--- a/pypy/jit/backend/detect_cpu.py
+++ b/pypy/jit/backend/detect_cpu.py
@@ -34,7 +34,17 @@ def autodetect_main_model():
'x86_64': 'x86',
}[mach]
except KeyError:
- raise ProcessorAutodetectError, "unsupported processor '%s'" % mach
+ return mach
+
+def autodetect_main_model_and_size():
+ model = autodetect_main_model()
+ if sys.maxint == 2**31-1:
+ model += '_32'
+ elif sys.maxint == 2**63-1:
+ model += '_64'
+ else:
+ raise AssertionError, "bad value for sys.maxint"
+ return model
def autodetect():
model = autodetect_main_model()
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
index deefa7f57d..40e2aa2560 100644
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -152,7 +152,7 @@ TYPES = {
'unicodegetitem' : (('ref', 'int'), 'int'),
'unicodesetitem' : (('ref', 'int', 'int'), 'int'),
'cast_ptr_to_int' : (('ref',), 'int'),
- 'debug_merge_point': (('ref',), None),
+ 'debug_merge_point': (('ref', 'int'), None),
'force_token' : ((), 'int'),
'call_may_force' : (('int', 'varargs'), 'intorptr'),
'guard_not_forced': ((), None),
@@ -568,7 +568,7 @@ class Frame(object):
#
return _op_default_implementation
- def op_debug_merge_point(self, _, value):
+ def op_debug_merge_point(self, _, value, recdepth):
from pypy.jit.metainterp.warmspot import get_stats
loc = ConstPtr(value)._get_str()
get_stats().add_merge_point_location(loc)
diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py
index b5fdc24dff..be7d563e06 100644
--- a/pypy/jit/backend/llsupport/descr.py
+++ b/pypy/jit/backend/llsupport/descr.py
@@ -130,6 +130,7 @@ def get_field_descr(gccache, STRUCT, fieldname):
# ArrayDescrs
_A = lltype.GcArray(lltype.Signed) # a random gcarray
+_AF = lltype.GcArray(lltype.Float) # an array of C doubles
class BaseArrayDescr(AbstractDescr):
@@ -171,16 +172,21 @@ class GcPtrArrayDescr(NonGcPtrArrayDescr):
_clsname = 'GcPtrArrayDescr'
_is_array_of_pointers = True
-_CA = rffi.CArray(lltype.Signed)
+class FloatArrayDescr(BaseArrayDescr):
+ _clsname = 'FloatArrayDescr'
+ _is_array_of_floats = True
+ def get_base_size(self, translate_support_code):
+ basesize, _, _ = symbolic.get_array_token(_AF, translate_support_code)
+ return basesize
+ def get_item_size(self, translate_support_code):
+ return symbolic.get_size(lltype.Float, translate_support_code)
class BaseArrayNoLengthDescr(BaseArrayDescr):
def get_base_size(self, translate_support_code):
- basesize, _, _ = symbolic.get_array_token(_CA, translate_support_code)
- return basesize
+ return 0
def get_ofs_length(self, translate_support_code):
- _, _, ofslength = symbolic.get_array_token(_CA, translate_support_code)
- return ofslength
+ return -1
class NonGcPtrArrayNoLengthDescr(BaseArrayNoLengthDescr):
_clsname = 'NonGcPtrArrayNoLengthDescr'
@@ -192,6 +198,8 @@ class GcPtrArrayNoLengthDescr(NonGcPtrArrayNoLengthDescr):
_is_array_of_pointers = True
def getArrayDescrClass(ARRAY):
+ if ARRAY.OF is lltype.Float:
+ return FloatArrayDescr
return getDescrClass(ARRAY.OF, BaseArrayDescr, GcPtrArrayDescr,
NonGcPtrArrayDescr, 'Array', 'get_item_size',
'_is_array_of_floats', '_is_item_signed')
@@ -219,7 +227,8 @@ def get_array_descr(gccache, ARRAY):
basesize, itemsize, ofslength = symbolic.get_array_token(ARRAY, False)
assert basesize == arraydescr.get_base_size(False)
assert itemsize == arraydescr.get_item_size(False)
- assert ofslength == arraydescr.get_ofs_length(False)
+ if not ARRAY._hints.get('nolength', False):
+ assert ofslength == arraydescr.get_ofs_length(False)
if isinstance(ARRAY, lltype.GcArray):
gccache.init_array_descr(ARRAY, arraydescr)
cache[ARRAY] = arraydescr
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
index 7a6e4b1274..ebce30a874 100644
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -19,6 +19,7 @@ from pypy.jit.backend.llsupport.descr import get_call_descr
# ____________________________________________________________
class GcLLDescription(GcCache):
+ minimal_size_in_nursery = 0
def __init__(self, gcdescr, translator=None, rtyper=None):
GcCache.__init__(self, translator is not None, rtyper)
self.gcdescr = gcdescr
@@ -386,6 +387,7 @@ class GcLLDescr_framework(GcLLDescription):
(self.array_basesize, _, self.array_length_ofs) = \
symbolic.get_array_token(lltype.GcArray(lltype.Signed), True)
self.max_size_of_young_obj = self.GCClass.JIT_max_size_of_young_obj()
+ self.minimal_size_in_nursery=self.GCClass.JIT_minimal_size_in_nursery()
# make a malloc function, with three arguments
def malloc_basic(size, tid):
@@ -468,6 +470,7 @@ class GcLLDescr_framework(GcLLDescription):
def malloc_fixedsize_slowpath(size):
if self.DEBUG:
random_usage_of_xmm_registers()
+ assert size >= self.minimal_size_in_nursery
try:
gcref = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
0, size, True, False, False)
@@ -570,6 +573,9 @@ class GcLLDescr_framework(GcLLDescription):
# GETFIELD_RAW from the array 'gcrefs.list'.
#
newops = []
+ # we can only remember one malloc since the next malloc can possibly
+ # collect
+ last_malloc = None
for op in operations:
if op.getopnum() == rop.DEBUG_MERGE_POINT:
continue
@@ -587,22 +593,32 @@ class GcLLDescr_framework(GcLLDescription):
[ConstInt(addr)], box,
self.single_gcref_descr))
op.setarg(i, box)
+ if op.is_malloc():
+ last_malloc = op.result
+ elif op.can_malloc():
+ last_malloc = None
# ---------- write barrier for SETFIELD_GC ----------
if op.getopnum() == rop.SETFIELD_GC:
- v = op.getarg(1)
- if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
- bool(v.value)): # store a non-NULL
- self._gen_write_barrier(newops, op.getarg(0), v)
- op = op.copy_and_change(rop.SETFIELD_RAW)
+ val = op.getarg(0)
+ # no need for a write barrier in the case of previous malloc
+ if val is not last_malloc:
+ v = op.getarg(1)
+ if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
+ bool(v.value)): # store a non-NULL
+ self._gen_write_barrier(newops, op.getarg(0), v)
+ op = op.copy_and_change(rop.SETFIELD_RAW)
# ---------- write barrier for SETARRAYITEM_GC ----------
if op.getopnum() == rop.SETARRAYITEM_GC:
- v = op.getarg(2)
- if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
- bool(v.value)): # store a non-NULL
- # XXX detect when we should produce a
- # write_barrier_from_array
- self._gen_write_barrier(newops, op.getarg(0), v)
- op = op.copy_and_change(rop.SETARRAYITEM_RAW)
+ val = op.getarg(0)
+ # no need for a write barrier in the case of previous malloc
+ if val is not last_malloc:
+ v = op.getarg(2)
+ if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
+ bool(v.value)): # store a non-NULL
+ # XXX detect when we should produce a
+ # write_barrier_from_array
+ self._gen_write_barrier(newops, op.getarg(0), v)
+ op = op.copy_and_change(rop.SETARRAYITEM_RAW)
# ----------
newops.append(op)
del operations[:]
diff --git a/pypy/jit/backend/llsupport/test/test_descr.py b/pypy/jit/backend/llsupport/test/test_descr.py
index 23a1991a5a..32d75c0637 100644
--- a/pypy/jit/backend/llsupport/test/test_descr.py
+++ b/pypy/jit/backend/llsupport/test/test_descr.py
@@ -5,6 +5,7 @@ from pypy.rlib.objectmodel import Symbolic
from pypy.rpython.annlowlevel import llhelper
from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr
from pypy.jit.metainterp import history
+import struct
def test_get_size_descr():
c0 = GcCache(False)
@@ -130,11 +131,13 @@ def test_get_array_descr():
assert not descr3.is_array_of_floats()
assert descr4.is_array_of_floats()
#
- WORD = rffi.sizeof(lltype.Signed)
- assert descr1.get_base_size(False) == WORD
- assert descr2.get_base_size(False) == WORD
- assert descr3.get_base_size(False) == WORD
- assert descr4.get_base_size(False) == WORD
+ def get_alignment(code):
+ # Retrieve default alignment for the compiler/platform
+ return struct.calcsize('l' + code) - struct.calcsize(code)
+ assert descr1.get_base_size(False) == get_alignment('c')
+ assert descr2.get_base_size(False) == get_alignment('p')
+ assert descr3.get_base_size(False) == get_alignment('p')
+ assert descr4.get_base_size(False) == get_alignment('d')
assert descr1.get_ofs_length(False) == 0
assert descr2.get_ofs_length(False) == 0
assert descr3.get_ofs_length(False) == 0
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py
index 8fc2dbb399..afd0e67275 100644
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -6,7 +6,9 @@ from pypy.jit.backend.llsupport.descr import *
from pypy.jit.backend.llsupport.gc import *
from pypy.jit.backend.llsupport import symbolic
from pypy.jit.metainterp.gc import get_description
-
+from pypy.jit.tool.oparser import parse
+from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
+from pypy.jit.metainterp.test.test_optimizeopt import equaloplists
def test_boehm():
gc_ll_descr = GcLLDescr_boehm(None, None, None)
@@ -114,7 +116,7 @@ def test_GcRootMap_asmgcc():
assert gcrootmap._gcmap[i*2+1] == expected_shapeaddr[i]
-class FakeLLOp:
+class FakeLLOp(object):
def __init__(self):
self.record = []
@@ -148,19 +150,19 @@ class FakeLLOp:
return llhelper(FPTRTYPE, self._write_barrier_failing_case)
-class TestFramework:
+class TestFramework(object):
gc = 'hybrid'
def setup_method(self, meth):
- class config_:
- class translation:
+ class config_(object):
+ class translation(object):
gc = self.gc
gcrootfinder = 'asmgcc'
gctransformer = 'framework'
gcremovetypeptr = False
- class FakeTranslator:
+ class FakeTranslator(object):
config = config_
- class FakeCPU:
+ class FakeCPU(object):
def cast_adr_to_int(self, adr):
ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR)
assert ptr._obj._callable == llop1._write_barrier_failing_case
@@ -270,7 +272,7 @@ class TestFramework:
def test_get_rid_of_debug_merge_point(self):
operations = [
- ResOperation(rop.DEBUG_MERGE_POINT, ['dummy'], None),
+ ResOperation(rop.DEBUG_MERGE_POINT, ['dummy', 2], None),
]
gc_ll_descr = self.gc_ll_descr
gc_ll_descr.rewrite_assembler(None, operations)
@@ -278,11 +280,11 @@ class TestFramework:
def test_rewrite_assembler_1(self):
# check rewriting of ConstPtrs
- class MyFakeCPU:
+ class MyFakeCPU(object):
def cast_adr_to_int(self, adr):
assert adr == "some fake address"
return 43
- class MyFakeGCRefList:
+ class MyFakeGCRefList(object):
def get_address_of_gcref(self, s_gcref1):
assert s_gcref1 == s_gcref
return "some fake address"
@@ -311,10 +313,10 @@ class TestFramework:
def test_rewrite_assembler_1_cannot_move(self):
# check rewriting of ConstPtrs
- class MyFakeCPU:
+ class MyFakeCPU(object):
def cast_adr_to_int(self, adr):
xxx # should not be called
- class MyFakeGCRefList:
+ class MyFakeGCRefList(object):
def get_address_of_gcref(self, s_gcref1):
seen.append(s_gcref1)
assert s_gcref1 == s_gcref
@@ -394,6 +396,68 @@ class TestFramework:
assert operations[1].getarg(2) == v_value
assert operations[1].getdescr() == array_descr
+ def test_rewrite_assembler_initialization_store(self):
+ S = lltype.GcStruct('S', ('parent', OBJECT),
+ ('x', lltype.Signed))
+ s_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ xdescr = get_field_descr(self.gc_ll_descr, S, 'x')
+ ops = parse("""
+ [p1]
+ p0 = new_with_vtable(ConstClass(s_vtable))
+ setfield_gc(p0, p1, descr=xdescr)
+ jump()
+ """, namespace=locals())
+ expected = parse("""
+ [p1]
+ p0 = new_with_vtable(ConstClass(s_vtable))
+ # no write barrier
+ setfield_gc(p0, p1, descr=xdescr)
+ jump()
+ """, namespace=locals())
+ self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
+ equaloplists(ops.operations, expected.operations)
+
+ def test_rewrite_assembler_initialization_store_2(self):
+ S = lltype.GcStruct('S', ('parent', OBJECT),
+ ('x', lltype.Signed))
+ s_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ wbdescr = self.gc_ll_descr.write_barrier_descr
+ xdescr = get_field_descr(self.gc_ll_descr, S, 'x')
+ ops = parse("""
+ [p1]
+ p0 = new_with_vtable(ConstClass(s_vtable))
+ p3 = new_with_vtable(ConstClass(s_vtable))
+ setfield_gc(p0, p1, descr=xdescr)
+ jump()
+ """, namespace=locals())
+ expected = parse("""
+ [p1]
+ p0 = new_with_vtable(ConstClass(s_vtable))
+ p3 = new_with_vtable(ConstClass(s_vtable))
+ cond_call_gc_wb(p0, p1, descr=wbdescr)
+ setfield_raw(p0, p1, descr=xdescr)
+ jump()
+ """, namespace=locals())
+ self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
+ equaloplists(ops.operations, expected.operations)
+
+ def test_rewrite_assembler_initialization_store_3(self):
+ A = lltype.GcArray(lltype.Ptr(lltype.GcStruct('S')))
+ arraydescr = get_array_descr(self.gc_ll_descr, A)
+ ops = parse("""
+ [p1]
+ p0 = new_array(3, descr=arraydescr)
+ setarrayitem_gc(p0, 0, p1, descr=arraydescr)
+ jump()
+ """, namespace=locals())
+ expected = parse("""
+ [p1]
+ p0 = new_array(3, descr=arraydescr)
+ setarrayitem_gc(p0, 0, p1, descr=arraydescr)
+ jump()
+ """, namespace=locals())
+ self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
+ equaloplists(ops.operations, expected.operations)
class TestFrameworkMiniMark(TestFramework):
gc = 'minimark'
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
index 95d7e3bf5a..9c437fbf00 100644
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -2168,12 +2168,14 @@ class LLtypeBackendTest(BaseBackendTest):
# Tested with a function that intentionally does not cast the
# result to RESTYPE, but makes sure that we return the whole
# value in eax or rax.
- eci = ExternalCompilationInfo(separate_module_sources=["""
+ eci = ExternalCompilationInfo(
+ separate_module_sources=["""
long fn_test_result_of_call(long x)
{
return x + 1;
}
- """])
+ """],
+ export_symbols=['fn_test_result_of_call'])
f = rffi.llexternal('fn_test_result_of_call', [lltype.Signed],
RESTYPE, compilation_info=eci, _nowrapper=True)
value = intmask(0xFFEEDDCCBBAA9988)
@@ -2199,12 +2201,14 @@ class LLtypeBackendTest(BaseBackendTest):
# Tested with a function that intentionally does not cast the
# result to RESTYPE, but makes sure that we return the whole
# value in eax or rax.
- eci = ExternalCompilationInfo(separate_module_sources=["""
+ eci = ExternalCompilationInfo(
+ separate_module_sources=["""
long fn_test_result_of_call(long x)
{
return x + 1;
}
- """])
+ """],
+ export_symbols=['fn_test_result_of_call'])
f = rffi.llexternal('fn_test_result_of_call', [lltype.Signed],
RESTYPE, compilation_info=eci, _nowrapper=True)
value = intmask(0xFFEEDDCCBBAA9988)
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
index 46caebe614..46e430ef72 100644
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -303,6 +303,7 @@ class Assembler386(object):
_x86_frame_depth
_x86_param_depth
_x86_arglocs
+ _x86_debug_checksum
"""
if not we_are_translated():
# Arguments should be unique
@@ -312,7 +313,7 @@ class Assembler386(object):
funcname = self._find_debug_merge_point(operations)
if log:
self._register_counter()
- operations = self._inject_debugging_code(operations)
+ operations = self._inject_debugging_code(looptoken, operations)
regalloc = RegAlloc(self, self.cpu.translate_support_code)
arglocs = regalloc.prepare_loop(inputargs, operations, looptoken)
@@ -336,8 +337,9 @@ class Assembler386(object):
self._assemble_bootstrap_direct_call(arglocs, curadr,
frame_depth+param_depth)
#
- debug_print("Loop #", looptoken.number, "has address",
- looptoken._x86_loop_code, "to", self.mc.tell())
+ debug_print("Loop #%d has address %x to %x" % (looptoken.number,
+ looptoken._x86_loop_code,
+ self.mc.tell()))
self.mc.end_function()
self.write_pending_failure_recoveries()
@@ -350,7 +352,7 @@ class Assembler386(object):
funcname = self._find_debug_merge_point(operations)
if log:
self._register_counter()
- operations = self._inject_debugging_code(operations)
+ operations = self._inject_debugging_code(faildescr, operations)
arglocs = self.rebuild_faillocs_from_descr(
faildescr._x86_failure_recovery_bytecode)
@@ -358,7 +360,6 @@ class Assembler386(object):
assert ([loc.assembler() for loc in arglocs] ==
[loc.assembler() for loc in faildescr._x86_debug_faillocs])
regalloc = RegAlloc(self, self.cpu.translate_support_code)
- operations = self._inject_debugging_code(operations)
fail_depths = faildescr._x86_current_depths
regalloc.prepare_bridge(fail_depths, inputargs, arglocs,
operations)
@@ -378,9 +379,8 @@ class Assembler386(object):
faildescr._x86_bridge_param_depth = param_depth
# patch the jump from original guard
self.patch_jump_for_descr(faildescr, adr_bridge)
- debug_print("Bridge out of guard",
- descr_number,
- "has address", adr_bridge, "to", self.mc.tell())
+ debug_print("Bridge out of guard %d has address %x to %x" %
+ (descr_number, adr_bridge, self.mc.tell()))
self.mc.end_function()
self.write_pending_failure_recoveries()
@@ -433,9 +433,14 @@ class Assembler386(object):
mc.done()
- def _inject_debugging_code(self, operations):
+ @specialize.argtype(1)
+ def _inject_debugging_code(self, looptoken, operations):
if self._debug:
# before doing anything, let's increase a counter
+ s = 0
+ for op in operations:
+ s += op.getopnum()
+ looptoken._x86_debug_checksum = s
c_adr = ConstInt(rffi.cast(lltype.Signed,
self.loop_run_counters[-1][1]))
box = BoxInt()
@@ -1768,13 +1773,18 @@ class Assembler386(object):
self.implement_guard(guard_token, 'L')
def genop_discard_cond_call_gc_wb(self, op, arglocs):
- # use 'mc._mc' directly instead of 'mc', to avoid
- # bad surprizes if the code buffer is mostly full
+ # Write code equivalent to write_barrier() in the GC: it checks
+ # a flag in the object at arglocs[0], and if set, it calls the
+ # function remember_young_pointer() from the GC. The two arguments
+ # to the call are in arglocs[:2]. The rest, arglocs[2:], contains
+ # registers that need to be saved and restored across the call.
descr = op.getdescr()
if we_are_translated():
cls = self.cpu.gc_ll_descr.has_write_barrier_class()
assert cls is not None and isinstance(descr, cls)
loc_base = arglocs[0]
+ # ensure that enough bytes are available to write the whole
+ # following piece of code atomically (for the JZ)
self.mc.ensure_bytes_available(256)
self.mc.TEST8_mi((loc_base.value, descr.jit_wb_if_flag_byteofs),
descr.jit_wb_if_flag_singlebyte)
@@ -1782,36 +1792,39 @@ class Assembler386(object):
jz_location = self.mc.get_relative_pos()
# the following is supposed to be the slow path, so whenever possible
# we choose the most compact encoding over the most efficient one.
- # XXX improve a bit, particularly for IS_X86_64.
- for i in range(len(arglocs)-1, -1, -1):
+ if IS_X86_32:
+ limit = -1 # push all arglocs on the stack
+ elif IS_X86_64:
+ limit = 1 # push only arglocs[2:] on the stack
+ for i in range(len(arglocs)-1, limit, -1):
loc = arglocs[i]
if isinstance(loc, RegLoc):
self.mc.PUSH_r(loc.value)
else:
- if IS_X86_64:
- self.mc.MOV_ri(X86_64_SCRATCH_REG.value, loc.getint())
- self.mc.PUSH_r(X86_64_SCRATCH_REG.value)
- else:
- self.mc.PUSH_i32(loc.getint())
-
+ assert not IS_X86_64 # there should only be regs in arglocs[2:]
+ self.mc.PUSH_i32(loc.getint())
if IS_X86_64:
# We clobber these registers to pass the arguments, but that's
# okay, because consider_cond_call_gc_wb makes sure that any
- # caller-save registers with values in them are present in arglocs,
- # so they are saved on the stack above and restored below
- self.mc.MOV_rs(edi.value, 0)
- self.mc.MOV_rs(esi.value, 8)
+ # caller-save registers with values in them are present in
+ # arglocs[2:] too, so they are saved on the stack above and
+ # restored below.
+ remap_frame_layout(self, arglocs[:2], [edi, esi],
+ X86_64_SCRATCH_REG)
# misaligned stack in the call, but it's ok because the write barrier
# is not going to call anything more. Also, this assumes that the
- # write barrier does not touch the xmm registers.
+ # write barrier does not touch the xmm registers. (Slightly delicate
+ # assumption, given that the write barrier can end up calling the
+ # platform's malloc() from AddressStack.append(). XXX may need to
+ # be done properly)
self.mc.CALL(imm(descr.get_write_barrier_fn(self.cpu)))
- for i in range(len(arglocs)):
+ if IS_X86_32:
+ self.mc.ADD_ri(esp.value, 2*WORD)
+ for i in range(2, len(arglocs)):
loc = arglocs[i]
- if isinstance(loc, RegLoc):
- self.mc.POP_r(loc.value)
- else:
- self.mc.ADD_ri(esp.value, WORD) # ignore the pushed constant
+ assert isinstance(loc, RegLoc)
+ self.mc.POP_r(loc.value)
# patch the JZ above
offset = self.mc.get_relative_pos() - jz_location
assert 0 < offset <= 127
@@ -1848,6 +1861,7 @@ class Assembler386(object):
def malloc_cond_fixedsize(self, nursery_free_adr, nursery_top_adr,
size, tid):
+ size = max(size, self.cpu.gc_ll_descr.minimal_size_in_nursery)
self.mc.ensure_bytes_available(256)
self.mc.MOV(eax, heap(nursery_free_adr))
self.mc.LEA_rm(edx.value, (eax.value, size))
diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py
index c307e515bd..05e21d5056 100644
--- a/pypy/jit/backend/x86/test/test_runner.py
+++ b/pypy/jit/backend/x86/test/test_runner.py
@@ -346,7 +346,7 @@ class TestX86(LLtypeBackendTest):
return self.val
operations = [
- ResOperation(rop.DEBUG_MERGE_POINT, [FakeString("hello")], None),
+ ResOperation(rop.DEBUG_MERGE_POINT, [FakeString("hello"), 0], None),
ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1),
ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2),
ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1),
@@ -365,7 +365,7 @@ class TestX86(LLtypeBackendTest):
bridge = [
ResOperation(rop.INT_LE, [i1b, ConstInt(19)], i3),
ResOperation(rop.GUARD_TRUE, [i3], None, descr=faildescr2),
- ResOperation(rop.DEBUG_MERGE_POINT, [FakeString("bye")], None),
+ ResOperation(rop.DEBUG_MERGE_POINT, [FakeString("bye"), 0], None),
ResOperation(rop.JUMP, [i1b], None, descr=looptoken),
]
bridge[1].setfailargs([i1b])
@@ -497,7 +497,7 @@ class TestDebuggingAssembler(object):
def test_debugger_on(self):
loop = """
[i0]
- debug_merge_point('xyz')
+ debug_merge_point('xyz', 0)
i1 = int_add(i0, 1)
i2 = int_ge(i1, 10)
guard_false(i2) []
@@ -515,3 +515,20 @@ class TestDebuggingAssembler(object):
self.cpu.finish_once()
lines = py.path.local(self.logfile + ".count").readlines()
assert lines[0] == '0:10\n' # '10 xyz\n'
+
+ def test_debugger_checksum(self):
+ loop = """
+ [i0]
+ debug_merge_point('xyz', 0)
+ i1 = int_add(i0, 1)
+ i2 = int_ge(i1, 10)
+ guard_false(i2) []
+ jump(i1)
+ """
+ ops = parse(loop)
+ self.cpu.assembler.set_debug(True)
+ self.cpu.compile_loop(ops.inputargs, ops.operations, ops.token)
+ self.cpu.set_future_value_int(0, 0)
+ self.cpu.execute_token(ops.token)
+ assert ops.token._x86_debug_checksum == sum([op.getopnum()
+ for op in ops.operations])
diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py
index 5fe1cfdb98..0fd525b09b 100644
--- a/pypy/jit/backend/x86/test/test_zrpy_gc.py
+++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py
@@ -550,3 +550,29 @@ class TestCompileFramework(object):
def test_compile_framework_float(self):
self.run('compile_framework_float')
+
+ def define_compile_framework_minimal_size_in_nursery(self):
+ S = lltype.GcStruct('S') # no fields!
+ T = lltype.GcStruct('T', ('i', lltype.Signed))
+ @unroll_safe
+ def f42(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s):
+ lst1 = []
+ lst2 = []
+ i = 0
+ while i < 42:
+ s1 = lltype.malloc(S)
+ t1 = lltype.malloc(T)
+ t1.i = 10000 + i + n
+ lst1.append(s1)
+ lst2.append(t1)
+ i += 1
+ i = 0
+ while i < 42:
+ check(lst2[i].i == 10000 + i + n)
+ i += 1
+ n -= 1
+ return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s
+ return None, f42, None
+
+ def test_compile_framework_minimal_size_in_nursery(self):
+ self.run('compile_framework_minimal_size_in_nursery')
diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py
index f3510639fd..1e3f81b553 100644
--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -2,6 +2,7 @@ import py, os, sys
from pypy.tool.udir import udir
from pypy.rlib.jit import JitDriver, OPTIMIZER_FULL, unroll_parameters
from pypy.rlib.jit import PARAMETERS, dont_look_inside
+from pypy.rlib.jit import hint
from pypy.jit.metainterp.jitprof import Profiler
from pypy.jit.backend.detect_cpu import getcpuclass
from pypy.jit.backend.test.support import CCompiledMixin
@@ -9,6 +10,7 @@ from pypy.jit.codewriter.policy import StopAtXPolicy
from pypy.translator.translator import TranslationContext
from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64
from pypy.config.translationoption import DEFL_GC
+from pypy.rlib import rgc
class TestTranslationX86(CCompiledMixin):
CPUClass = getcpuclass()
@@ -82,12 +84,12 @@ class TestTranslationX86(CCompiledMixin):
argchain.arg(x)
res = func.call(argchain, rffi.DOUBLE)
i -= 1
- return res
+ return int(res)
#
def main(i, j):
return f(i, j) + libffi_stuff(i, j)
- expected = f(40, -49)
- res = self.meta_interp(f, [40, -49])
+ expected = main(40, -49)
+ res = self.meta_interp(main, [40, -49])
assert res == expected
def test_direct_assembler_call_translates(self):
diff --git a/pypy/jit/backend/x86/tool/viewcode.py b/pypy/jit/backend/x86/tool/viewcode.py
index 33a1895121..dd0ff1606f 100755
--- a/pypy/jit/backend/x86/tool/viewcode.py
+++ b/pypy/jit/backend/x86/tool/viewcode.py
@@ -37,7 +37,7 @@ def machine_code_dump(data, originaddr, backend_name):
'x86_64': 'x86-64',
'i386': 'i386',
}
- objdump = ('objdump -M intel,%(backend)s -b binary -m i386 '
+ objdump = ('objdump -M %(backend)s -b binary -m i386 '
'--adjust-vma=%(origin)d -D %(file)s')
#
f = open(tmpfile, 'wb')
diff --git a/pypy/jit/codewriter/assembler.py b/pypy/jit/codewriter/assembler.py
index 0fb4f6051a..1fdd0d6ea2 100644
--- a/pypy/jit/codewriter/assembler.py
+++ b/pypy/jit/codewriter/assembler.py
@@ -233,10 +233,9 @@ class Assembler(object):
addr = llmemory.cast_ptr_to_adr(value)
self.list_of_addr2name.append((addr, name))
- def finished(self):
+ def finished(self, callinfocollection):
# Helper called at the end of assembling. Registers the extra
# functions shown in _callinfo_for_oopspec.
- from pypy.jit.codewriter.effectinfo import _callinfo_for_oopspec
- for _, func in _callinfo_for_oopspec.values():
+ for func in callinfocollection.all_function_addresses_as_int():
func = heaptracker.int2adr(func)
self.see_raw_object(func.ptr)
diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py
index 9dc12a7cb7..2f82e49a08 100644
--- a/pypy/jit/codewriter/call.py
+++ b/pypy/jit/codewriter/call.py
@@ -7,7 +7,7 @@ from pypy.jit.codewriter import support
from pypy.jit.codewriter.jitcode import JitCode
from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer
from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze
-from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection
from pypy.translator.simplify import get_funcobj, get_functype
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.translator.backendopt.canraise import RaiseAnalyzer
@@ -23,6 +23,7 @@ class CallControl(object):
self.jitdrivers_sd = jitdrivers_sd
self.jitcodes = {} # map {graph: jitcode}
self.unfinished_graphs = [] # list of graphs with pending jitcodes
+ self.callinfocollection = CallInfoCollection()
if hasattr(cpu, 'rtyper'): # for tests
self.rtyper = cpu.rtyper
translator = self.rtyper.annotator.translator
diff --git a/pypy/jit/codewriter/codewriter.py b/pypy/jit/codewriter/codewriter.py
index 9013ed9615..ff2c860c17 100644
--- a/pypy/jit/codewriter/codewriter.py
+++ b/pypy/jit/codewriter/codewriter.py
@@ -73,7 +73,7 @@ class CodeWriter(object):
count += 1
if not count % 500:
log.info("Produced %d jitcodes" % count)
- self.assembler.finished()
+ self.assembler.finished(self.callcontrol.callinfocollection)
heaptracker.finish_registering(self.cpu)
log.info("there are %d JitCode instances." % count)
diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
index d8c18af704..84c7edcab2 100644
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -144,30 +144,44 @@ class VirtualizableAnalyzer(BoolGraphAnalyzer):
# ____________________________________________________________
-_callinfo_for_oopspec = {} # {oopspecindex: (calldescr, func_as_int)}
-
-def callinfo_for_oopspec(oopspecindex):
- """A function that returns the calldescr and the function
- address (as an int) of one of the OS_XYZ functions defined above.
- Don't use this if there might be several implementations of the same
- OS_XYZ specialized by type, e.g. OS_ARRAYCOPY."""
- try:
- return _callinfo_for_oopspec[oopspecindex]
- except KeyError:
- return (None, 0)
-
-
-def _funcptr_for_oopspec_memo(oopspecindex):
- from pypy.jit.codewriter import heaptracker
- _, func_as_int = callinfo_for_oopspec(oopspecindex)
- funcadr = heaptracker.int2adr(func_as_int)
- return funcadr.ptr
-_funcptr_for_oopspec_memo._annspecialcase_ = 'specialize:memo'
-
-def funcptr_for_oopspec(oopspecindex):
- """A memo function that returns a pointer to the function described
- by OS_XYZ (as a real low-level function pointer)."""
- funcptr = _funcptr_for_oopspec_memo(oopspecindex)
- assert funcptr
- return funcptr
-funcptr_for_oopspec._annspecialcase_ = 'specialize:arg(0)'
+class CallInfoCollection(object):
+ def __init__(self):
+ # {oopspecindex: (calldescr, func_as_int)}
+ self._callinfo_for_oopspec = {}
+
+ def _freeze_(self):
+ return True
+
+ def add(self, oopspecindex, calldescr, func_as_int):
+ self._callinfo_for_oopspec[oopspecindex] = calldescr, func_as_int
+
+ def has_oopspec(self, oopspecindex):
+ return oopspecindex in self._callinfo_for_oopspec
+
+ def all_function_addresses_as_int(self):
+ return [func for (_, func) in self._callinfo_for_oopspec.values()]
+
+ def callinfo_for_oopspec(self, oopspecindex):
+ """A function that returns the calldescr and the function
+ address (as an int) of one of the OS_XYZ functions defined above.
+ Don't use this if there might be several implementations of the same
+ OS_XYZ specialized by type, e.g. OS_ARRAYCOPY."""
+ try:
+ return self._callinfo_for_oopspec[oopspecindex]
+ except KeyError:
+ return (None, 0)
+
+ def _funcptr_for_oopspec_memo(self, oopspecindex):
+ from pypy.jit.codewriter import heaptracker
+ _, func_as_int = self.callinfo_for_oopspec(oopspecindex)
+ funcadr = heaptracker.int2adr(func_as_int)
+ return funcadr.ptr
+ _funcptr_for_oopspec_memo._annspecialcase_ = 'specialize:memo'
+
+ def funcptr_for_oopspec(self, oopspecindex):
+ """A memo function that returns a pointer to the function described
+ by OS_XYZ (as a real low-level function pointer)."""
+ funcptr = self._funcptr_for_oopspec_memo(oopspecindex)
+ assert funcptr
+ return funcptr
+ funcptr_for_oopspec._annspecialcase_ = 'specialize:arg(1)'
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
index 326e1fe16f..68e7127e02 100644
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -6,7 +6,7 @@ from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
from pypy.objspace.flow.model import Block, Link, c_last_exception
from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
from pypy.jit.codewriter import support, heaptracker
-from pypy.jit.codewriter.effectinfo import EffectInfo, _callinfo_for_oopspec
+from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.codewriter.policy import log
from pypy.jit.metainterp.typesystem import deref, arrayItem
from pypy.rlib import objectmodel
@@ -873,6 +873,8 @@ class Transformer(object):
elif oopspec_name == 'jit.assert_green':
kind = getkind(args[0].concretetype)
return SpaceOperation('%s_assert_green' % kind, args, None)
+ elif oopspec_name == 'jit.current_trace_length':
+ return SpaceOperation('current_trace_length', [], op.result)
else:
raise AssertionError("missing support for %r" % oopspec_name)
@@ -1082,7 +1084,8 @@ class Transformer(object):
else:
func = heaptracker.adr2int(
llmemory.cast_ptr_to_adr(op.args[0].value))
- _callinfo_for_oopspec[oopspecindex] = calldescr, func
+ self.callcontrol.callinfocollection.add(oopspecindex,
+ calldescr, func)
op1 = self.rewrite_call(op, 'residual_call',
[op.args[0], calldescr],
args=args)
@@ -1093,7 +1096,7 @@ class Transformer(object):
def _register_extra_helper(self, oopspecindex, oopspec_name,
argtypes, resulttype):
# a bit hackish
- if oopspecindex in _callinfo_for_oopspec:
+ if self.callcontrol.callinfocollection.has_oopspec(oopspecindex):
return
c_func, TP = support.builtin_func_for_spec(self.cpu.rtyper,
oopspec_name, argtypes,
@@ -1107,7 +1110,7 @@ class Transformer(object):
else:
func = heaptracker.adr2int(
llmemory.cast_ptr_to_adr(c_func.value))
- _callinfo_for_oopspec[oopspecindex] = calldescr, func
+ self.callcontrol.callinfocollection.add(oopspecindex, calldescr, func)
def _handle_stroruni_call(self, op, oopspec_name, args):
SoU = args[0].concretetype # Ptr(STR) or Ptr(UNICODE)
diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py
index 760feea625..01dca13392 100644
--- a/pypy/jit/codewriter/test/test_jtransform.py
+++ b/pypy/jit/codewriter/test/test_jtransform.py
@@ -74,7 +74,20 @@ class FakeRegularIndirectCallControl:
def calldescr_canraise(self, calldescr):
return False
+class FakeCallInfoCollection:
+ def __init__(self):
+ self.seen = []
+ def add(self, oopspecindex, calldescr, func):
+ self.seen.append((oopspecindex, calldescr, func))
+ def has_oopspec(self, oopspecindex):
+ for i, c, f in self.seen:
+ if i == oopspecindex:
+ return True
+ return False
+
class FakeBuiltinCallControl:
+ def __init__(self):
+ self.callinfocollection = FakeCallInfoCollection()
def guess_call_kind(self, op):
return 'builtin'
def getcalldescr(self, op, oopspecindex=None):
@@ -810,7 +823,8 @@ def test_unicode_concat():
v2 = varoftype(PSTR)
v3 = varoftype(PSTR)
op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+ cc = FakeBuiltinCallControl()
+ tr = Transformer(FakeCPU(), cc)
op1 = tr.rewrite_operation(op)
assert op1.opname == 'residual_call_r_r'
assert op1.args[0].value == func
@@ -819,9 +833,10 @@ def test_unicode_concat():
assert op1.result == v3
#
# check the callinfo_for_oopspec
- got = effectinfo.callinfo_for_oopspec(effectinfo.EffectInfo.OS_UNI_CONCAT)
- assert got[0] == op1.args[1] # the calldescr
- assert heaptracker.int2adr(got[1]) == llmemory.cast_ptr_to_adr(func)
+ got = cc.callinfocollection.seen[0]
+ assert got[0] == effectinfo.EffectInfo.OS_UNI_CONCAT
+ assert got[1] == op1.args[1] # the calldescr
+ assert heaptracker.int2adr(got[2]) == llmemory.cast_ptr_to_adr(func)
def test_str_slice():
# test that the oopspec is present and correctly transformed
@@ -893,7 +908,8 @@ def test_unicode_eq_checknull_char():
v2 = varoftype(PUNICODE)
v3 = varoftype(lltype.Bool)
op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+ cc = FakeBuiltinCallControl()
+ tr = Transformer(FakeCPU(), cc)
op1 = tr.rewrite_operation(op)
assert op1.opname == 'residual_call_r_i'
assert op1.args[0].value == func
@@ -901,9 +917,9 @@ def test_unicode_eq_checknull_char():
assert op1.args[2] == ListOfKind('ref', [v1, v2])
assert op1.result == v3
# test that the OS_UNIEQ_* functions are registered
- cifo = effectinfo._callinfo_for_oopspec
- assert effectinfo.EffectInfo.OS_UNIEQ_SLICE_NONNULL in cifo
- assert effectinfo.EffectInfo.OS_UNIEQ_CHECKNULL_CHAR in cifo
+ cic = cc.callinfocollection
+ assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_SLICE_NONNULL)
+ assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_CHECKNULL_CHAR)
def test_list_ll_arraycopy():
from pypy.rlib.rgc import ll_arraycopy
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
index 700280971b..c67dc8b2fa 100644
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -774,6 +774,10 @@ class BlackholeInterpreter(object):
def bhimpl_float_assert_green(x):
pass
+ @arguments(returns="i")
+ def bhimpl_current_trace_length():
+ return -1
+
# ----------
# the main hints and recursive calls
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
index 31df49b3ff..342898daab 100644
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -1,4 +1,5 @@
+from pypy.rpython.lltypesystem import lltype
from pypy.rpython.ootypesystem import ootype
from pypy.objspace.flow.model import Constant, Variable
from pypy.rlib.objectmodel import we_are_translated
@@ -13,6 +14,7 @@ from pypy.jit.metainterp.history import BoxPtr, BoxObj, BoxFloat, Const
from pypy.jit.metainterp import history
from pypy.jit.metainterp.typesystem import llhelper, oohelper
from pypy.jit.metainterp.optimizeutil import InvalidLoop
+from pypy.jit.metainterp.resume import NUMBERING
from pypy.jit.codewriter import heaptracker
def giveup():
@@ -52,7 +54,6 @@ def compile_new_loop(metainterp, old_loop_tokens, greenkey, start):
"""
history = metainterp.history
loop = create_empty_loop(metainterp)
- loop.greenkey = greenkey
loop.inputargs = history.inputargs
for box in loop.inputargs:
assert isinstance(box, Box)
@@ -66,7 +67,6 @@ def compile_new_loop(metainterp, old_loop_tokens, greenkey, start):
loop.operations[-1].setdescr(loop_token) # patch the target of the JUMP
loop.preamble = create_empty_loop(metainterp, 'Preamble ')
- loop.preamble.greenkey = greenkey
loop.preamble.inputargs = loop.inputargs
loop.preamble.token = make_loop_token(len(loop.inputargs), jitdriver_sd)
@@ -214,8 +214,7 @@ def make_done_loop_tokens():
}
class ResumeDescr(AbstractFailDescr):
- def __init__(self, original_greenkey):
- self.original_greenkey = original_greenkey
+ pass
class ResumeGuardDescr(ResumeDescr):
_counter = 0 # if < 0, there is one counter per value;
@@ -224,7 +223,7 @@ class ResumeGuardDescr(ResumeDescr):
# this class also gets the following attributes stored by resume.py code
rd_snapshot = None
rd_frame_info_list = None
- rd_numb = None
+ rd_numb = lltype.nullptr(NUMBERING)
rd_consts = None
rd_virtuals = None
rd_pendingfields = None
@@ -234,8 +233,7 @@ class ResumeGuardDescr(ResumeDescr):
CNT_FLOAT = -0x60000000
CNT_MASK = 0x1FFFFFFF
- def __init__(self, metainterp_sd, original_greenkey):
- ResumeDescr.__init__(self, original_greenkey)
+ def __init__(self, metainterp_sd):
self.metainterp_sd = metainterp_sd
def store_final_boxes(self, guard_op, boxes):
@@ -339,14 +337,14 @@ class ResumeGuardDescr(ResumeDescr):
res.rd_pendingfields = self.rd_pendingfields
def _clone_if_mutable(self):
- res = ResumeGuardDescr(self.metainterp_sd, self.original_greenkey)
+ res = ResumeGuardDescr(self.metainterp_sd)
self.copy_all_attrbutes_into(res)
return res
class ResumeGuardForcedDescr(ResumeGuardDescr):
- def __init__(self, metainterp_sd, original_greenkey, jitdriver_sd):
- ResumeGuardDescr.__init__(self, metainterp_sd, original_greenkey)
+ def __init__(self, metainterp_sd, jitdriver_sd):
+ ResumeGuardDescr.__init__(self, metainterp_sd)
self.jitdriver_sd = jitdriver_sd
def handle_fail(self, metainterp_sd, jitdriver_sd):
@@ -413,7 +411,6 @@ class ResumeGuardForcedDescr(ResumeGuardDescr):
def _clone_if_mutable(self):
res = ResumeGuardForcedDescr(self.metainterp_sd,
- self.original_greenkey,
self.jitdriver_sd)
self.copy_all_attrbutes_into(res)
return res
@@ -480,9 +477,8 @@ class ResumeGuardCountersFloat(AbstractResumeGuardCounters):
class ResumeFromInterpDescr(ResumeDescr):
- def __init__(self, original_greenkey, redkey):
- ResumeDescr.__init__(self, original_greenkey)
- self.redkey = redkey
+ def __init__(self, original_greenkey):
+ self.original_greenkey = original_greenkey
def compile_and_attach(self, metainterp, new_loop):
# We managed to create a bridge going from the interpreter
@@ -491,10 +487,8 @@ class ResumeFromInterpDescr(ResumeDescr):
# with completely unoptimized arguments, as in the interpreter.
metainterp_sd = metainterp.staticdata
jitdriver_sd = metainterp.jitdriver_sd
- metainterp.history.inputargs = self.redkey
- new_loop_token = make_loop_token(len(self.redkey), jitdriver_sd)
- new_loop.greenkey = self.original_greenkey
- new_loop.inputargs = self.redkey
+ redargs = new_loop.inputargs
+ 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 the new_loop to warmspot.py, to be called directly the next time
diff --git a/pypy/jit/metainterp/logger.py b/pypy/jit/metainterp/logger.py
index 189462f3b5..898e1b4ff8 100644
--- a/pypy/jit/metainterp/logger.py
+++ b/pypy/jit/metainterp/logger.py
@@ -81,7 +81,8 @@ class Logger(object):
op = operations[i]
if op.getopnum() == rop.DEBUG_MERGE_POINT:
loc = op.getarg(0)._get_str()
- debug_print("debug_merge_point('%s')" % (loc,))
+ reclev = op.getarg(1).getint()
+ debug_print("debug_merge_point('%s', %s)" % (loc, reclev))
continue
args = ", ".join([self.repr_of_arg(memo, op.getarg(i)) for i in range(op.numargs())])
if op.result is not None:
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
index 2bf3551380..cbceaf4b42 100644
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -86,10 +86,10 @@ class OptValue(object):
assert isinstance(constbox, Const)
self.box = constbox
self.level = LEVEL_CONSTANT
- try:
- val = self.box.getint()
+ if isinstance(constbox, ConstInt):
+ val = constbox.getint()
self.intbound = IntBound(val, val)
- except NotImplementedError:
+ else:
self.intbound = IntUnbounded()
def get_constant_class(self, cpu):
diff --git a/pypy/jit/metainterp/optimizeopt/string.py b/pypy/jit/metainterp/optimizeopt/string.py
index 949d0b63b9..6680885490 100644
--- a/pypy/jit/metainterp/optimizeopt/string.py
+++ b/pypy/jit/metainterp/optimizeopt/string.py
@@ -9,7 +9,7 @@ from pypy.jit.metainterp.optimizeopt import optimizer, virtualize
from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1
from pypy.jit.metainterp.optimizeopt.optimizer import llhelper
from pypy.jit.metainterp.optimizeutil import _findall
-from pypy.jit.codewriter.effectinfo import EffectInfo, callinfo_for_oopspec
+from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.codewriter import heaptracker
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.objectmodel import specialize, we_are_translated
@@ -642,7 +642,8 @@ class OptString(optimizer.Optimization):
def generate_modified_call(self, oopspecindex, args, result, mode):
oopspecindex += mode.OS_offset
- calldescr, func = callinfo_for_oopspec(oopspecindex)
+ cic = self.optimizer.metainterp_sd.callinfocollection
+ calldescr, func = cic.callinfo_for_oopspec(oopspecindex)
op = ResOperation(rop.CALL, [ConstInt(func)] + args, result,
descr=calldescr)
self.optimizer.newoperations.append(op)
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
index 35b8fc0360..abb8fc84d3 100644
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -14,7 +14,7 @@ from pypy.jit.metainterp import executor
from pypy.jit.metainterp.logger import Logger
from pypy.jit.metainterp.jitprof import EmptyProfiler
from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE
-from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE
+from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG
from pypy.jit.metainterp.jitexc import JitException, get_llexception
from pypy.rlib.rarithmetic import intmask
from pypy.rlib.objectmodel import specialize
@@ -820,7 +820,8 @@ class MIFrame(object):
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, greenboxes)
+ self.debug_merge_point(jitdriver_sd, self.metainterp.in_recursion,
+ greenboxes)
if self.metainterp.seen_loop_header_for_jdindex < 0:
if not jitdriver_sd.no_loop_header or not any_operation:
return
@@ -860,13 +861,13 @@ class MIFrame(object):
assembler_call=True)
raise ChangeFrame
- def debug_merge_point(self, jitdriver_sd, greenkey):
+ def debug_merge_point(self, jitdriver_sd, in_recursion, greenkey):
# debugging: produce a DEBUG_MERGE_POINT operation
loc = jitdriver_sd.warmstate.get_location_str(greenkey)
debug_print(loc)
constloc = self.metainterp.cpu.ts.conststr(loc)
self.metainterp.history.record(rop.DEBUG_MERGE_POINT,
- [constloc], None)
+ [constloc, ConstInt(in_recursion)], None)
@arguments("box", "label")
def opimpl_goto_if_exception_mismatch(self, vtablebox, next_exc_target):
@@ -948,6 +949,11 @@ class MIFrame(object):
opimpl_ref_assert_green = _opimpl_assert_green
opimpl_float_assert_green = _opimpl_assert_green
+ @arguments()
+ def opimpl_current_trace_length(self):
+ trace_length = len(self.metainterp.history.operations)
+ return ConstInt(trace_length)
+
@arguments("box")
def opimpl_virtual_ref(self, box):
# Details on the content of metainterp.virtualref_boxes:
@@ -1042,14 +1048,11 @@ class MIFrame(object):
else:
moreargs = list(extraargs)
metainterp_sd = metainterp.staticdata
- original_greenkey = metainterp.resumekey.original_greenkey
if opnum == rop.GUARD_NOT_FORCED:
resumedescr = compile.ResumeGuardForcedDescr(metainterp_sd,
- original_greenkey,
metainterp.jitdriver_sd)
else:
- resumedescr = compile.ResumeGuardDescr(metainterp_sd,
- original_greenkey)
+ resumedescr = compile.ResumeGuardDescr(metainterp_sd)
guard_op = metainterp.history.record(opnum, moreargs, None,
descr=resumedescr)
virtualizable_boxes = None
@@ -1255,6 +1258,7 @@ class MetaInterpStaticData(object):
#
self.jitdrivers_sd = codewriter.callcontrol.jitdrivers_sd
self.virtualref_info = codewriter.callcontrol.virtualref_info
+ self.callinfocollection = codewriter.callcontrol.callinfocollection
self.setup_jitdrivers_sd(optimizer)
#
# store this information for fastpath of call_assembler
@@ -1618,7 +1622,7 @@ class MetaInterp(object):
assert jitdriver_sd is self.jitdriver_sd
self.create_empty_history()
try:
- original_boxes = self.initialize_original_boxes(jitdriver_sd,*args)
+ original_boxes = self.initialize_original_boxes(jitdriver_sd, *args)
return self._compile_and_run_once(original_boxes)
finally:
self.staticdata.profiler.end_tracing()
@@ -1629,9 +1633,8 @@ class MetaInterp(object):
self.current_merge_points = [(original_boxes, 0)]
num_green_args = self.jitdriver_sd.num_green_args
original_greenkey = original_boxes[:num_green_args]
- redkey = original_boxes[num_green_args:]
- self.resumekey = compile.ResumeFromInterpDescr(original_greenkey,
- redkey)
+ self.resumekey = compile.ResumeFromInterpDescr(original_greenkey)
+ self.history.inputargs = original_boxes[num_green_args:]
self.seen_loop_header_for_jdindex = -1
try:
self.interpret()
@@ -1653,11 +1656,7 @@ class MetaInterp(object):
debug_stop('jit-tracing')
def _handle_guard_failure(self, key):
- original_greenkey = key.original_greenkey
- # notice that here we just put the greenkey
- # use -1 to mark that we will have to give up
- # because we cannot reconstruct the beginning of the proper loop
- self.current_merge_points = [(original_greenkey, -1)]
+ self.current_merge_points = []
self.resumekey = key
self.seen_loop_header_for_jdindex = -1
try:
@@ -1721,7 +1720,7 @@ class MetaInterp(object):
num_green_args = self.jitdriver_sd.num_green_args
for j in range(len(self.current_merge_points)-1, -1, -1):
original_boxes, start = self.current_merge_points[j]
- assert len(original_boxes) == len(live_arg_boxes) or start < 0
+ assert len(original_boxes) == len(live_arg_boxes)
for i in range(num_green_args):
box1 = original_boxes[i]
box2 = live_arg_boxes[i]
@@ -1730,10 +1729,6 @@ class MetaInterp(object):
break
else:
# Found! Compile it as a loop.
- if start < 0:
- # we cannot reconstruct the beginning of the proper loop
- raise SwitchToBlackhole(ABORT_BRIDGE)
-
# raises in case it works -- which is the common case
self.compile(original_boxes, live_arg_boxes, start)
# creation of the loop was cancelled!
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
index eea9079a9a..08e2e7126c 100644
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -143,6 +143,16 @@ class AbstractResOp(object):
def can_raise(self):
return rop._CANRAISE_FIRST <= self.getopnum() <= rop._CANRAISE_LAST
+ def is_malloc(self):
+ # a slightly different meaning from can_malloc
+ return rop._MALLOC_FIRST <= self.getopnum() <= rop._MALLOC_LAST
+
+ def can_malloc(self):
+ return self.is_call() or self.is_malloc()
+
+ def is_call(self):
+ return rop._CALL_FIRST <= self.getopnum() <= rop._CALL_LAST
+
def is_ovf(self):
return rop._OVF_FIRST <= self.getopnum() <= rop._OVF_LAST
@@ -441,9 +451,13 @@ _oplist = [
'GETARRAYITEM_RAW/2d',
'GETFIELD_GC/1d',
'GETFIELD_RAW/1d',
+ '_MALLOC_FIRST',
'NEW/0d',
'NEW_WITH_VTABLE/1',
'NEW_ARRAY/1d',
+ 'NEWSTR/1',
+ 'NEWUNICODE/1',
+ '_MALLOC_LAST',
'FORCE_TOKEN/0',
'VIRTUAL_REF/2', # removed before it's passed to the backend
'_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations -----
@@ -452,19 +466,18 @@ _oplist = [
'SETARRAYITEM_RAW/3d',
'SETFIELD_GC/2d',
'SETFIELD_RAW/2d',
- 'NEWSTR/1',
'STRSETITEM/3',
'UNICODESETITEM/3',
- 'NEWUNICODE/1',
#'RUNTIMENEW/1', # ootype operation
'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier)
- 'DEBUG_MERGE_POINT/1', # debugging only
+ 'DEBUG_MERGE_POINT/2', # debugging only
'JIT_DEBUG/*', # debugging only
'VIRTUAL_REF_FINISH/2', # removed before it's passed to the backend
'COPYSTRCONTENT/5', # src, dst, srcstart, dststart, length
'COPYUNICODECONTENT/5',
'_CANRAISE_FIRST', # ----- start of can_raise operations -----
+ '_CALL_FIRST',
'CALL/*d',
'CALL_ASSEMBLER/*d', # call already compiled assembler
'CALL_MAY_FORCE/*d',
@@ -473,6 +486,7 @@ _oplist = [
#'OOSEND_PURE', # ootype operation
'CALL_PURE/*d', # removed before it's passed to the backend
# CALL_PURE(result, func, arg_1,..,arg_n)
+ '_CALL_LAST',
'_CANRAISE_LAST', # ----- end of can_raise operations -----
'_OVF_FIRST', # ----- start of is_ovf operations -----
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
index 338bba1065..89a5d28354 100644
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -4,8 +4,7 @@ from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat
from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp import jitprof
-from pypy.jit.codewriter.effectinfo import EffectInfo, callinfo_for_oopspec
-from pypy.jit.codewriter.effectinfo import funcptr_for_oopspec
+from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr
from pypy.rlib import rarithmetic
from pypy.rlib.objectmodel import we_are_translated, specialize
@@ -66,12 +65,21 @@ def capture_resumedata(framestack, virtualizable_boxes, virtualref_boxes,
snapshot = Snapshot(snapshot, boxes)
storage.rd_snapshot = snapshot
-class Numbering(object):
- __slots__ = ('prev', 'nums')
-
- def __init__(self, prev, nums):
- self.prev = prev
- self.nums = nums
+#
+# The following is equivalent to the RPython-level declaration:
+#
+# class Numbering: __slots__ = ['prev', 'nums']
+#
+# except that it is more compact in translated programs, because the
+# array 'nums' is inlined in the single NUMBERING object. This is
+# important because this is often the biggest single consumer of memory
+# in a pypy-c-jit.
+#
+NUMBERINGP = lltype.Ptr(lltype.GcForwardReference())
+NUMBERING = lltype.GcStruct('Numbering',
+ ('prev', NUMBERINGP),
+ ('nums', lltype.Array(rffi.SHORT)))
+NUMBERINGP.TO.become(NUMBERING)
TAGMASK = 3
@@ -163,7 +171,7 @@ class ResumeDataLoopMemo(object):
def number(self, values, snapshot):
if snapshot is None:
- return None, {}, 0
+ return lltype.nullptr(NUMBERING), {}, 0
if snapshot in self.numberings:
numb, liveboxes, v = self.numberings[snapshot]
return numb, liveboxes.copy(), v
@@ -172,7 +180,7 @@ class ResumeDataLoopMemo(object):
n = len(liveboxes)-v
boxes = snapshot.boxes
length = len(boxes)
- nums = [UNASSIGNED] * length
+ numb = lltype.malloc(NUMBERING, length)
for i in range(length):
box = boxes[i]
value = values.get(box, None)
@@ -191,9 +199,9 @@ class ResumeDataLoopMemo(object):
tagged = tag(n, TAGBOX)
n += 1
liveboxes[box] = tagged
- nums[i] = tagged
+ numb.nums[i] = tagged
#
- numb = Numbering(numb1, nums)
+ numb.prev = numb1
self.numberings[snapshot] = numb, liveboxes, v
return numb, liveboxes.copy(), v
@@ -298,7 +306,7 @@ class ResumeDataVirtualAdder(object):
# compute the numbering
storage = self.storage
# make sure that nobody attached resume data to this guard yet
- assert storage.rd_numb is None
+ assert not storage.rd_numb
snapshot = storage.rd_snapshot
assert snapshot is not None # is that true?
numb, liveboxes_from_env, v = self.memo.number(values, snapshot)
@@ -724,34 +732,36 @@ class ResumeDataBoxReader(AbstractResumeDataReader):
self.boxes_f = boxes_f
self._prepare_next_section(info)
- def consume_virtualizable_boxes(self, vinfo, nums):
+ def consume_virtualizable_boxes(self, vinfo, numb):
# we have to ignore the initial part of 'nums' (containing vrefs),
# find the virtualizable from nums[-1], and use it to know how many
# boxes of which type we have to return. This does not write
# anything into the virtualizable.
- virtualizablebox = self.decode_ref(nums[-1])
+ index = len(numb.nums) - 1
+ virtualizablebox = self.decode_ref(numb.nums[index])
virtualizable = vinfo.unwrap_virtualizable_box(virtualizablebox)
- return vinfo.load_list_of_boxes(virtualizable, self, nums)
+ return vinfo.load_list_of_boxes(virtualizable, self, numb)
- def consume_virtualref_boxes(self, nums, end):
+ def consume_virtualref_boxes(self, numb, end):
# Returns a list of boxes, assumed to be all BoxPtrs.
# We leave up to the caller to call vrefinfo.continue_tracing().
assert (end & 1) == 0
- return [self.decode_ref(nums[i]) for i in range(end)]
+ return [self.decode_ref(numb.nums[i]) for i in range(end)]
def consume_vref_and_vable_boxes(self, vinfo, ginfo):
- nums = self.cur_numb.nums
- self.cur_numb = self.cur_numb.prev
+ numb = self.cur_numb
+ self.cur_numb = numb.prev
if vinfo is not None:
- virtualizable_boxes = self.consume_virtualizable_boxes(vinfo, nums)
- end = len(nums) - len(virtualizable_boxes)
+ virtualizable_boxes = self.consume_virtualizable_boxes(vinfo, numb)
+ end = len(numb.nums) - len(virtualizable_boxes)
elif ginfo is not None:
- virtualizable_boxes = [self.decode_ref(nums[-1])]
- end = len(nums) - 1
+ index = len(numb.nums) - 1
+ virtualizable_boxes = [self.decode_ref(numb.nums[index])]
+ end = len(numb.nums) - 1
else:
virtualizable_boxes = None
- end = len(nums)
- virtualref_boxes = self.consume_virtualref_boxes(nums, end)
+ end = len(numb.nums)
+ virtualref_boxes = self.consume_virtualref_boxes(numb, end)
return virtualizable_boxes, virtualref_boxes
def allocate_with_vtable(self, known_class):
@@ -775,14 +785,16 @@ class ResumeDataBoxReader(AbstractResumeDataReader):
strbox, ConstInt(index), charbox)
def concat_strings(self, str1num, str2num):
- calldescr, func = callinfo_for_oopspec(EffectInfo.OS_STR_CONCAT)
+ cic = self.metainterp.staticdata.callinfocollection
+ calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_STR_CONCAT)
str1box = self.decode_box(str1num, REF)
str2box = self.decode_box(str2num, REF)
return self.metainterp.execute_and_record_varargs(
rop.CALL, [ConstInt(func), str1box, str2box], calldescr)
def slice_string(self, strnum, startnum, lengthnum):
- calldescr, func = callinfo_for_oopspec(EffectInfo.OS_STR_SLICE)
+ cic = self.metainterp.staticdata.callinfocollection
+ calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_STR_SLICE)
strbox = self.decode_box(strnum, REF)
startbox = self.decode_box(startnum, INT)
lengthbox = self.decode_box(lengthnum, INT)
@@ -801,14 +813,16 @@ class ResumeDataBoxReader(AbstractResumeDataReader):
strbox, ConstInt(index), charbox)
def concat_unicodes(self, str1num, str2num):
- calldescr, func = callinfo_for_oopspec(EffectInfo.OS_UNI_CONCAT)
+ cic = self.metainterp.staticdata.callinfocollection
+ calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_UNI_CONCAT)
str1box = self.decode_box(str1num, REF)
str2box = self.decode_box(str2num, REF)
return self.metainterp.execute_and_record_varargs(
rop.CALL, [ConstInt(func), str1box, str2box], calldescr)
def slice_unicode(self, strnum, startnum, lengthnum):
- calldescr, func = callinfo_for_oopspec(EffectInfo.OS_UNI_SLICE)
+ cic = self.metainterp.staticdata.callinfocollection
+ calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_UNI_SLICE)
strbox = self.decode_box(strnum, REF)
startbox = self.decode_box(startnum, INT)
lengthbox = self.decode_box(lengthnum, INT)
@@ -904,8 +918,8 @@ class ResumeDataBoxReader(AbstractResumeDataReader):
def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage,
all_virtuals=None):
- resumereader = ResumeDataDirectReader(blackholeinterpbuilder.cpu, storage,
- all_virtuals)
+ resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd,
+ storage, all_virtuals)
vinfo = jitdriver_sd.virtualizable_info
ginfo = jitdriver_sd.greenfield_info
vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info
@@ -940,7 +954,7 @@ def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage,
return firstbh
def force_from_resumedata(metainterp_sd, storage, vinfo, ginfo):
- resumereader = ResumeDataDirectReader(metainterp_sd.cpu, storage)
+ resumereader = ResumeDataDirectReader(metainterp_sd, storage)
resumereader.handling_async_forcing()
vrefinfo = metainterp_sd.virtualref_info
resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
@@ -954,8 +968,9 @@ class ResumeDataDirectReader(AbstractResumeDataReader):
# 1: in handle_async_forcing
# 2: resuming from the GUARD_NOT_FORCED
- def __init__(self, cpu, storage, all_virtuals=None):
- self._init(cpu, storage)
+ def __init__(self, metainterp_sd, storage, all_virtuals=None):
+ self._init(metainterp_sd.cpu, storage)
+ self.callinfocollection = metainterp_sd.callinfocollection
if all_virtuals is None: # common case
self._prepare(storage)
else:
@@ -974,23 +989,24 @@ class ResumeDataDirectReader(AbstractResumeDataReader):
info = blackholeinterp.get_current_position_info()
self._prepare_next_section(info)
- def consume_virtualref_info(self, vrefinfo, nums, end):
+ def consume_virtualref_info(self, vrefinfo, numb, end):
# we have to decode a list of references containing pairs
# [..., virtual, vref, ...] stopping at 'end'
assert (end & 1) == 0
for i in range(0, end, 2):
- virtual = self.decode_ref(nums[i])
- vref = self.decode_ref(nums[i+1])
+ virtual = self.decode_ref(numb.nums[i])
+ vref = self.decode_ref(numb.nums[i+1])
# For each pair, we store the virtual inside the vref.
vrefinfo.continue_tracing(vref, virtual)
- def consume_vable_info(self, vinfo, nums):
+ def consume_vable_info(self, vinfo, numb):
# we have to ignore the initial part of 'nums' (containing vrefs),
# find the virtualizable from nums[-1], load all other values
# from the CPU stack, and copy them into the virtualizable
if vinfo is None:
- return len(nums)
- virtualizable = self.decode_ref(nums[-1])
+ return len(numb.nums)
+ index = len(numb.nums) - 1
+ virtualizable = self.decode_ref(numb.nums[index])
virtualizable = vinfo.cast_gcref_to_vtype(virtualizable)
if self.resume_after_guard_not_forced == 1:
# in the middle of handle_async_forcing()
@@ -1002,7 +1018,7 @@ class ResumeDataDirectReader(AbstractResumeDataReader):
# is and stays 0. Note the call to reset_vable_token() in
# warmstate.py.
assert not virtualizable.vable_token
- return vinfo.write_from_resume_data_partial(virtualizable, self, nums)
+ return vinfo.write_from_resume_data_partial(virtualizable, self, numb)
def load_value_of_type(self, TYPE, tagged):
from pypy.jit.metainterp.warmstate import specialize_value
@@ -1019,12 +1035,12 @@ class ResumeDataDirectReader(AbstractResumeDataReader):
load_value_of_type._annspecialcase_ = 'specialize:arg(1)'
def consume_vref_and_vable(self, vrefinfo, vinfo, ginfo):
- nums = self.cur_numb.nums
- self.cur_numb = self.cur_numb.prev
+ numb = self.cur_numb
+ self.cur_numb = numb.prev
if self.resume_after_guard_not_forced != 2:
- end_vref = self.consume_vable_info(vinfo, nums)
+ end_vref = self.consume_vable_info(vinfo, numb)
if ginfo is not None: end_vref -= 1
- self.consume_virtualref_info(vrefinfo, nums, end_vref)
+ self.consume_virtualref_info(vrefinfo, numb, end_vref)
def allocate_with_vtable(self, known_class):
from pypy.jit.metainterp.executor import exec_new_with_vtable
@@ -1048,7 +1064,8 @@ class ResumeDataDirectReader(AbstractResumeDataReader):
str2 = self.decode_ref(str2num)
str1 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str1)
str2 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str2)
- funcptr = funcptr_for_oopspec(EffectInfo.OS_STR_CONCAT)
+ cic = self.callinfocollection
+ funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_STR_CONCAT)
result = funcptr(str1, str2)
return lltype.cast_opaque_ptr(llmemory.GCREF, result)
@@ -1057,7 +1074,8 @@ class ResumeDataDirectReader(AbstractResumeDataReader):
start = self.decode_int(startnum)
length = self.decode_int(lengthnum)
str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str)
- funcptr = funcptr_for_oopspec(EffectInfo.OS_STR_SLICE)
+ cic = self.callinfocollection
+ funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_STR_SLICE)
result = funcptr(str, start, start + length)
return lltype.cast_opaque_ptr(llmemory.GCREF, result)
@@ -1073,7 +1091,8 @@ class ResumeDataDirectReader(AbstractResumeDataReader):
str2 = self.decode_ref(str2num)
str1 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str1)
str2 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str2)
- funcptr = funcptr_for_oopspec(EffectInfo.OS_UNI_CONCAT)
+ cic = self.callinfocollection
+ funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_UNI_CONCAT)
result = funcptr(str1, str2)
return lltype.cast_opaque_ptr(llmemory.GCREF, result)
@@ -1082,7 +1101,8 @@ class ResumeDataDirectReader(AbstractResumeDataReader):
start = self.decode_int(startnum)
length = self.decode_int(lengthnum)
str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str)
- funcptr = funcptr_for_oopspec(EffectInfo.OS_UNI_SLICE)
+ cic = self.callinfocollection
+ funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_UNI_SLICE)
result = funcptr(str, start, start + length)
return lltype.cast_opaque_ptr(llmemory.GCREF, result)
@@ -1173,8 +1193,9 @@ def dump_storage(storage, liveboxes):
'at', compute_unique_id(frameinfo))
frameinfo = frameinfo.prev
numb = storage.rd_numb
- while numb is not None:
- debug_print('\tnumb', str([untag(i) for i in numb.nums]),
+ while numb:
+ debug_print('\tnumb', str([untag(numb.nums[i])
+ for i in range(len(numb.nums))]),
'at', compute_unique_id(numb))
numb = numb.prev
for const in storage.rd_consts:
diff --git a/pypy/jit/metainterp/test/test_basic.py b/pypy/jit/metainterp/test/test_basic.py
index 6b994f5d75..a96440a7bf 100644
--- a/pypy/jit/metainterp/test/test_basic.py
+++ b/pypy/jit/metainterp/test/test_basic.py
@@ -3,6 +3,7 @@ import sys
from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside
from pypy.rlib.jit import OPTIMIZER_FULL, OPTIMIZER_SIMPLE, loop_invariant
from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed
+from pypy.rlib.jit import unroll_safe, current_trace_length
from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
from pypy.jit.backend.llgraph import runner
from pypy.jit.metainterp import pyjitpl, history
@@ -1837,6 +1838,31 @@ class BasicTests:
'int_add': 1, 'int_mul': 1, 'int_sub': 2,
'int_gt': 2, 'jump': 2})
+ def test_current_trace_length(self):
+ myjitdriver = JitDriver(greens = ['g'], reds = ['x'])
+ @dont_look_inside
+ def residual():
+ print "hi there"
+ @unroll_safe
+ def loop(g):
+ y = 0
+ while y < g:
+ residual()
+ y += 1
+ def f(x, g):
+ n = 0
+ while x > 0:
+ myjitdriver.can_enter_jit(x=x, g=g)
+ myjitdriver.jit_merge_point(x=x, g=g)
+ loop(g)
+ x -= 1
+ n = current_trace_length()
+ return n
+ res = self.meta_interp(f, [5, 8])
+ assert 14 < res < 42
+ res = self.meta_interp(f, [5, 2])
+ assert 4 < res < 14
+
class TestOOtype(BasicTests, OOJitMixin):
diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py
index 98edd3f7e8..cddc61080a 100644
--- a/pypy/jit/metainterp/test/test_compile.py
+++ b/pypy/jit/metainterp/test/test_compile.py
@@ -85,7 +85,7 @@ def test_compile_new_loop():
metainterp.history.inputargs = loop.inputargs[:]
#
loop_tokens = []
- loop_token = compile_new_loop(metainterp, loop_tokens, [], 0)
+ loop_token = compile_new_loop(metainterp, loop_tokens, 0)
assert loop_tokens == [loop_token]
assert loop_token.number == 1
assert staticdata.globaldata.loopnumbering == 2
@@ -101,7 +101,7 @@ def test_compile_new_loop():
metainterp.history.operations = loop.operations[:]
metainterp.history.inputargs = loop.inputargs[:]
#
- loop_token_2 = compile_new_loop(metainterp, loop_tokens, [], 0)
+ loop_token_2 = compile_new_loop(metainterp, loop_tokens, 0)
assert loop_token_2 is loop_token
assert loop_tokens == [loop_token]
assert len(cpu.seen) == 0
diff --git a/pypy/jit/metainterp/test/test_del.py b/pypy/jit/metainterp/test/test_del.py
index 8ce32f6535..5ea0dc817f 100644
--- a/pypy/jit/metainterp/test/test_del.py
+++ b/pypy/jit/metainterp/test/test_del.py
@@ -85,6 +85,7 @@ class TestLLtype(DelTests, LLJitMixin):
def test_signal_action(self):
from pypy.module.signal.interp_signal import SignalActionFlag
action = SignalActionFlag()
+ action.has_bytecode_counter = True
#
myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
class X:
@@ -92,17 +93,17 @@ class TestLLtype(DelTests, LLJitMixin):
#
def f(n):
x = X()
- while n > 0:
+ action.reset_ticker(n)
+ while True:
myjitdriver.can_enter_jit(n=n, x=x)
myjitdriver.jit_merge_point(n=n, x=x)
x.foo = n
n -= 1
- if action.get() != 0:
+ if action.decrement_ticker(1) < 0:
break
- action.set(0)
return 42
self.meta_interp(f, [20])
- self.check_loops(getfield_raw=1, call=0, call_pure=0)
+ self.check_loops(getfield_raw=1, setfield_raw=1, call=0, call_pure=0)
class TestOOtype(DelTests, OOJitMixin):
def setup_class(cls):
diff --git a/pypy/jit/metainterp/test/test_logger.py b/pypy/jit/metainterp/test/test_logger.py
index 24618f6a09..8a2eeaa51e 100644
--- a/pypy/jit/metainterp/test/test_logger.py
+++ b/pypy/jit/metainterp/test/test_logger.py
@@ -97,7 +97,7 @@ class TestLogger(object):
def test_debug_merge_point(self):
inp = '''
[]
- debug_merge_point("info")
+ debug_merge_point("info", 0)
'''
loop, oloop = self.reparse(inp, check_equal=False)
assert loop.operations[0].getarg(0)._get_str() == 'info'
diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py
index baf8e65777..74393e540d 100644
--- a/pypy/jit/metainterp/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/test/test_optimizeopt.py
@@ -26,6 +26,100 @@ class FakeMetaInterpStaticData(object):
self.options = Fake()
self.globaldata = Fake()
+def test_store_final_boxes_in_guard():
+ from pypy.jit.metainterp.compile import ResumeGuardDescr
+ from pypy.jit.metainterp.resume import tag, TAGBOX
+ b0 = BoxInt()
+ b1 = BoxInt()
+ opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu),
+ None)
+ fdescr = ResumeGuardDescr(None)
+ op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr)
+ # setup rd data
+ fi0 = resume.FrameInfo(None, "code0", 11)
+ fdescr.rd_frame_info_list = resume.FrameInfo(fi0, "code1", 33)
+ snapshot0 = resume.Snapshot(None, [b0])
+ fdescr.rd_snapshot = resume.Snapshot(snapshot0, [b1])
+ #
+ opt.store_final_boxes_in_guard(op)
+ if op.getfailargs() == [b0, b1]:
+ assert list(fdescr.rd_numb.nums) == [tag(1, TAGBOX)]
+ assert list(fdescr.rd_numb.prev.nums) == [tag(0, TAGBOX)]
+ else:
+ assert op.getfailargs() == [b1, b0]
+ assert list(fdescr.rd_numb.nums) == [tag(0, TAGBOX)]
+ assert list(fdescr.rd_numb.prev.nums) == [tag(1, TAGBOX)]
+ assert fdescr.rd_virtuals is None
+ assert fdescr.rd_consts == []
+
+def test_sharing_field_lists_of_virtual():
+ class FakeOptimizer(object):
+ class cpu(object):
+ pass
+ opt = FakeOptimizer()
+ virt1 = virtualize.AbstractVirtualStructValue(opt, None)
+ lst1 = virt1._get_field_descr_list()
+ assert lst1 == []
+ lst2 = virt1._get_field_descr_list()
+ assert lst1 is lst2
+ virt1.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None))
+ lst3 = virt1._get_field_descr_list()
+ assert lst3 == [LLtypeMixin.valuedescr]
+ lst4 = virt1._get_field_descr_list()
+ assert lst3 is lst4
+
+ virt2 = virtualize.AbstractVirtualStructValue(opt, None)
+ lst5 = virt2._get_field_descr_list()
+ assert lst5 is lst1
+ virt2.setfield(LLtypeMixin.valuedescr, optimizeopt.OptValue(None))
+ lst6 = virt1._get_field_descr_list()
+ assert lst6 is lst3
+
+def test_reuse_vinfo():
+ class FakeVInfo(object):
+ def set_content(self, fieldnums):
+ self.fieldnums = fieldnums
+ def equals(self, fieldnums):
+ return self.fieldnums == fieldnums
+ class FakeVirtualValue(virtualize.AbstractVirtualValue):
+ def _make_virtual(self, *args):
+ return FakeVInfo()
+ v1 = FakeVirtualValue(None, None, None)
+ vinfo1 = v1.make_virtual_info(None, [1, 2, 4])
+ vinfo2 = v1.make_virtual_info(None, [1, 2, 4])
+ assert vinfo1 is vinfo2
+ vinfo3 = v1.make_virtual_info(None, [1, 2, 6])
+ assert vinfo3 is not vinfo2
+ vinfo4 = v1.make_virtual_info(None, [1, 2, 6])
+ assert vinfo3 is vinfo4
+
+def test_descrlist_dict():
+ from pypy.jit.metainterp import optimizeutil
+ h1 = optimizeutil.descrlist_hash([])
+ h2 = optimizeutil.descrlist_hash([LLtypeMixin.valuedescr])
+ h3 = optimizeutil.descrlist_hash(
+ [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr])
+ assert h1 != h2
+ assert h2 != h3
+ assert optimizeutil.descrlist_eq([], [])
+ assert not optimizeutil.descrlist_eq([], [LLtypeMixin.valuedescr])
+ assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr],
+ [LLtypeMixin.valuedescr])
+ assert not optimizeutil.descrlist_eq([LLtypeMixin.valuedescr],
+ [LLtypeMixin.nextdescr])
+ assert optimizeutil.descrlist_eq([LLtypeMixin.valuedescr, LLtypeMixin.nextdescr],
+ [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr])
+ assert not optimizeutil.descrlist_eq([LLtypeMixin.nextdescr, LLtypeMixin.valuedescr],
+ [LLtypeMixin.valuedescr, LLtypeMixin.nextdescr])
+
+ # descrlist_eq should compare by identity of the descrs, not by the result
+ # of sort_key
+ class FakeDescr(object):
+ def sort_key(self):
+ return 1
+
+ assert not optimizeutil.descrlist_eq([FakeDescr()], [FakeDescr()])
+
# ____________________________________________________________
class Storage(compile.ResumeGuardDescr):
"for tests."
@@ -76,6 +170,8 @@ class BaseTestOptimizeOpt(BaseTest):
metainterp_sd = FakeMetaInterpStaticData(self.cpu)
if hasattr(self, 'vrefinfo'):
metainterp_sd.virtualref_info = self.vrefinfo
+ if hasattr(self, 'callinfocollection'):
+ metainterp_sd.callinfocollection = self.callinfocollection
optimize_loop_1(metainterp_sd, loop)
#
@@ -1430,7 +1526,7 @@ class OptimizeOptTest(BaseTestOptimizeOpt):
ops = """
[p1]
i1 = getfield_gc(p1, descr=valuedescr)
- debug_merge_point(15)
+ debug_merge_point(15, 0)
i2 = getfield_gc(p1, descr=valuedescr)
escape(i1)
escape(i2)
@@ -1439,7 +1535,7 @@ class OptimizeOptTest(BaseTestOptimizeOpt):
expected = """
[p1]
i1 = getfield_gc(p1, descr=valuedescr)
- debug_merge_point(15)
+ debug_merge_point(15, 0)
escape(i1)
escape(i1)
jump(p1)
@@ -4288,22 +4384,20 @@ class TestLLtype(OptimizeOptTest, LLtypeMixin):
# ----------
def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble=None):
from pypy.jit.metainterp.optimizeopt import string
- def my_callinfo_for_oopspec(oopspecindex):
- calldescrtype = type(LLtypeMixin.strequaldescr)
- for value in LLtypeMixin.__dict__.values():
- if isinstance(value, calldescrtype):
- if (value.get_extra_info() and
- value.get_extra_info().oopspecindex == oopspecindex):
- # returns 0 for 'func' in this test
- return value, 0
- raise AssertionError("not found: oopspecindex=%d" % oopspecindex)
+ class FakeCallInfoCollection:
+ def callinfo_for_oopspec(self, oopspecindex):
+ calldescrtype = type(LLtypeMixin.strequaldescr)
+ for value in LLtypeMixin.__dict__.values():
+ if isinstance(value, calldescrtype):
+ extra = value.get_extra_info()
+ if extra and extra.oopspecindex == oopspecindex:
+ # returns 0 for 'func' in this test
+ return value, 0
+ raise AssertionError("not found: oopspecindex=%d" %
+ oopspecindex)
#
- saved = string.callinfo_for_oopspec
- try:
- string.callinfo_for_oopspec = my_callinfo_for_oopspec
- self.optimize_strunicode_loop(ops, optops, preamble)
- finally:
- string.callinfo_for_oopspec = saved
+ self.callinfocollection = FakeCallInfoCollection()
+ self.optimize_strunicode_loop(ops, optops, preamble)
def test_str_equal_noop1(self):
ops = """
diff --git a/pypy/jit/metainterp/test/test_resoperation.py b/pypy/jit/metainterp/test/test_resoperation.py
index b8cebb8b7a..b64390a784 100644
--- a/pypy/jit/metainterp/test/test_resoperation.py
+++ b/pypy/jit/metainterp/test/test_resoperation.py
@@ -61,3 +61,10 @@ def test_instantiate():
assert op.getarglist() == ['a', 'b']
assert op.result == 'c'
assert op.getdescr() is mydescr
+
+def test_can_malloc():
+ mydescr = AbstractDescr()
+ assert rop.ResOperation(rop.rop.NEW, [], 'b').can_malloc()
+ call = rop.ResOperation(rop.rop.CALL, ['a', 'b'], 'c', descr=mydescr)
+ assert call.can_malloc()
+ assert not rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c').can_malloc()
diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py
index 3e0a8a8fcb..bd891d9ea6 100644
--- a/pypy/jit/metainterp/test/test_resume.py
+++ b/pypy/jit/metainterp/test/test_resume.py
@@ -52,6 +52,7 @@ def test_vinfo():
class MyMetaInterp:
_already_allocated_resume_virtuals = None
+ callinfocollection = None
def __init__(self, cpu=None):
if cpu is None:
@@ -142,6 +143,13 @@ def _next_section(reader, *expected):
assert bh.written_f == expected_f
+def Numbering(prev, nums):
+ numb = lltype.malloc(NUMBERING, len(nums))
+ numb.prev = prev or lltype.nullptr(NUMBERING)
+ for i in range(len(nums)):
+ numb.nums[i] = nums[i]
+ return numb
+
def test_simple_read():
#b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()]
c1, c2, c3 = [ConstInt(111), ConstInt(222), ConstInt(333)]
@@ -157,12 +165,12 @@ def test_simple_read():
storage.rd_numb = numb
#
cpu = MyCPU([42, gcref1, -66])
- reader = ResumeDataDirectReader(cpu, storage)
+ metainterp = MyMetaInterp(cpu)
+ reader = ResumeDataDirectReader(metainterp, storage)
_next_section(reader, 42, 111, gcrefnull, 42, gcref1)
_next_section(reader, 222, 333)
_next_section(reader, 42, gcref1, -66)
#
- metainterp = MyMetaInterp(cpu)
reader = ResumeDataBoxReader(storage, metainterp)
bi, br, bf = [None]*3, [None]*2, [None]*0
info = MyBlackholeInterp([lltype.Signed, lltype.Signed,
@@ -194,7 +202,7 @@ def test_simple_read_tagged_ints():
storage.rd_numb = numb
#
cpu = MyCPU([])
- reader = ResumeDataDirectReader(cpu, storage)
+ reader = ResumeDataDirectReader(MyMetaInterp(cpu), storage)
_next_section(reader, 100)
@@ -212,7 +220,7 @@ def test_prepare_virtuals():
class FakeMetainterp(object):
_already_allocated_resume_virtuals = None
cpu = None
- reader = ResumeDataDirectReader(None, FakeStorage())
+ reader = ResumeDataDirectReader(MyMetaInterp(None), FakeStorage())
assert reader.force_all_virtuals() == ["allocated", reader.virtual_default]
# ____________________________________________________________
@@ -391,15 +399,15 @@ def test_FrameInfo_create():
assert fi1.pc == 3
def test_Numbering_create():
- l = [1, 2]
+ l = [rffi.r_short(1), rffi.r_short(2)]
numb = Numbering(None, l)
- assert numb.prev is None
- assert numb.nums is l
+ assert not numb.prev
+ assert list(numb.nums) == l
- l1 = ['b3']
+ l1 = [rffi.r_short(3)]
numb1 = Numbering(numb, l1)
- assert numb1.prev is numb
- assert numb1.nums is l1
+ assert numb1.prev == numb
+ assert list(numb1.nums) == l1
def test_capture_resumedata():
b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()]
@@ -765,11 +773,12 @@ def test_ResumeDataLoopMemo_number():
assert liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
b3: tag(2, TAGBOX)}
- assert numb.nums == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
- tag(1, TAGINT)]
- assert numb.prev.nums == [tag(0, TAGBOX), tag(1, TAGINT), tag(1, TAGBOX),
- tag(0, TAGBOX), tag(2, TAGINT)]
- assert numb.prev.prev is None
+ assert list(numb.nums) == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
+ tag(1, TAGINT)]
+ assert list(numb.prev.nums) == [tag(0, TAGBOX), tag(1, TAGINT),
+ tag(1, TAGBOX),
+ tag(0, TAGBOX), tag(2, TAGINT)]
+ assert not numb.prev.prev
numb2, liveboxes2, v = memo.number({}, snap2)
assert v == 0
@@ -777,9 +786,9 @@ def test_ResumeDataLoopMemo_number():
assert liveboxes2 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
b3: tag(2, TAGBOX)}
assert liveboxes2 is not liveboxes
- assert numb2.nums == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
- tag(3, TAGINT)]
- assert numb2.prev is numb.prev
+ assert list(numb2.nums) == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
+ tag(3, TAGINT)]
+ assert numb2.prev == numb.prev
env3 = [c3, b3, b1, c3]
snap3 = Snapshot(snap, env3)
@@ -800,9 +809,9 @@ def test_ResumeDataLoopMemo_number():
assert v == 0
assert liveboxes3 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX)}
- assert numb3.nums == [tag(3, TAGINT), tag(4, TAGINT), tag(0, TAGBOX),
- tag(3, TAGINT)]
- assert numb3.prev is numb.prev
+ assert list(numb3.nums) == [tag(3, TAGINT), tag(4, TAGINT), tag(0, TAGBOX),
+ tag(3, TAGINT)]
+ assert numb3.prev == numb.prev
# virtual
env4 = [c3, b4, b1, c3]
@@ -813,9 +822,9 @@ def test_ResumeDataLoopMemo_number():
assert liveboxes4 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
b4: tag(0, TAGVIRTUAL)}
- assert numb4.nums == [tag(3, TAGINT), tag(0, TAGVIRTUAL), tag(0, TAGBOX),
- tag(3, TAGINT)]
- assert numb4.prev is numb.prev
+ assert list(numb4.nums) == [tag(3, TAGINT), tag(0, TAGVIRTUAL),
+ tag(0, TAGBOX), tag(3, TAGINT)]
+ assert numb4.prev == numb.prev
env5 = [b1, b4, b5]
snap5 = Snapshot(snap4, env5)
@@ -826,9 +835,9 @@ def test_ResumeDataLoopMemo_number():
assert liveboxes5 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
b4: tag(0, TAGVIRTUAL), b5: tag(1, TAGVIRTUAL)}
- assert numb5.nums == [tag(0, TAGBOX), tag(0, TAGVIRTUAL),
- tag(1, TAGVIRTUAL)]
- assert numb5.prev is numb4
+ assert list(numb5.nums) == [tag(0, TAGBOX), tag(0, TAGVIRTUAL),
+ tag(1, TAGVIRTUAL)]
+ assert numb5.prev == numb4
def test_ResumeDataLoopMemo_number_boxes():
memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
@@ -926,7 +935,7 @@ def test_virtual_adder_int_constants():
liveboxes = modifier.finish({})
assert storage.rd_snapshot is None
cpu = MyCPU([])
- reader = ResumeDataDirectReader(cpu, storage)
+ reader = ResumeDataDirectReader(MyMetaInterp(cpu), storage)
_next_section(reader, sys.maxint, 2**16, -65)
_next_section(reader, 2, 3)
_next_section(reader, sys.maxint, 1, sys.maxint, 2**16)
diff --git a/pypy/jit/metainterp/test/test_virtualref.py b/pypy/jit/metainterp/test/test_virtualref.py
index 097f9f99c9..e0e738207f 100644
--- a/pypy/jit/metainterp/test/test_virtualref.py
+++ b/pypy/jit/metainterp/test/test_virtualref.py
@@ -88,7 +88,11 @@ class VRefTests:
cpu.get_latest_value_int = lambda i:guard_op.getfailargs()[i].getint()
cpu.get_latest_value_ref = lambda i:guard_op.getfailargs()[i].getref_base()
cpu.clear_latest_values = lambda count: None
- resumereader = ResumeDataDirectReader(cpu, guard_op.getdescr())
+ class FakeMetaInterpSd:
+ callinfocollection = None
+ FakeMetaInterpSd.cpu = cpu
+ resumereader = ResumeDataDirectReader(FakeMetaInterpSd(),
+ guard_op.getdescr())
vrefinfo = self.metainterp.staticdata.virtualref_info
lst = []
vrefinfo.continue_tracing = lambda vref, virtual: \
diff --git a/pypy/jit/metainterp/test/test_ztranslation.py b/pypy/jit/metainterp/test/test_ztranslation.py
index 3987544b19..026e4d5dee 100644
--- a/pypy/jit/metainterp/test/test_ztranslation.py
+++ b/pypy/jit/metainterp/test/test_ztranslation.py
@@ -79,7 +79,7 @@ class TranslationTest:
res = ll_meta_interp(main, [40, 5], CPUClass=self.CPUClass,
type_system=self.type_system)
assert res == main(40, 5)
- res = rpython_ll_meta_interp(main, [40, 5], loops=2,
+ res = rpython_ll_meta_interp(main, [40, 5],
CPUClass=self.CPUClass,
type_system=self.type_system,
optimizer=OPTIMIZER_FULL,
@@ -120,7 +120,7 @@ class TranslationTest:
res = ll_meta_interp(main, [40], CPUClass=self.CPUClass,
type_system=self.type_system)
assert res == main(40)
- res = rpython_ll_meta_interp(main, [40], loops=2, CPUClass=self.CPUClass,
+ res = rpython_ll_meta_interp(main, [40], CPUClass=self.CPUClass,
type_system=self.type_system,
optimizer=OPTIMIZER_FULL,
ProfilerClass=Profiler)
diff --git a/pypy/jit/metainterp/virtualizable.py b/pypy/jit/metainterp/virtualizable.py
index c6071dab9f..baa54fdb3d 100644
--- a/pypy/jit/metainterp/virtualizable.py
+++ b/pypy/jit/metainterp/virtualizable.py
@@ -100,48 +100,48 @@ class VirtualizableInfo:
i = i + 1
assert len(boxes) == i + 1
#
- def write_from_resume_data_partial(virtualizable, reader, nums):
+ def write_from_resume_data_partial(virtualizable, reader, numb):
# Load values from the reader (see resume.py) described by
# the list of numbers 'nums', and write them in their proper
# place in the 'virtualizable'. This works from the end of
# the list and returns the index in 'nums' of the start of
# the virtualizable data found, allowing the caller to do
# further processing with the start of the list.
- i = len(nums) - 1
+ i = len(numb.nums) - 1
assert i >= 0
for ARRAYITEMTYPE, fieldname in unroll_array_fields_rev:
lst = getattr(virtualizable, fieldname)
for j in range(getlength(lst)-1, -1, -1):
i -= 1
assert i >= 0
- x = reader.load_value_of_type(ARRAYITEMTYPE, nums[i])
+ x = reader.load_value_of_type(ARRAYITEMTYPE, numb.nums[i])
setarrayitem(lst, j, x)
for FIELDTYPE, fieldname in unroll_static_fields_rev:
i -= 1
assert i >= 0
- x = reader.load_value_of_type(FIELDTYPE, nums[i])
+ x = reader.load_value_of_type(FIELDTYPE, numb.nums[i])
setattr(virtualizable, fieldname, x)
return i
#
- def load_list_of_boxes(virtualizable, reader, nums):
+ def load_list_of_boxes(virtualizable, reader, numb):
# Uses 'virtualizable' only to know the length of the arrays;
# does not write anything into it. The returned list is in
# the format expected of virtualizable_boxes, so it ends in
# the virtualizable itself.
- i = len(nums) - 1
+ i = len(numb.nums) - 1
assert i >= 0
- boxes = [reader.decode_box_of_type(self.VTYPEPTR, nums[i])]
+ boxes = [reader.decode_box_of_type(self.VTYPEPTR, numb.nums[i])]
for ARRAYITEMTYPE, fieldname in unroll_array_fields_rev:
lst = getattr(virtualizable, fieldname)
for j in range(getlength(lst)-1, -1, -1):
i -= 1
assert i >= 0
- box = reader.decode_box_of_type(ARRAYITEMTYPE, nums[i])
+ box = reader.decode_box_of_type(ARRAYITEMTYPE,numb.nums[i])
boxes.append(box)
for FIELDTYPE, fieldname in unroll_static_fields_rev:
i -= 1
assert i >= 0
- box = reader.decode_box_of_type(FIELDTYPE, nums[i])
+ box = reader.decode_box_of_type(FIELDTYPE, numb.nums[i])
boxes.append(box)
boxes.reverse()
return boxes
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
index 819fa79957..a5d36ee7b8 100644
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -98,8 +98,7 @@ def jittify_and_run(interp, graph, args, repeat=1,
repeat -= 1
return res
-def rpython_ll_meta_interp(function, args, backendopt=True,
- loops='not used right now', **kwds):
+def rpython_ll_meta_interp(function, args, backendopt=True, **kwds):
return ll_meta_interp(function, args, backendopt=backendopt,
translate_support_code=True, **kwds)
diff --git a/pypy/jit/tool/loopcounter.py b/pypy/jit/tool/loopcounter.py
new file mode 100644
index 0000000000..978056f797
--- /dev/null
+++ b/pypy/jit/tool/loopcounter.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+"""
+Parse and display the traces produced by pypy-c-jit when PYPYLOG is set.
+"""
+
+import autopath
+import py
+import sys
+import optparse
+
+def get_timestamp(line):
+ import re
+ match = re.match(r'\[([0-9a-f]*)\] .*', line)
+ return int(match.group(1), 16)
+
+def main(logfile, options):
+ log = open(logfile)
+ loops = 0
+ bridges = 0
+ time0 = None
+ print 'timestamp,total,loops,bridges'
+ for line in log:
+ if time0 is None and line.startswith('['):
+ time0 = get_timestamp(line)
+ if '{jit-log-opt-' in line:
+ time_now = get_timestamp(line)
+ if '{jit-log-opt-loop' in line:
+ loops += 1
+ elif '{jit-log-opt-bridge' in line:
+ bridges += 1
+ else:
+ assert False, 'unknown category %s' % line
+ total = loops+bridges
+ timestamp = time_now - time0
+ print '%d,%d,%d,%d' % (timestamp, total, loops, bridges)
+
+if __name__ == '__main__':
+ parser = optparse.OptionParser(usage="%prog loopfile [options]")
+ options, args = parser.parse_args()
+ if len(args) != 1:
+ parser.print_help()
+ sys.exit(2)
+
+ main(args[0], options)
diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py
index 6d568bb195..9ac74a1617 100644
--- a/pypy/jit/tool/oparser.py
+++ b/pypy/jit/tool/oparser.py
@@ -192,7 +192,7 @@ class OpParser(object):
descr = None
if argspec.strip():
if opname == 'debug_merge_point':
- allargs = [argspec]
+ allargs = argspec.rsplit(', ', 1)
else:
allargs = [arg for arg in argspec.split(",")
if arg != '']
diff --git a/pypy/jit/tool/pypytrace-mode.el b/pypy/jit/tool/pypytrace-mode.el
index 77207b6d2c..6136a8331d 100644
--- a/pypy/jit/tool/pypytrace-mode.el
+++ b/pypy/jit/tool/pypytrace-mode.el
@@ -26,7 +26,7 @@
("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face))
;; comment out debug_merge_point, but then highlight specific part of it
("^debug_merge_point.*" . font-lock-comment-face)
- ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)')"
+ ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)"
(1 'compilation-warning t)
(2 'escape-glyph t)
(3 'font-lock-string-face t)
diff --git a/pypy/jit/tool/pypytrace.vim b/pypy/jit/tool/pypytrace.vim
index be299495e9..42f9cd3994 100644
--- a/pypy/jit/tool/pypytrace.vim
+++ b/pypy/jit/tool/pypytrace.vim
@@ -21,10 +21,10 @@ syn match pypyDebugMergePoint '^debug_merge_point(.\+)'
hi def link pypyLoopStart Structure
"hi def link pypyLoopArgs PreProc
-hi def link pypyFailArgs String
+hi def link pypyFailArgs Special
"hi def link pypyOpName Statement
-hi def link pypyDebugMergePoint Comment
+hi def link pypyDebugMergePoint String
hi def link pypyConstPtr Constant
hi def link pypyNumber Number
-hi def link pypyDescr String
+hi def link pypyDescr PreProc
hi def link pypyDescrField Label
diff --git a/pypy/jit/metainterp/test/test_oparser.py b/pypy/jit/tool/test/test_oparser.py
index ef06d4a439..a5a03314e3 100644
--- a/pypy/jit/metainterp/test/test_oparser.py
+++ b/pypy/jit/tool/test/test_oparser.py
@@ -141,10 +141,10 @@ def test_floats():
def test_debug_merge_point():
x = '''
[]
- debug_merge_point("info")
- debug_merge_point('info')
- debug_merge_point('<some ('other,')> info')
- debug_merge_point('(stuff) #1')
+ debug_merge_point("info", 0)
+ debug_merge_point('info', 1)
+ debug_merge_point('<some ('other,')> info', 1)
+ debug_merge_point('(stuff) #1', 1)
'''
loop = parse(x)
assert loop.operations[0].getarg(0)._get_str() == 'info'
@@ -168,7 +168,7 @@ i4 = int_add(i0, 2)
i6 = int_sub(i1, 1)
i8 = int_gt(i6, 3)
guard_true(i8, descr=<Guard15>) [i4, i6]
-debug_merge_point('(no jitdriver.get_printable_location!)')
+debug_merge_point('(no jitdriver.get_printable_location!)', 0)
jump(i6, i4, descr=<Loop0>)
'''
diff --git a/pypy/jit/tool/test/test_traceviewer.py b/pypy/jit/tool/test/test_traceviewer.py
index b3f3a3cde1..c505c8a576 100644
--- a/pypy/jit/tool/test/test_traceviewer.py
+++ b/pypy/jit/tool/test/test_traceviewer.py
@@ -19,7 +19,7 @@ class TestSplitLoops(object):
def test_no_of_loops(self):
data = [preparse("""
# Loop 0 : loop with 39 ops
- debug_merge_point('')
+ debug_merge_point('', 0)
guard_class(p4, 141310752, descr=<Guard5>) [p0, p1]
p60 = getfield_gc(p4, descr=<GcPtrFieldDescr 16>)
guard_nonnull(p60, descr=<Guard6>) [p0, p1]
@@ -51,7 +51,7 @@ class TestSplitLoops(object):
assert loop.right.content == 'extra'
def test_postparse(self):
- real_loops = [FinalBlock("debug_merge_point('<code object _runCallbacks, file '/tmp/x/twisted-trunk/twisted/internet/defer.py', line 357> #40 POP_TOP')", None)]
+ real_loops = [FinalBlock("debug_merge_point('<code object _runCallbacks, file '/tmp/x/twisted-trunk/twisted/internet/defer.py', line 357> #40 POP_TOP', 0)", None)]
postprocess(real_loops, real_loops[:], {})
assert real_loops[0].header.startswith("_runCallbacks, file '/tmp/x/twisted-trunk/twisted/internet/defer.py', line 357")