diff options
author | 2010-11-17 19:41:25 +0000 | |
---|---|---|
committer | 2010-11-17 19:41:25 +0000 | |
commit | baf678c574081d15f0e409eb8d004c76e87b95c2 (patch) | |
tree | 1b7f8e03b86f24a6c8a44ece82fcdb6e5602fce4 /pypy/jit/metainterp | |
parent | Better name (diff) | |
download | pypy-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/metainterp')
-rw-r--r-- | pypy/jit/metainterp/blackhole.py | 4 | ||||
-rw-r--r-- | pypy/jit/metainterp/compile.py | 30 | ||||
-rw-r--r-- | pypy/jit/metainterp/logger.py | 3 | ||||
-rw-r--r-- | pypy/jit/metainterp/optimizeopt/optimizer.py | 6 | ||||
-rw-r--r-- | pypy/jit/metainterp/optimizeopt/string.py | 5 | ||||
-rw-r--r-- | pypy/jit/metainterp/pyjitpl.py | 39 | ||||
-rw-r--r-- | pypy/jit/metainterp/resoperation.py | 20 | ||||
-rw-r--r-- | pypy/jit/metainterp/resume.py | 125 | ||||
-rw-r--r-- | pypy/jit/metainterp/test/test_basic.py | 26 | ||||
-rw-r--r-- | pypy/jit/metainterp/test/test_compile.py | 4 | ||||
-rw-r--r-- | pypy/jit/metainterp/test/test_del.py | 9 | ||||
-rw-r--r-- | pypy/jit/metainterp/test/test_logger.py | 2 | ||||
-rw-r--r-- | pypy/jit/metainterp/test/test_oparser.py | 205 | ||||
-rw-r--r-- | pypy/jit/metainterp/test/test_optimizeopt.py | 128 | ||||
-rw-r--r-- | pypy/jit/metainterp/test/test_resoperation.py | 7 | ||||
-rw-r--r-- | pypy/jit/metainterp/test/test_resume.py | 65 | ||||
-rw-r--r-- | pypy/jit/metainterp/test/test_virtualref.py | 6 | ||||
-rw-r--r-- | pypy/jit/metainterp/test/test_ztranslation.py | 4 | ||||
-rw-r--r-- | pypy/jit/metainterp/virtualizable.py | 18 | ||||
-rw-r--r-- | pypy/jit/metainterp/warmspot.py | 3 |
20 files changed, 337 insertions, 372 deletions
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_oparser.py b/pypy/jit/metainterp/test/test_oparser.py deleted file mode 100644 index ef06d4a439..0000000000 --- a/pypy/jit/metainterp/test/test_oparser.py +++ /dev/null @@ -1,205 +0,0 @@ - -from pypy.rpython.lltypesystem import lltype, llmemory - -from pypy.jit.tool.oparser import parse -from pypy.jit.metainterp.resoperation import rop -from pypy.jit.metainterp.history import AbstractDescr, BoxInt, LoopToken,\ - BoxFloat - -def test_basic_parse(): - x = """ - [i0, i1] - # a comment - i2 = int_add(i0, i1) - i3 = int_sub(i2, 3) # another comment - finish() # (tricky) - """ - loop = parse(x) - assert len(loop.operations) == 3 - assert [op.getopnum() for op in loop.operations] == [rop.INT_ADD, rop.INT_SUB, - rop.FINISH] - assert len(loop.inputargs) == 2 - assert loop.operations[-1].getdescr() - -def test_const_ptr_subops(): - x = """ - [p0] - guard_class(p0, ConstClass(vtable)) [] - """ - S = lltype.Struct('S') - vtable = lltype.nullptr(S) - loop = parse(x, None, locals()) - assert len(loop.operations) == 1 - assert loop.operations[0].getdescr() - assert loop.operations[0].getfailargs() == [] - -def test_descr(): - class Xyz(AbstractDescr): - pass - - x = """ - [p0] - i1 = getfield_gc(p0, descr=stuff) - """ - stuff = Xyz() - loop = parse(x, None, locals()) - assert loop.operations[0].getdescr() is stuff - -def test_after_fail(): - x = """ - [i0] - guard_value(i0, 3) [] - i1 = int_add(1, 2) - """ - loop = parse(x, None, {}) - assert len(loop.operations) == 2 - -def test_descr_setfield(): - class Xyz(AbstractDescr): - pass - - x = """ - [p0] - setfield_gc(p0, 3, descr=stuff) - """ - stuff = Xyz() - loop = parse(x, None, locals()) - assert loop.operations[0].getdescr() is stuff - -def test_boxname(): - x = """ - [i42] - i50 = int_add(i42, 1) - """ - loop = parse(x, None, {}) - assert str(loop.inputargs[0]) == 'i42' - assert str(loop.operations[0].result) == 'i50' - -def test_getboxes(): - x = """ - [i0] - i1 = int_add(i0, 10) - """ - loop = parse(x, None, {}) - boxes = loop.getboxes() - assert boxes.i0 is loop.inputargs[0] - assert boxes.i1 is loop.operations[0].result - -def test_setvalues(): - x = """ - [i0] - i1 = int_add(i0, 10) - """ - loop = parse(x, None, {}) - loop.setvalues(i0=32, i1=42) - assert loop.inputargs[0].value == 32 - assert loop.operations[0].result.value == 42 - -def test_boxkind(): - x = """ - [sum0] - """ - loop = parse(x, None, {}, boxkinds={'sum': BoxInt}) - b = loop.getboxes() - assert isinstance(b.sum0, BoxInt) - -def test_getvar_const_ptr(): - x = ''' - [] - call(ConstPtr(func_ptr)) - ''' - TP = lltype.GcArray(lltype.Signed) - NULL = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.nullptr(TP)) - loop = parse(x, None, {'func_ptr' : NULL}) - assert loop.operations[0].getarg(0).value == NULL - -def test_jump_target(): - x = ''' - [] - jump() - ''' - loop = parse(x) - assert loop.operations[0].getdescr() is loop.token - -def test_jump_target_other(): - looptoken = LoopToken() - x = ''' - [] - jump(descr=looptoken) - ''' - loop = parse(x, namespace=locals()) - assert loop.operations[0].getdescr() is looptoken - -def test_floats(): - x = ''' - [f0] - f1 = float_add(f0, 3.5) - ''' - loop = parse(x) - assert isinstance(loop.operations[0].getarg(0), BoxFloat) - -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') - ''' - loop = parse(x) - assert loop.operations[0].getarg(0)._get_str() == 'info' - assert loop.operations[1].getarg(0)._get_str() == 'info' - assert loop.operations[2].getarg(0)._get_str() == "<some ('other,')> info" - assert loop.operations[3].getarg(0)._get_str() == "(stuff) #1" - - -def test_descr_with_obj_print(): - x = ''' - [p0] - setfield_gc(p0, 1, descr=<SomeDescr>) - ''' - loop = parse(x) - # assert did not explode - -example_loop_log = '''\ -# bridge out of Guard12, 6 ops -[i0, i1, i2] -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!)') -jump(i6, i4, descr=<Loop0>) -''' - -def test_parse_no_namespace(): - loop = parse(example_loop_log, no_namespace=True) - -def test_attach_comment_to_loop(): - loop = parse(example_loop_log, no_namespace=True) - assert loop.comment == '# bridge out of Guard12, 6 ops' - -def test_parse_new_with_comma(): - # this is generated by PYPYJITLOG, check that we can handle it - x = ''' - [] - p0 = new(, descr=<SizeDescr 12>) - ''' - loop = parse(x) - assert loop.operations[0].getopname() == 'new' - -def test_no_fail_args(): - x = ''' - [i0] - guard_true(i0, descr=<Guard0>) - ''' - loop = parse(x, nonstrict=True) - assert loop.operations[0].getfailargs() == [] - -def test_no_inputargs(): - x = ''' - i2 = int_add(i0, i1) - ''' - loop = parse(x, nonstrict=True) - assert loop.inputargs == [] - assert loop.operations[0].getopname() == 'int_add' 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) |