Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: optinfo-into-bridges Changeset: r87847:50dd16dbcea8 Date: 2016-10-17 15:52 +0200 http://bitbucket.org/pypy/pypy/changeset/50dd16dbcea8/
Log: encode pending fields into the resume code (it's more compact and saves one word on every guard) diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -17,8 +17,7 @@ TargetToken, AbstractFailDescr, ConstInt) from rpython.jit.metainterp import history, jitexc from rpython.jit.metainterp.optimize import InvalidLoop -from rpython.jit.metainterp.resume import (PENDINGFIELDSP, - ResumeDataDirectReader, AccumInfo) +from rpython.jit.metainterp.resume import ResumeDataDirectReader from rpython.jit.metainterp.resumecode import NUMBERING from rpython.jit.codewriter import heaptracker, longlong @@ -864,18 +863,16 @@ class ResumeGuardDescr(AbstractResumeGuardDescr): _attrs_ = ('rd_numb', 'rd_consts', 'rd_virtuals', - 'rd_pendingfields', 'status') + 'status') rd_numb = lltype.nullptr(NUMBERING) rd_consts = None rd_virtuals = None - rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) def copy_all_attributes_from(self, other): if isinstance(other, ResumeGuardCopiedDescr): other = other.prev assert isinstance(other, ResumeGuardDescr) self.rd_consts = other.rd_consts - self.rd_pendingfields = other.rd_pendingfields self.rd_virtuals = other.rd_virtuals self.rd_numb = other.rd_numb # we don't copy status diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -227,6 +227,11 @@ self.cached_infos = [] self.cached_structs = [] +class PendingWrites(object): + def __init__(self, fields, arrays): + self.fields = fields + self.arrays = arrays + class OptHeap(Optimization): """Cache repeated heap accesses""" @@ -329,7 +334,7 @@ if rop.is_ovf(op.opnum): return if rop.is_guard(op.opnum): - self.optimizer.pendingfields = ( + self.optimizer.pendingwrites = ( self.force_lazy_sets_for_guard()) return opnum = op.getopnum() @@ -513,6 +518,7 @@ pendingfields.append(op) continue cf.force_lazy_set(self, descr) + pendingarrays = [] for descr, submap in self.cached_arrayitems.iteritems(): for index, cf in submap.iteritems(): op = cf._lazy_set @@ -525,10 +531,10 @@ opinfo = self.getptrinfo(op.getarg(0)) assert not opinfo.is_virtual() # it must be a non-virtual if self.optimizer.is_virtual(op.getarg(2)): - pendingfields.append(op) + pendingarrays.append(op) else: cf.force_lazy_set(self, descr) - return pendingfields + return PendingWrites(pendingfields, pendingarrays) def optimize_GETFIELD_GC_I(self, op): descr = op.getdescr() diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py b/rpython/jit/metainterp/optimizeopt/optimizer.py --- a/rpython/jit/metainterp/optimizeopt/optimizer.py +++ b/rpython/jit/metainterp/optimizeopt/optimizer.py @@ -274,8 +274,9 @@ self.interned_refs = self.cpu.ts.new_ref_dict() self.interned_ints = {} self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd) - self.pendingfields = None # set temporarily to a list, normally by - # heap.py, as we're about to generate a guard + # set temporarily to an instance of heap.PendingWrites, normally by + # heap.py, as we're about to generate a guard + self.pendingwrites = None self.quasi_immutable_deps = None self.replaces_guard = {} self._newoperations = [] @@ -612,14 +613,14 @@ if rop.is_guard(op.opnum): assert isinstance(op, GuardResOp) self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS) - pendingfields = self.pendingfields - self.pendingfields = None + pendingwrites = self.pendingwrites + self.pendingwrites = None if self.replaces_guard and orig_op in self.replaces_guard: self.replace_guard_op(self.replaces_guard[orig_op], op) del self.replaces_guard[orig_op] return else: - op = self.emit_guard_operation(op, pendingfields) + op = self.emit_guard_operation(op, pendingwrites) elif op.can_raise(): self.exception_might_have_happened = True opnum = op.opnum @@ -632,7 +633,7 @@ self._really_emitted_operation = op self._newoperations.append(op) - def emit_guard_operation(self, op, pendingfields): + def emit_guard_operation(self, op, pendingwrites): guard_op = op # self.replace_op_with(op, op.getopnum()) opnum = guard_op.getopnum() # If guard_(no)_exception is merged with another previous guard, then @@ -652,7 +653,7 @@ op = self._copy_resume_data_from(guard_op, self._last_guard_op) else: - op = self.store_final_boxes_in_guard(guard_op, pendingfields) + op = self.store_final_boxes_in_guard(guard_op, pendingwrites) self._last_guard_op = op # for unrolling for farg in op.getfailargs(): @@ -722,8 +723,7 @@ new_descr.copy_all_attributes_from(old_descr) self._newoperations[old_op_pos] = new_op - def store_final_boxes_in_guard(self, op, pendingfields): - assert pendingfields is not None + def store_final_boxes_in_guard(self, op, pendingwrites): if op.getdescr() is not None: descr = op.getdescr() assert isinstance(descr, compile.ResumeGuardDescr) @@ -735,11 +735,12 @@ modifier = resume.ResumeDataVirtualAdder(self, descr, op, self.trace, self.resumedata_memo) try: - newboxes = modifier.finish(pendingfields) + newboxes = modifier.finish(pendingwrites) if (newboxes is not None and len(newboxes) > self.metainterp_sd.options.failargs_limit): raise resume.TagOverflow except resume.TagOverflow: + #import pdb;pdb.xpm() raise compile.giveup() # check no duplicates #if not we_are_translated(): diff --git a/rpython/jit/metainterp/optimizeopt/simplify.py b/rpython/jit/metainterp/optimizeopt/simplify.py --- a/rpython/jit/metainterp/optimizeopt/simplify.py +++ b/rpython/jit/metainterp/optimizeopt/simplify.py @@ -10,8 +10,7 @@ def emit(self, op): if op.is_guard(): - if self.optimizer.pendingfields is None: - self.optimizer.pendingfields = [] + self.optimizer.pendingwrites = None return Optimization.emit(self, op) def optimize_CALL_PURE_I(self, op): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py --- a/rpython/jit/metainterp/optimizeopt/test/test_util.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py @@ -488,6 +488,8 @@ self.globaldata = Fake() self.config = get_combined_translation_config(translating=True) self.jitlog = jl.JitLogger() + if cpu: + self.all_descrs = self.cpu.setup_descrs() class logger_noopt: @classmethod diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -80,7 +80,8 @@ def postprocess_FINISH(self, op): guard_op = self._finish_guard_op if guard_op is not None: - guard_op = self.optimizer.store_final_boxes_in_guard(guard_op, []) + # XXX why are there never any pendingwrites here? + guard_op = self.optimizer.store_final_boxes_in_guard(guard_op, None) i = len(self.optimizer._newoperations) - 1 assert i >= 0 self.optimizer._newoperations.insert(i, guard_op) diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py --- a/rpython/jit/metainterp/resume.py +++ b/rpython/jit/metainterp/resume.py @@ -116,13 +116,6 @@ virtualizable_boxes, virtualref_boxes) return result -PENDINGFIELDSTRUCT = lltype.Struct('PendingField', - ('lldescr', OBJECTPTR), - ('num', rffi.SHORT), - ('fieldnum', rffi.SHORT), - ('itemindex', rffi.INT)) -PENDINGFIELDSP = lltype.Ptr(lltype.GcArray(PENDINGFIELDSTRUCT)) - TAGMASK = 3 def tag(value, tagbits): @@ -160,7 +153,7 @@ TAG_CONST_OFFSET = 0 class NumberingState(resumecode.Writer): - def __init__(self, size): + def __init__(self, size=0): resumecode.Writer.__init__(self, size) self.liveboxes = {} self.num_boxes = 0 @@ -217,45 +210,47 @@ # env numbering + def _number_box(self, box, optimizer, numb_state): + box = optimizer.get_box_replacement(box) + liveboxes = numb_state.liveboxes + + if isinstance(box, Const): + tagged = self.getconst(box) + elif box in liveboxes: + tagged = liveboxes[box] + else: + is_virtual = False + if box.type == 'r': + info = optimizer.getptrinfo(box) + is_virtual = (info is not None and info.is_virtual()) + if box.type == 'i': + info = optimizer.getrawptrinfo(box, create=False) + is_virtual = (info is not None and info.is_virtual()) + if is_virtual: + tagged = tag(numb_state.num_virtuals, TAGVIRTUAL) + numb_state.num_virtuals += 1 + else: + tagged = tag(numb_state.num_boxes, TAGBOX) + numb_state.num_boxes += 1 + liveboxes[box] = tagged + return tagged + def _number_boxes(self, iter, arr, optimizer, numb_state): """ Number boxes from one snapshot """ - num_boxes = numb_state.num_boxes - num_virtuals = numb_state.num_virtuals - liveboxes = numb_state.liveboxes for item in arr: box = iter.get(rffi.cast(lltype.Signed, item)) - box = optimizer.get_box_replacement(box) + tagged = self._number_box(box, optimizer, numb_state) + numb_state.append_int(tagged) - if isinstance(box, Const): - tagged = self.getconst(box) - elif box in liveboxes: - tagged = liveboxes[box] - else: - is_virtual = False - if box.type == 'r': - info = optimizer.getptrinfo(box) - is_virtual = (info is not None and info.is_virtual()) - if box.type == 'i': - info = optimizer.getrawptrinfo(box, create=False) - is_virtual = (info is not None and info.is_virtual()) - if is_virtual: - tagged = tag(num_virtuals, TAGVIRTUAL) - num_virtuals += 1 - else: - tagged = tag(num_boxes, TAGBOX) - num_boxes += 1 - liveboxes[box] = tagged - numb_state.append_int(tagged) - numb_state.num_boxes = num_boxes - numb_state.num_virtuals = num_virtuals - - def number(self, optimizer, position, trace): + def number(self, optimizer, position, trace, pendingwrites=None): snapshot_iter = trace.get_snapshot_iter(position) numb_state = NumberingState(snapshot_iter.size) numb_state.append_int(0) # patch later: size of resume section numb_state.append_int(0) # patch later: number of failargs + self._add_pending_writes(optimizer, pendingwrites, numb_state) + arr = snapshot_iter.vable_array numb_state.append_int(len(arr)) @@ -278,6 +273,43 @@ return numb_state + def _add_pending_writes(self, optimizer, pendingwrites, numb_state): + if not pendingwrites: + numb_state.append_int(0) + numb_state.append_int(0) + return + metainterp_sd = optimizer.metainterp_sd + numb_state.append_int(len(pendingwrites.fields)) + for op in pendingwrites.fields: + box = optimizer.get_box_replacement(op.getarg(0)) + descr = op.getdescr() + if descr.descr_index == -1: + raise TagOverflow # shouldn't happen + fieldbox = optimizer.get_box_replacement(op.getarg(1)) + numb_state.append_int(self._number_box(box, optimizer, numb_state)) + numb_state.append_int(descr.descr_index) + numb_state.append_int(self._number_box(fieldbox, optimizer, numb_state)) + + numb_state.append_int(len(pendingwrites.arrays)) + for op in pendingwrites.arrays: + box = optimizer.get_box_replacement(op.getarg(0)) + descr = op.getdescr() + if descr.descr_index == -1: + raise TagOverflow # shouldn't happen + boxindex = optimizer.get_box_replacement(op.getarg(1)) + itemindex = boxindex.getint() + # sanity: it's impossible to run code with SETARRAYITEM_GC + # with negative index, so this guard cannot ever fail; + # but it's possible to try to *build* such invalid code + if itemindex < 0: + raise TagOverflow + fieldbox = optimizer.get_box_replacement(op.getarg(2)) + numb_state.append_int(self._number_box(box, optimizer, numb_state)) + numb_state.append_int(descr.descr_index) + # the index is limited to 2**21 + numb_state.append_int(itemindex) + numb_state.append_int(self._number_box(fieldbox, optimizer, numb_state)) + # caching for virtuals and boxes inside them @@ -409,7 +441,7 @@ _, tagbits = untag(tagged) return tagbits == TAGVIRTUAL - def finish(self, pending_setfields=[]): + def finish(self, pendingwrites=None): optimizer = self.optimizer # compute the numbering storage = self.storage @@ -419,7 +451,7 @@ assert resume_position >= 0 # count stack depth numb_state = self.memo.number(optimizer, - resume_position, optimizer.trace) + resume_position, optimizer.trace, pendingwrites) self.liveboxes_from_env = liveboxes_from_env = numb_state.liveboxes num_virtuals = numb_state.num_virtuals self.liveboxes = {} @@ -442,22 +474,8 @@ assert info.is_virtual() info.visitor_walk_recursive(box, self, optimizer) - for setfield_op in pending_setfields: - box = setfield_op.getarg(0) - box = optimizer.get_box_replacement(box) - if setfield_op.getopnum() == rop.SETFIELD_GC: - fieldbox = setfield_op.getarg(1) - else: - fieldbox = setfield_op.getarg(2) - fieldbox = optimizer.get_box_replacement(fieldbox) - self.register_box(box) - self.register_box(fieldbox) - info = optimizer.getptrinfo(fieldbox) - assert info is not None and info.is_virtual() - info.visitor_walk_recursive(fieldbox, self, optimizer) - + # extends liveboxes! self._number_virtuals(liveboxes, optimizer, num_virtuals) - self._add_pending_fields(optimizer, pending_setfields) numb_state.patch(1, len(liveboxes)) @@ -468,7 +486,7 @@ def _number_virtuals(self, liveboxes, optimizer, num_env_virtuals): from rpython.jit.metainterp.optimizeopt.info import AbstractVirtualPtrInfo - + # !! 'liveboxes' is a list that is extend()ed in-place !! memo = self.memo new_liveboxes = [None] * memo.num_cached_boxes() @@ -532,45 +550,6 @@ return True return False - def _add_pending_fields(self, optimizer, pending_setfields): - rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO) - if pending_setfields: - n = len(pending_setfields) - rd_pendingfields = lltype.malloc(PENDINGFIELDSP.TO, n) - for i in range(n): - op = pending_setfields[i] - box = optimizer.get_box_replacement(op.getarg(0)) - descr = op.getdescr() - opnum = op.getopnum() - if opnum == rop.SETARRAYITEM_GC: - fieldbox = op.getarg(2) - boxindex = optimizer.get_box_replacement(op.getarg(1)) - itemindex = boxindex.getint() - # sanity: it's impossible to run code with SETARRAYITEM_GC - # with negative index, so this guard cannot ever fail; - # but it's possible to try to *build* such invalid code - if itemindex < 0: - raise TagOverflow - elif opnum == rop.SETFIELD_GC: - fieldbox = op.getarg(1) - itemindex = -1 - else: - raise AssertionError - fieldbox = optimizer.get_box_replacement(fieldbox) - #descr, box, fieldbox, itemindex = pending_setfields[i] - lldescr = annlowlevel.cast_instance_to_base_ptr(descr) - num = rffi.r_short(self._gettagged(box)) - fieldnum = rffi.r_short(self._gettagged(fieldbox)) - # the index is limited to 2147483647 (64-bit machines only) - if itemindex > 2147483647: - raise TagOverflow - # - rd_pendingfields[i].lldescr = lldescr - rd_pendingfields[i].num = num - rd_pendingfields[i].fieldnum = fieldnum - rd_pendingfields[i].itemindex = rffi.cast(rffi.INT, itemindex) - self.storage.rd_pendingfields = rd_pendingfields - def _gettagged(self, box): if box is None: return UNINITIALIZED @@ -926,17 +905,18 @@ virtual_int_default = None - def _init(self, cpu, storage): - self.cpu = cpu + def _init(self, metainterp_sd, storage): + self.metainterp_sd = metainterp_sd + self.cpu = metainterp_sd.cpu self.resumecodereader = resumecode.Reader(storage.rd_numb) - count = self.resumecodereader.next_item() - self.items_resume_section = count + items_resume_section = self.resumecodereader.next_item() + self.items_resume_section = items_resume_section self.count = self.resumecodereader.next_item() self.consts = storage.rd_consts def _prepare(self, storage): self._prepare_virtuals(storage.rd_virtuals) - self._prepare_pendingfields(storage.rd_pendingfields) + self._prepare_pendingfields() def read_jitcode_pos_pc(self): jitcode_pos = self.resumecodereader.next_item() @@ -1003,21 +983,23 @@ self.virtuals_cache = self.VirtualCache([self.virtual_ptr_default] * len(virtuals), [self.virtual_int_default] * len(virtuals)) - def _prepare_pendingfields(self, pendingfields): - if pendingfields: - for i in range(len(pendingfields)): - lldescr = pendingfields[i].lldescr - num = pendingfields[i].num - fieldnum = pendingfields[i].fieldnum - itemindex = pendingfields[i].itemindex - descr = annlowlevel.cast_base_ptr_to_instance(AbstractDescr, - lldescr) - struct = self.decode_ref(num) - itemindex = rffi.cast(lltype.Signed, itemindex) - if itemindex < 0: - self.setfield(struct, fieldnum, descr) - else: - self.setarrayitem(struct, itemindex, fieldnum, descr) + def _prepare_pendingfields(self): + metainterp_sd = self.metainterp_sd + for i in range(self.resumecodereader.next_item()): + num = self.resumecodereader.next_item() + struct = self.decode_ref(num) + descrindex = self.resumecodereader.next_item() + descr = metainterp_sd.all_descrs[descrindex] + fieldnum = self.resumecodereader.next_item() + self.setfield(struct, fieldnum, descr) + for i in range(self.resumecodereader.next_item()): + num = self.resumecodereader.next_item() + struct = self.decode_ref(num) + descrindex = self.resumecodereader.next_item() + descr = metainterp_sd.all_descrs[descrindex] + index = self.resumecodereader.next_item() + fieldnum = self.resumecodereader.next_item() + self.setarrayitem(struct, index, fieldnum, descr) def setarrayitem(self, array, index, fieldnum, arraydescr): if arraydescr.is_array_of_pointers(): @@ -1072,7 +1054,7 @@ VirtualCache = get_VirtualCache_class('BoxReader') def __init__(self, storage, deadframe, metainterp): - self._init(metainterp.cpu, storage) + self._init(metainterp.staticdata, storage) self.deadframe = deadframe self.metainterp = metainterp self.liveboxes = [None] * self.count @@ -1363,7 +1345,7 @@ # 2: resuming from the GUARD_NOT_FORCED def __init__(self, metainterp_sd, storage, deadframe, all_virtuals=None): - self._init(metainterp_sd.cpu, storage) + self._init(metainterp_sd, storage) self.deadframe = deadframe self.callinfocollection = metainterp_sd.callinfocollection if all_virtuals is None: # common case @@ -1376,6 +1358,12 @@ # self.rd_virtuals can remain None, because virtuals_cache is # already filled + # skip over the resume code section that does pending field writes + num_field_writes = self.resumecodereader.next_item() + assert num_field_writes == 0 + num_array_writes = self.resumecodereader.next_item() + assert num_array_writes == 0 + def handling_async_forcing(self): self.resume_after_guard_not_forced = 1 diff --git a/rpython/jit/metainterp/resumecode.py b/rpython/jit/metainterp/resumecode.py --- a/rpython/jit/metainterp/resumecode.py +++ b/rpython/jit/metainterp/resumecode.py @@ -3,6 +3,8 @@ # ----- resume section [total size of resume section, unencoded] [number of failargs] + [<length> (<numb> <descr> <numb>] setfields + [<length> (<numb> <descr> <index> <numb>] setarrayitems [<length> <virtualizable object> <numb> <numb> <numb>] if vinfo is not None -OR- [1 <ginfo object>] if ginfo is not None diff --git a/rpython/jit/metainterp/test/test_resume.py b/rpython/jit/metainterp/test/test_resume.py --- a/rpython/jit/metainterp/test/test_resume.py +++ b/rpython/jit/metainterp/test/test_resume.py @@ -10,9 +10,9 @@ VArrayInfoNotClear, VStrPlainInfo, VStrConcatInfo, VStrSliceInfo,\ VUniPlainInfo, VUniConcatInfo, VUniSliceInfo,\ capture_resumedata, ResumeDataLoopMemo, UNASSIGNEDVIRTUAL, INT,\ - annlowlevel, PENDINGFIELDSP, TAG_CONST_OFFSET + annlowlevel, TAG_CONST_OFFSET, NumberingState from rpython.jit.metainterp.resumecode import unpack_numbering,\ - create_numbering, NULL_NUMBER + create_numbering, NULL_NUMBER, Reader from rpython.jit.metainterp.opencoder import Trace, Snapshot, TopSnapshot from rpython.jit.metainterp.optimizeopt import info @@ -35,7 +35,6 @@ rd_numb = None rd_consts = [] rd_virtuals = None - rd_pendingfields = None class FakeOptimizer(object): @@ -97,14 +96,6 @@ debug_print('\t\t', 'None') else: virtual.debug_prints() - if storage.rd_pendingfields: - debug_print('\tpending setfields') - for i in range(len(storage.rd_pendingfields)): - lldescr = storage.rd_pendingfields[i].lldescr - num = storage.rd_pendingfields[i].num - fieldnum = storage.rd_pendingfields[i].fieldnum - itemindex = storage.rd_pendingfields[i].itemindex - debug_print("\t\t", str(lldescr), str(untag(num)), str(untag(fieldnum)), itemindex) debug_stop("jit-resume") @@ -171,6 +162,12 @@ else: assert op.type == 'v' +class FakeStaticData(object): + def __init__(self, cpu): + self.cpu = cpu + if hasattr(cpu, 'setup_descrs'): + self.all_descrs = cpu.setup_descrs() + class MyMetaInterp: _already_allocated_resume_virtuals = None callinfocollection = None @@ -179,6 +176,7 @@ if cpu is None: cpu = LLtypeMixin.cpu self.cpu = cpu + self.staticdata = FakeStaticData(cpu) self.trace = [] self.framestack = [] @@ -301,7 +299,7 @@ c1, c2, c3 = [ConstInt(111), ConstInt(222), ConstInt(333)] storage = Storage() storage.rd_consts = [c1, c2, c3] - numb = Numbering([3, tag(0, TAGBOX), tagconst(0), + numb = Numbering([3, 0, 0, tag(0, TAGBOX), tagconst(0), NULLREF, tag(0, TAGBOX), tag(1, TAGBOX)] + [tagconst(1), tagconst(2)] + [tag(0, TAGBOX), tag(1, TAGBOX), tag(2, TAGBOX)]) @@ -346,7 +344,7 @@ def test_simple_read_tagged_ints(): storage = Storage() storage.rd_consts = [] - numb = Numbering([1, tag(100, TAGINT)]) + numb = Numbering([1, 0, 0, tag(100, TAGINT)]) storage.rd_numb = numb # cpu = MyCPU([]) @@ -363,9 +361,8 @@ return s class FakeStorage(object): rd_virtuals = [FakeVinfo(), None] - rd_numb = Numbering([1]) + rd_numb = Numbering([1, 0, 0]) rd_consts = [] - rd_pendingfields = None class FakeMetainterp(object): _already_allocated_resume_virtuals = None cpu = None @@ -858,7 +855,7 @@ base = [0, 0, tag(0, TAGBOX), tag(1, TAGINT), tag(1, TAGBOX), tag(0, TAGBOX), tag(2, TAGINT)] - assert unpack_numbering(numb) == [17, 0, 0, 0] + base + [0, 2, tag(3, TAGINT), tag(2, TAGBOX), + assert unpack_numbering(numb) == [19, 0, 0, 0, 0, 0] + base + [0, 2, tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX), tag(1, TAGINT)] t.append(0) snap2 = t.create_top_snapshot(FakeJitCode("jitcode", 0), 2, Frame(env2), @@ -872,7 +869,7 @@ assert numb_state2.liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX), b3: tag(2, TAGBOX)} assert numb_state2.liveboxes is not numb_state.liveboxes - assert unpack_numbering(numb2) == [17, 0, 0, 0] + base + [0, 2, tag(3, TAGINT), tag(2, TAGBOX), + assert unpack_numbering(numb2) == [19, 0, 0, 0, 0, 0] + base + [0, 2, tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX), tag(3, TAGINT)] t.append(0) @@ -894,7 +891,7 @@ assert numb_state3.num_virtuals == 0 assert numb_state3.liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX)} - assert unpack_numbering(numb3) == ([17, 0, 0, 2, tag(3, TAGINT), tag(4, TAGINT), + assert unpack_numbering(numb3) == ([19, 0, 0, 0, 0, 2, tag(3, TAGINT), tag(4, TAGINT), tag(0, TAGBOX), tag(3, TAGINT)] + base + [0, 2]) @@ -911,7 +908,7 @@ assert numb_state4.liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX), b4: tag(0, TAGVIRTUAL)} - assert unpack_numbering(numb4) == [17, 0, 0, 2, tag(3, TAGINT), tag(0, TAGVIRTUAL), + assert unpack_numbering(numb4) == [19, 0, 0, 0, 0, 2, tag(3, TAGINT), tag(0, TAGVIRTUAL), tag(0, TAGBOX), tag(3, TAGINT)] + base + [0, 2] t.append(0) @@ -930,7 +927,7 @@ assert numb_state5.liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX), b4: tag(0, TAGVIRTUAL), b5: tag(1, TAGVIRTUAL)} - assert unpack_numbering(numb5) == [22, 0, + assert unpack_numbering(numb5) == [24, 0, 0, 0, 3, tag(0, TAGBOX), tag(0, TAGVIRTUAL), tag(1, TAGVIRTUAL), 0] + base + [ 2, 1, tag(3, TAGINT), tag(0, TAGVIRTUAL), tag(0, TAGBOX), tag(3, TAGINT) @@ -951,15 +948,17 @@ l = unpack_numbering(numb) assert l[0] == len(l) assert l[1] == 0 - assert l[1] == 0 assert l[2] == 0 assert l[3] == 0 assert l[4] == 0 + assert l[5] == 0 + assert l[6] == 0 + assert l[7] == 0 mapping = dict(zip(inpargs, i.inputargs)) for i, item in enumerate(lst): - v, tag = untag(l[i + 6]) + v, tag = untag(l[i + 8]) if tag == TAGBOX: - assert l[i + 6] == numb_state.liveboxes[mapping[item]] + assert l[i + 8] == numb_state.liveboxes[mapping[item]] elif tag == TAGCONST: assert memo.consts[v].getint() == item.getint() elif tag == TAGINT: @@ -1102,7 +1101,7 @@ class ResumeDataFakeReader(ResumeDataBoxReader): """Another subclass of AbstractResumeDataReader meant for tests.""" def __init__(self, storage, newboxes, metainterp): - self._init(metainterp.cpu, storage) + self._init(metainterp.staticdata, storage) self.liveboxes = newboxes self.metainterp = metainterp self._prepare(storage) @@ -1232,7 +1231,7 @@ liveboxes = [] modifier._number_virtuals(liveboxes, FakeOptimizer(), 0) storage.rd_consts = memo.consts[:] - storage.rd_numb = Numbering([0]) + storage.rd_numb = Numbering([0, 0, 0]) # resume b3t, b5t = [IntFrontendOp(0), RefFrontendOp(0)] b5t.setref_base(demo55o) @@ -1303,7 +1302,7 @@ modifier._number_virtuals(liveboxes, FakeOptimizer(), 0) dump_storage(storage, liveboxes) storage.rd_consts = memo.consts[:] - storage.rd_numb = Numbering([0]) + storage.rd_numb = Numbering([0, 0, 0]) # resume b1t, b3t, b4t = [IntFrontendOp(0), IntFrontendOp(0), IntFrontendOp(0)] b1t.setint(11) @@ -1356,7 +1355,7 @@ modifier._number_virtuals(liveboxes, FakeOptimizer(), 0) dump_storage(storage, liveboxes) storage.rd_consts = memo.consts[:] - storage.rd_numb = Numbering([0]) + storage.rd_numb = Numbering([0, 0, 0]) b4t = RefFrontendOp(0) newboxes = _resume_remap(liveboxes, [#b2s -- virtual b4s], b4t) @@ -1384,25 +1383,50 @@ assert ptr.b == lltype.nullptr(LLtypeMixin.NODE) -def test_virtual_adder_pending_fields(): +def test_virtual_adder_pending_fields(monkeypatch): + from rpython.jit.metainterp.optimizeopt.heap import PendingWrites + monkeypatch.setattr(LLtypeMixin.nextdescr, "descr_index", 0) + metainterp_sd = FakeMetaInterpStaticData() + metainterp_sd.all_descrs = [LLtypeMixin.nextdescr] b2s, b4s = [RefFrontendOp(0), RefFrontendOp(0)] storage = Storage() - memo = ResumeDataLoopMemo(FakeMetaInterpStaticData()) + optimizer = FakeOptimizer() + optimizer.metainterp_sd = metainterp_sd + + memo = ResumeDataLoopMemo(metainterp_sd) + modifier = ResumeDataVirtualAdder(None, storage, storage, None, memo) - modifier.liveboxes_from_env = {} + # simulated call to "finish" + # first call number: + numb_state = NumberingState() + numb_state.append_int(0) + numb_state.append_int(0) + pendingwrites = PendingWrites([ + ResOperation(rop.SETFIELD_GC, [b2s, b4s], descr=LLtypeMixin.nextdescr)], + []) + memo._add_pending_writes(optimizer, pendingwrites, numb_state) + + # now back in finish + + modifier.liveboxes_from_env = numb_state.liveboxes modifier.liveboxes = {} + liveboxes = [None] * len(modifier.liveboxes_from_env) + for box, tagged in modifier.liveboxes_from_env.iteritems(): + i, tagbits = untag(tagged) + assert tagbits == TAGBOX + liveboxes[i] = box + assert liveboxes == [b2s, b4s] + modifier.vfieldboxes = {} + # simulate _walk_pending_write # XXX unneeded? modifier.register_box(b2s) modifier.register_box(b4s) - liveboxes = [] modifier._number_virtuals(liveboxes, FakeOptimizer(), 0) - assert liveboxes == [b2s, b4s] or liveboxes == [b4s, b2s] - modifier._add_pending_fields(FakeOptimizer(), [ - ResOperation(rop.SETFIELD_GC, [b2s, b4s], descr=LLtypeMixin.nextdescr)]) storage.rd_consts = memo.consts[:] - storage.rd_numb = Numbering([0]) + storage.rd_numb = numb_state.create_numbering() + # resume demo55.next = lltype.nullptr(LLtypeMixin.NODE) b2t = RefFrontendOp(0) @@ -1412,6 +1436,7 @@ newboxes = _resume_remap(liveboxes, [b2s, b4s], b2t, b4t) metainterp = MyMetaInterp() + metainterp.staticdata = metainterp_sd reader = ResumeDataFakeReader(storage, newboxes, metainterp) assert reader.virtuals_cache is None trace = metainterp.trace @@ -1424,125 +1449,130 @@ assert demo55.next == demo66 def test_virtual_adder_pending_fields_and_arrayitems(): - class Storage(object): - pass - storage = Storage() - modifier = ResumeDataVirtualAdder(None, storage, storage, None, None) - modifier._add_pending_fields(None, []) - assert not storage.rd_pendingfields + from rpython.jit.metainterp.optimizeopt.heap import PendingWrites + metainterp_sd = FakeMetaInterpStaticData() + metainterp_sd.all_descrs = [] + optimizer = FakeOptimizer() + optimizer.metainterp_sd = metainterp_sd + + memo = ResumeDataLoopMemo(metainterp_sd) + numb_state = NumberingState() + memo._add_pending_writes(optimizer, None, numb_state) + assert numb_state.current == [0, 0] + # class FieldDescr(AbstractDescr): + def __init__(self): + self.descr_index = len(metainterp_sd.all_descrs) + metainterp_sd.all_descrs.append(self) + def is_array_of_primitives(self): return False + field_a = FieldDescr() - storage = Storage() - modifier = ResumeDataVirtualAdder(None, storage, storage, None, None) + memo = ResumeDataLoopMemo(metainterp_sd) + numb_state = NumberingState() a = IntFrontendOp(0) b = IntFrontendOp(0) - modifier.liveboxes_from_env = {a: rffi.cast(rffi.SHORT, 1042), - b: rffi.cast(rffi.SHORT, 1061)} - modifier._add_pending_fields(FakeOptimizer(), [ + numb_state.liveboxes = {a: 1042, b: 1061} + pendingwrites = PendingWrites([ ResOperation(rop.SETFIELD_GC, [a, b], - descr=field_a)]) - pf = storage.rd_pendingfields - assert len(pf) == 1 - assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) - is field_a) - assert rffi.cast(lltype.Signed, pf[0].num) == 1042 - assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 - assert rffi.cast(lltype.Signed, pf[0].itemindex) == -1 + descr=field_a)], []) + memo._add_pending_writes(optimizer, pendingwrites, numb_state) + assert numb_state.current == [1, 1042, 0, 1061, 0] + # array_a = FieldDescr() - storage = Storage() - modifier = ResumeDataVirtualAdder(None, storage, storage, None, None) + memo = ResumeDataLoopMemo(metainterp_sd) + numb_state = NumberingState() a42 = IntFrontendOp(0) a61 = IntFrontendOp(0) a62 = IntFrontendOp(0) a63 = IntFrontendOp(0) - modifier.liveboxes_from_env = {a42: rffi.cast(rffi.SHORT, 1042), - a61: rffi.cast(rffi.SHORT, 1061), - a62: rffi.cast(rffi.SHORT, 1062), - a63: rffi.cast(rffi.SHORT, 1063)} - modifier._add_pending_fields(FakeOptimizer(), [ + numb_state.liveboxes = {a42: 1042, a61: 1061, a62: 1062, a63: 1063} + pendingwrites = PendingWrites([], + [ ResOperation(rop.SETARRAYITEM_GC, [a42, ConstInt(0), a61], descr=array_a), - ResOperation(rop.SETARRAYITEM_GC, [a42, ConstInt(2147483647), a62], + ResOperation(rop.SETARRAYITEM_GC, [a42, ConstInt(2**21 - 1), a62], descr=array_a)]) - pf = storage.rd_pendingfields - assert len(pf) == 2 - assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[0].lldescr) - is array_a) - assert rffi.cast(lltype.Signed, pf[0].num) == 1042 - assert rffi.cast(lltype.Signed, pf[0].fieldnum) == 1061 - assert rffi.cast(lltype.Signed, pf[0].itemindex) == 0 - assert (annlowlevel.cast_base_ptr_to_instance(FieldDescr, pf[1].lldescr) - is array_a) - assert rffi.cast(lltype.Signed, pf[1].num) == 1042 - assert rffi.cast(lltype.Signed, pf[1].fieldnum) == 1062 - assert rffi.cast(lltype.Signed, pf[1].itemindex) == 2147483647 + memo._add_pending_writes(optimizer, pendingwrites, numb_state) + assert numb_state.current == [0, # no pending field writes + 2, # two pending array writes + 1042, 1, 0, 1061, # first write + 1042, 1, 2 ** 21 - 1, 1062 # second write + ] # - if sys.maxint >= 2147483648: - py.test.raises(TagOverflow, modifier._add_pending_fields, - FakeOptimizer(), - [ResOperation(rop.SETARRAYITEM_GC, - [a42, ConstInt(2147483648), a63], - descr=array_a)]) + + pendingwrites = PendingWrites([], + [ResOperation(rop.SETARRAYITEM_GC, + [a42, ConstInt(2147483648), a63], + descr=array_a)]) + with py.test.raises(TagOverflow): + memo._add_pending_writes(optimizer, pendingwrites, numb_state) + def test_resume_reader_fields_and_arrayitems(): + metainterp_sd = FakeMetaInterpStaticData() + metainterp_sd.all_descrs = [] + class ResumeReader(AbstractResumeDataReader): - def __init__(self, got=None, got_array=None): + def __init__(self, numb, got=None, got_array=None): + self.resumecodereader = Reader(numb) + self.metainterp_sd = metainterp_sd self.got = got self.got_array = got_array def setfield(self, struct, fieldnum, descr): assert lltype.typeOf(struct) is lltype.Signed - assert lltype.typeOf(fieldnum) is rffi.SHORT - fieldnum = rffi.cast(lltype.Signed, fieldnum) + assert lltype.typeOf(fieldnum) is lltype.Signed self.got.append((descr, struct, fieldnum)) def setarrayitem(self, array, index, fieldnum, arraydescr): assert lltype.typeOf(array) is lltype.Signed assert lltype.typeOf(index) is lltype.Signed - assert lltype.typeOf(fieldnum) is rffi.SHORT - fieldnum = rffi.cast(lltype.Signed, fieldnum) + assert lltype.typeOf(fieldnum) is lltype.Signed self.got_array.append((arraydescr, array, index, fieldnum)) def decode_ref(self, num): return rffi.cast(lltype.Signed, num) * 100 + numb = create_numbering([0, 0]) got = [] - pf = lltype.nullptr(PENDINGFIELDSP.TO) - ResumeReader(got)._prepare_pendingfields(pf) + ResumeReader(numb, got)._prepare_pendingfields() assert got == [] # class FieldDescr(AbstractDescr): - pass + def __init__(self): + self.descr_index = len(metainterp_sd.all_descrs) + metainterp_sd.all_descrs.append(self) field_a = FieldDescr() field_b = FieldDescr() - pf = lltype.malloc(PENDINGFIELDSP.TO, 2) - pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(field_a) - pf[0].num = rffi.cast(rffi.SHORT, 1042) - pf[0].fieldnum = rffi.cast(rffi.SHORT, 1061) - pf[0].itemindex = rffi.cast(rffi.INT, -1) - pf[1].lldescr = annlowlevel.cast_instance_to_base_ptr(field_b) - pf[1].num = rffi.cast(rffi.SHORT, 2042) - pf[1].fieldnum = rffi.cast(rffi.SHORT, 2061) - pf[1].itemindex = rffi.cast(rffi.INT, -1) + numb = create_numbering([2, # number writes + 1042, + field_a.descr_index, + 1061, + 2042, + field_b.descr_index, + 2061, + 0, # number array writes + ]) got = [] - ResumeReader(got)._prepare_pendingfields(pf) + ResumeReader(numb, got)._prepare_pendingfields() assert got == [(field_a, 104200, 1061), (field_b, 204200, 2061)] # array_a = FieldDescr() - pf = lltype.malloc(PENDINGFIELDSP.TO, 1) - pf[0].lldescr = annlowlevel.cast_instance_to_base_ptr(array_a) - pf[0].num = rffi.cast(rffi.SHORT, 1042) - pf[0].fieldnum = rffi.cast(rffi.SHORT, 1063) - pf[0].itemindex = rffi.cast(rffi.INT, 123) + numb = create_numbering([0, # number writes + 1, # number array writes + 1042, + array_a.descr_index, + 123, + 1063]) got_array = [] - ResumeReader(got_array=got_array)._prepare_pendingfields(pf) + ResumeReader(numb, got_array=got_array)._prepare_pendingfields() assert got_array == [(array_a, 104200, 123, 1063)] def test_invalidation_needed(): class options: failargs_limit = 10 - + metainterp_sd = FakeMetaInterpStaticData() metainterp_sd.options = options memo = ResumeDataLoopMemo(metainterp_sd) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit