def gen_initialize_tid(self, v_newgcobj, tid): if self.gc_ll_descr.fielddescr_tid is not None: # produce a SETFIELD to initialize the GC header op = ResOperation(rop.SETFIELD_GC, [v_newgcobj, ConstInt(tid)], None, descr=self.gc_ll_descr.fielddescr_tid) self.newops.append(op)
def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) original_intvars = builder.intvars[:] super(AbstractOvfOperation, self).produce_into(builder, r) if builder.fakemetainterp._got_exc: # overflow detected assert isinstance(builder.fakemetainterp._got_exc, OverflowError) op = ResOperation(rop.GUARD_OVERFLOW, [], None) # the overflowed result should not be used any more, but can # be used on the failure path: recompute fail_subset including # the result, and then remove it from builder.intvars. fail_subset = builder.subset_of_intvars(r) builder.intvars[:] = original_intvars else: op = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) op.setdescr(BasicFailDescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op)
def generate_modified_call(self, oopspecindex, args, result, mode): oopspecindex += mode.OS_offset cic = self.optimizer.metainterp_sd.callinfocollection calldescr, func = cic.callinfo_for_oopspec(oopspecindex) op = ResOperation(rop.CALL, [ConstInt(func)] + args, result, descr=calldescr) self.emit_operation(op)
def gen_write_barrier(self, v_base, v_value): write_barrier_descr = self.gc_ll_descr.write_barrier_descr args = [v_base, v_value] self.newops.append( ResOperation(rop.COND_CALL_GC_WB, args, None, descr=write_barrier_descr))
def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) original_intvars = builder.intvars[:] super(AbstractOvfOperation, self).produce_into(builder, r) if builder.cpu._overflow_flag: # overflow detected del builder.cpu._overflow_flag op = ResOperation(rop.GUARD_OVERFLOW, [], None) # the overflowed result should not be used any more, but can # be used on the failure path: recompute fail_subset including # the result, and then remove it from builder.intvars. fail_subset = builder.subset_of_intvars(r) builder.intvars[:] = original_intvars else: op = ResOperation(rop.GUARD_NO_OVERFLOW, [], None) op.descr = builder.make_fail_descr() op.fail_args = fail_subset builder.loop.operations.append(op)
def handle_str_equal_level1(self, v1, v2, resultbox, mode): l2box = v2.getstrlen(None, mode, None) if isinstance(l2box, ConstInt): if l2box.value == 0: lengthbox = v1.getstrlen(self, mode, None) seo = self.optimizer.send_extra_operation seo(ResOperation(rop.INT_EQ, [lengthbox, CONST_0], resultbox)) return True if l2box.value == 1: l1box = v1.getstrlen(None, mode, None) if isinstance(l1box, ConstInt) and l1box.value == 1: # comparing two single chars vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO, mode) vchar2 = self.strgetitem(v2, optimizer.CVAL_ZERO, mode) seo = self.optimizer.send_extra_operation seo( ResOperation( rop.INT_EQ, [vchar1.force_box(self), vchar2.force_box(self)], resultbox)) return True if isinstance(v1, VStringSliceValue): vchar = self.strgetitem(v2, optimizer.CVAL_ZERO, mode) do = EffectInfo.OS_STREQ_SLICE_CHAR self.generate_modified_call(do, [ v1.vstr.force_box(self), v1.vstart.force_box(self), v1.vlength.force_box(self), vchar.force_box(self) ], resultbox, mode) return True # if v2.is_null(): if v1.is_nonnull(): self.make_constant(resultbox, CONST_0) return True if v1.is_null(): self.make_constant(resultbox, CONST_1) return True op = ResOperation(rop.PTR_EQ, [v1.force_box(self), llhelper.CONST_NULL], resultbox) self.emit_operation(op) return True # return False
def gen_guard(self, builder, r): if not builder.ptrvars: raise CannotProduceOperation box = r.choice(builder.ptrvars)[0] op = ResOperation(self.opnum, [box], None) passing = ((self.opnum == rop.GUARD_NONNULL and box.value) or (self.opnum == rop.GUARD_ISNULL and not box.value)) return op, passing
def make_guards(self, box): guards = [] if self.level == LEVEL_CONSTANT: op = ResOperation(rop.GUARD_VALUE, [box, self.box], None) guards.append(op) elif self.level == LEVEL_KNOWNCLASS: op = ResOperation(rop.GUARD_NONNULL, [box], None) guards.append(op) op = ResOperation(rop.GUARD_CLASS, [box, self.known_class], None) guards.append(op) else: if self.level == LEVEL_NONNULL: op = ResOperation(rop.GUARD_NONNULL, [box], None) guards.append(op) self.intbound.make_guards(box, guards) if self.lenbound: lenbox = BoxInt() if self.lenbound.mode == MODE_ARRAY: op = ResOperation(rop.ARRAYLEN_GC, [box], lenbox, self.lenbound.descr) elif self.lenbound.mode == MODE_STR: op = ResOperation(rop.STRLEN, [box], lenbox, self.lenbound.descr) elif self.lenbound.mode == MODE_UNICODE: op = ResOperation(rop.UNICODELEN, [box], lenbox, self.lenbound.descr) else: debug_print("Unknown lenbound mode") assert False guards.append(op) self.lenbound.bound.make_guards(lenbox, guards) return guards
def do(self, opnum, argboxes, descr=None): self.fakemetainterp._got_exc = None v_result = execute_nonspec(self.cpu, self.fakemetainterp, opnum, argboxes, descr) if isinstance(v_result, Const): v_result = v_result.clonebox() self.loop.operations.append( ResOperation(opnum, argboxes, v_result, descr)) return v_result
def optimize_VIRTUAL_REF(self, op): indexbox = op.args[1] # # get some constants vrefinfo = self.metainterp_sd.virtualref_info c_cls = vrefinfo.jit_virtual_ref_const_class descr_virtual_token = vrefinfo.descr_virtual_token descr_virtualref_index = vrefinfo.descr_virtualref_index # # Replace the VIRTUAL_REF operation with a virtual structure of type # 'jit_virtual_ref'. The jit_virtual_ref structure may be forced soon, # but the point is that doing so does not force the original structure. op = ResOperation(rop.NEW_WITH_VTABLE, [c_cls], op.result) vrefvalue = self.make_virtual(c_cls, op.result, op) tokenbox = BoxInt() self.emit_operation(ResOperation(rop.FORCE_TOKEN, [], tokenbox)) vrefvalue.setfield(descr_virtual_token, self.getvalue(tokenbox)) vrefvalue.setfield(descr_virtualref_index, self.getvalue(indexbox))
def _int_sub(string_optimizer, box1, box2): if isinstance(box2, ConstInt): if box2.value == 0: return box1 if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) resbox = BoxInt() string_optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) return resbox
def _optimize_oois_ooisnot(self, op, expect_isnot, unary_opnum): value0 = self.getvalue(op.args[0]) value1 = self.getvalue(op.args[1]) if value0.is_virtual(): if value1.is_virtual(): intres = (value0 is value1) ^ expect_isnot self.make_constant_int(op.result, intres) else: self.make_constant_int(op.result, expect_isnot) elif value1.is_virtual(): self.make_constant_int(op.result, expect_isnot) elif value1.is_null(): op = ResOperation(unary_opnum, [op.args[0]], op.result) self._optimize_nullness(op, expect_isnot, self.cpu.ts.CONST_NULL) elif value0.is_null(): op = ResOperation(unary_opnum, [op.args[1]], op.result) self._optimize_nullness(op, expect_isnot, self.cpu.ts.CONST_NULL) else: self.optimize_default(op)
def optimize_NEW_ARRAY(self, op): sizebox = self.get_constant_box(op.args[0]) if sizebox is not None: # if the original 'op' did not have a ConstInt as argument, # build a new one with the ConstInt argument if not isinstance(op.args[0], ConstInt): op = ResOperation(rop.NEW_ARRAY, [sizebox], op.result, descr=op.descr) self.make_varray(op.descr, sizebox.getint(), op.result, op) else: self.optimize_default(op)
def optimize_NEW_ARRAY(self, op): sizebox = self.get_constant_box(op.getarg(0)) if sizebox is not None: # if the original 'op' did not have a ConstInt as argument, # build a new one with the ConstInt argument if not isinstance(op.getarg(0), ConstInt): op = ResOperation(rop.NEW_ARRAY, [sizebox], op.result, descr=op.getdescr()) self.make_varray(op.getdescr(), sizebox.getint(), op.result, op) else: self.getvalue(op.result).ensure_nonnull() self.emit_operation(op)
def prepare_last_operation(new_loop, target_loop_token): op = new_loop.operations[-1] if not isinstance(target_loop_token, TerminatingLoopToken): # normal case op.descr = target_loop_token # patch the jump target else: # The target_loop_token is a pseudo loop token, # e.g. loop_tokens_done_with_this_frame_void[0] # Replace the operation with the real operation we want, i.e. a FINISH descr = target_loop_token.finishdescr new_op = ResOperation(rop.FINISH, op.args, None, descr=descr) new_loop.operations[-1] = new_op
def optimize_VIRTUAL_REF_FINISH(self, op): # Set the 'forced' field of the virtual_ref. # In good cases, this is all virtual, so has no effect. # Otherwise, this forces the real object -- but only now, as # opposed to much earlier. This is important because the object is # typically a PyPy PyFrame, and now is the end of its execution, so # forcing it now does not have catastrophic effects. vrefinfo = self.metainterp_sd.virtualref_info # op.args[1] should really never point to null here # - set 'forced' to point to the real object op1 = ResOperation(rop.SETFIELD_GC, op.args, None, descr=vrefinfo.descr_forced) self.optimize_SETFIELD_GC(op1) # - set 'virtual_token' to TOKEN_NONE args = [op.args[0], ConstInt(vrefinfo.TOKEN_NONE)] op1 = ResOperation(rop.SETFIELD_GC, args, None, descr=vrefinfo.descr_virtual_token) self.optimize_SETFIELD_GC(op1)
def _strgetitem(string_optimizer, strbox, indexbox, mode, resbox=None): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): if mode is mode_string: s = strbox.getref(lltype.Ptr(rstr.STR)) return ConstInt(ord(s.chars[indexbox.getint()])) else: s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) if resbox is None: resbox = BoxInt() string_optimizer.emit_operation( ResOperation(mode.STRGETITEM, [strbox, indexbox], resbox)) return resbox
def parse_result_op(self, line): res, op = line.split("=", 1) res = res.strip() op = op.strip() opnum, args, descr, fail_args = self.parse_op(op) if res in self.vars: raise ParseError("Double assign to var %s in line: %s" % (res, line)) rvar = self.box_for_var(res) self.vars[res] = rvar res = ResOperation(opnum, args, rvar, descr) res.fail_args = fail_args return res
def _optimize_NEWSTR(self, op, mode): length_box = self.get_constant_box(op.getarg(0)) if length_box: # if the original 'op' did not have a ConstInt as argument, # build a new one with the ConstInt argument if not isinstance(op.getarg(0), ConstInt): op = ResOperation(mode.NEWSTR, [length_box], op.result) vvalue = self.make_vstring_plain(op.result, op, mode) vvalue.setup(length_box.getint()) else: self.getvalue(op.result).ensure_nonnull() self.emit_operation(op) self.pure(mode.STRLEN, [op.result], op.getarg(0))
def _int_add(string_optimizer, box1, box2): if isinstance(box1, ConstInt): if box1.value == 0: return box2 if isinstance(box2, ConstInt): return ConstInt(box1.value + box2.value) elif isinstance(box2, ConstInt) and box2.value == 0: return box1 if string_optimizer is None: return None resbox = BoxInt() string_optimizer.emit_operation(ResOperation(rop.INT_ADD, [box1, box2], resbox)) return resbox
def insert_label(self, loop, position, r): assert not hasattr(loop, '_targettoken') for i in range(position): op = loop.operations[i] if (not op.has_no_side_effect() or not isinstance(op.result, (BoxInt, BoxFloat))): position = i break # cannot move the LABEL later randompos = r.randrange(0, len(self.startvars) + 1) self.startvars.insert(randompos, op.result) loop._targettoken = TargetToken() loop.operations.insert( position, ResOperation(rop.LABEL, self.startvars, None, loop._targettoken))
def initialize_forced_string(self, string_optimizer, targetbox, offsetbox, mode): for i in range(len(self._chars)): assert isinstance(targetbox, BoxPtr) # ConstPtr never makes sense charvalue = self.getitem(i) if charvalue is not None: charbox = charvalue.force_box(string_optimizer) if not (isinstance(charbox, Const) and charbox.same_constant(CONST_0)): op = ResOperation(mode.STRSETITEM, [targetbox, offsetbox, charbox], None) string_optimizer.emit_operation(op) offsetbox = _int_add(string_optimizer, offsetbox, CONST_1) return offsetbox
def gen_guard(self, builder, r): v = r.choice(builder.intvars) if r.random() > 0.8: other = r.choice(builder.intvars) else: if r.random() < 0.75: value = v.value elif r.random() < 0.5: value = v.value ^ 1 else: value = r.random_integer() other = ConstInt(value) op = ResOperation(self.opnum, [v, other], None) return op, (v.value == other.value)
def _really_force(self): assert self.source_op is not None newoperations = self.optimizer.newoperations newoperations.append(self.source_op) self.box = box = self.source_op.result for index in range(len(self._items)): subvalue = self._items[index] if subvalue is not self.constvalue: subbox = subvalue.force_box() op = ResOperation(rop.SETARRAYITEM_GC, [box, ConstInt(index), subbox], None, descr=self.arraydescr) newoperations.append(op)
def _really_force(self): assert self.source_op is not None newoperations = self.optimizer.newoperations newoperations.append(self.source_op) self.box = box = self.source_op.result # iteritems = self._fields.iteritems() if not we_are_translated(): #random order is fine, except for tests iteritems = list(iteritems) iteritems.sort(key=lambda (x, y): x.sort_key()) for ofs, value in iteritems: subbox = value.force_box() op = ResOperation(rop.SETFIELD_GC, [box, subbox], None, descr=ofs) newoperations.append(op) self._fields = None
def test_remove_consts_and_duplicates(): class FakeStaticData: cpu = None warmrunnerdesc = None def is_another_box_like(box, referencebox): assert box is not referencebox assert isinstance(box, referencebox.clonebox().__class__) assert box.value == referencebox.value return True metainterp = pyjitpl.MetaInterp(FakeStaticData(), None) metainterp.history = History() b1 = BoxInt(1) b2 = BoxInt(2) c3 = ConstInt(3) boxes = [b1, b2, b1, c3] dup = {} metainterp.remove_consts_and_duplicates(boxes, 4, dup) assert boxes[0] is b1 assert boxes[1] is b2 assert is_another_box_like(boxes[2], b1) assert is_another_box_like(boxes[3], c3) assert equaloplists(metainterp.history.operations, [ ResOperation(rop.SAME_AS, [b1], boxes[2]), ResOperation(rop.SAME_AS, [c3], boxes[3]), ]) assert dup == {b1: None, b2: None} # del metainterp.history.operations[:] b4 = BoxInt(4) boxes = [b2, b4, "something random"] metainterp.remove_consts_and_duplicates(boxes, 2, dup) assert is_another_box_like(boxes[0], b2) assert boxes[1] is b4 assert equaloplists(metainterp.history.operations, [ ResOperation(rop.SAME_AS, [b2], boxes[0]), ])
def gen_guard(self, builder, r): ptrvars = [(v, S) for (v, S) in builder.ptrvars if isinstance(S, lltype.Struct) and S._names[0] == 'parent'] if not ptrvars: raise test_random.CannotProduceOperation v, S = r.choice(ptrvars) if r.random() < 0.3: v2, S2 = v, S else: v2, S2 = builder.get_structptr_var(r, must_have_vtable=True) vtable = S._hints['vtable']._as_ptr() vtable2 = S2._hints['vtable']._as_ptr() c_vtable2 = ConstAddr(llmemory.cast_ptr_to_adr(vtable2), builder.cpu) op = ResOperation(self.opnum, [v, c_vtable2], None) return op, (vtable == vtable2)
def produce_into(self, builder, r): fail_subset = builder.subset_of_intvars(r) subset, f, exc = self.raising_func_code(builder, r) TP = lltype.FuncType([lltype.Signed] * len(subset), lltype.Void) ptr = llhelper(lltype.Ptr(TP), f) c_addr = ConstAddr(llmemory.cast_ptr_to_adr(ptr), builder.cpu) args = [c_addr] + subset descr = self.getcalldescr(builder, TP) self.put(builder, args, descr) exc_box = ConstAddr(llmemory.cast_ptr_to_adr(exc), builder.cpu) op = ResOperation(rop.GUARD_EXCEPTION, [exc_box], BoxPtr(), descr=BasicFailDescr()) op.setfailargs(fail_subset) builder.loop.operations.append(op)
def runjitcelltoken(self): if self.startvars == self.loop.inputargs: return self.loop._jitcelltoken if not hasattr(self, '_initialjumploop_celltoken'): self._initialjumploop_celltoken = JitCellToken() args = [] for box in self.startvars: if box not in self.loop.inputargs: box = box.constbox() args.append(box) self.cpu.compile_loop(self.loop.inputargs, [ ResOperation( rop.JUMP, args, None, descr=self.loop._targettoken) ], self._initialjumploop_celltoken) return self._initialjumploop_celltoken
def _get_loop_for_call(self, argnum, calldescr): loop = calldescr._generated_mp if loop is None: args = [BoxInt() for i in range(argnum + 1)] if calldescr.res_index < 0: result = None elif calldescr.res_index == self.SIZE_GCPTR: result = BoxPtr(lltype.nullptr(llmemory.GCREF.TO)) else: result = BoxInt(0) result_list = [] if result is not None: result_list.append(result) operations = [ ResOperation(rop.CALL, args, result, calldescr), ResOperation(rop.GUARD_NO_EXCEPTION, [], None), ResOperation(rop.FAIL, result_list, None)] operations[1].suboperations = [ResOperation(rop.FAIL, [], None)] loop = history.TreeLoop('call') loop.inputargs = args loop.operations = operations self.compile_operations(loop) calldescr._generated_mp = loop return loop