def test_simple_read(): b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()] c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] storage = Storage() storage.rd_consts = [c1, c2, c3] numb = Numbering(None, [tag(0, TAGBOX), tag(1, TAGBOX), tag(2, TAGBOX)]) numb = Numbering(numb, [tag(1, TAGCONST), tag(2, TAGCONST)]) numb = Numbering(numb, [ tag(0, TAGBOX), tag(0, TAGCONST), NULLREF, tag(0, TAGBOX), tag(1, TAGBOX) ]) storage.rd_numb = numb storage.rd_virtuals = None b1s, b2s, b3s = [BoxInt(), BoxPtr(), BoxInt()] assert b1s != b3s reader = ResumeDataReader(storage, [b1s, b2s, b3s], MyMetaInterp()) lst = reader.consume_boxes() assert lst == [b1s, ConstInt(1), LLtypeMixin.cpu.ts.CONST_NULL, b1s, b2s] lst = reader.consume_boxes() assert lst == [ConstInt(2), ConstInt(3)] lst = reader.consume_boxes() assert lst == [b1s, b2s, b3s]
def get_token_for_call(self, cpu): if self.loop_token is not None: return self.loop_token args = [BoxInt()] + self.instantiate_arg_classes() if self.get_result_size(cpu.translate_support_code) == 0: result = None result_list = [] else: if self.returns_a_pointer(): result = BoxPtr() elif self.returns_a_float(): result = BoxFloat() else: result = BoxInt() result_list = [result] operations = [ ResOperation(rop.CALL, args[:], result, self), ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=BasicFailDescr()), ResOperation(rop.FINISH, result_list, None, descr=BasicFailDescr()) ] operations[1].fail_args = [] loop_token = LoopToken() # note: the 'args' that we pass below is not the same object as the # 'args[:]' that was passed above to ResOperation, because we want # the argument to ResOperation to be non-resizable, but the argument # to compile_loop to be resizable. cpu.compile_loop(args, operations, loop_token) self.loop_token = loop_token return loop_token
def test_rebuild_from_resumedata_with_virtualizable(): b1, b2, b3, b4 = [BoxInt(), BoxPtr(), BoxInt(), BoxPtr()] c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)] storage = Storage() fs = [ FakeFrame("code0", 0, -1, b1, c1, b2), FakeFrame("code1", 3, 7, b3, c2, b1), FakeFrame("code2", 9, -1, c3, b2) ] capture_resumedata(fs, [b4], storage) memo = ResumeDataLoopMemo(LLtypeMixin.cpu) modifier = ResumeDataVirtualAdder(storage, memo) liveboxes = modifier.finish({}) metainterp = MyMetaInterp() b1t, b2t, b3t, b4t = [BoxInt(), BoxPtr(), BoxInt(), BoxPtr()] newboxes = _resume_remap(liveboxes, [b1, b2, b3, b4], b1t, b2t, b3t, b4t) result = rebuild_from_resumedata(metainterp, newboxes, storage, True) assert result == [b4t] fs2 = [ FakeFrame("code0", 0, -1, b1t, c1, b2t), FakeFrame("code1", 3, 7, b3t, c2, b1t), FakeFrame("code2", 9, -1, c3, b2t) ] assert metainterp.framestack == fs2
def test_ResumeDataLoopMemo_number_boxes(): memo = ResumeDataLoopMemo(FakeMetaInterpStaticData()) b1, b2 = [BoxInt(), BoxInt()] assert memo.num_cached_boxes() == 0 boxes = [] num = memo.assign_number_to_box(b1, boxes) assert num == -1 assert boxes == [b1] assert memo.num_cached_boxes() == 1 boxes = [None] num = memo.assign_number_to_box(b1, boxes) assert num == -1 assert boxes == [b1] num = memo.assign_number_to_box(b2, boxes) assert num == -2 assert boxes == [b1, b2] assert memo.num_cached_boxes() == 2 boxes = [None, None] num = memo.assign_number_to_box(b2, boxes) assert num == -2 assert boxes == [None, b2] num = memo.assign_number_to_box(b1, boxes) assert num == -1 assert boxes == [b1, b2] memo.clear_box_virtual_numbers() assert memo.num_cached_boxes() == 0
def test_rebuild_from_resumedata_two_guards_w_shared_virtuals(): b1, b2, b3, b4, b5, b6 = [BoxPtr(), BoxPtr(), BoxInt(), BoxPtr(), BoxInt(), BoxInt()] c1, c2, c3, c4 = [ConstInt(1), ConstInt(2), ConstInt(3), LLtypeMixin.nodebox.constbox()] storage = Storage() fs = [FakeFrame("code0", 0, -1, c1, b2, b3)] capture_resumedata(fs, None, [], storage) memo = ResumeDataLoopMemo(FakeMetaInterpStaticData()) values = {b2: virtual_value(b2, b5, c4)} modifier = ResumeDataVirtualAdder(storage, memo) liveboxes = modifier.finish(values) assert len(storage.rd_virtuals) == 1 assert storage.rd_virtuals[0].fieldnums == [tag(-1, TAGBOX), tag(0, TAGCONST)] storage2 = Storage() fs = [FakeFrame("code0", 0, -1, b1, b4, b2)] capture_resumedata(fs, None, [], storage2) values[b4] = virtual_value(b4, b6, c4) modifier = ResumeDataVirtualAdder(storage2, memo) liveboxes = modifier.finish(values) assert len(storage2.rd_virtuals) == 2 assert storage2.rd_virtuals[1].fieldnums == storage.rd_virtuals[0].fieldnums assert storage2.rd_virtuals[1] is storage.rd_virtuals[0]
def __init__(self, cpu, cliloop): self.setoptions() self.cpu = cpu self.name = cliloop.get_fresh_cli_name() self.cliloop = cliloop self.boxes = {} # box --> local var self.branches = [] self.branchlabels = [] self.consts = {} # object --> index self.meth_wrapper = self._get_meth_wrapper() self.il = self.meth_wrapper.get_il_generator() self.av_consts = MethodArgument(0, System.Type.GetType("System.Object[]")) t_InputArgs = dotnet.typeof(InputArgs) self.av_inputargs = MethodArgument(1, t_InputArgs) self.av_ovf_flag = BoxInt() self.exc_value_field = t_InputArgs.GetField('exc_value') if cpu.rtyper: self.av_OverflowError = ConstObj( ootype.cast_to_object(cpu.ll_ovf_exc)) self.av_ZeroDivisionError = ConstObj( ootype.cast_to_object(cpu.ll_zero_exc)) else: self.av_OverflowError = None self.av_ZeroDivisionError = None self.box2type = {}
def test_execute_nonspec(): cpu = FakeCPU() descr = FakeDescr() # cases with a descr # arity == -1 argboxes = [BoxInt(321), ConstInt(123)] box = execute_nonspec(cpu, rop.CALL, argboxes, descr) assert box.args == ('call', argboxes, descr) # arity == 0 box = execute_nonspec(cpu, rop.NEW, [], descr) assert box.args == ('new', descr) # arity == 1 box1 = BoxInt(515) box = execute_nonspec(cpu, rop.ARRAYLEN_GC, [box1], descr) assert box.args == ('arraylen_gc', box1, descr) # arity == 2 box2 = BoxInt(222) box = execute_nonspec(cpu, rop.SETFIELD_GC, [box1, box2], descr) assert box.args == ('setfield_gc', box1, box2, descr) # arity == 3 box3 = BoxInt(-33) box = execute_nonspec(cpu, rop.SETARRAYITEM_GC, [box1, box2, box3], descr) assert box.args == ('setarrayitem_gc', box1, box2, box3, descr) # cases without descr # arity == 1 box = execute_nonspec(cpu, rop.INT_INVERT, [box1]) assert box.value == ~515 # arity == 2 box = execute_nonspec(cpu, rop.INT_LSHIFT, [box1, BoxInt(3)]) assert box.value == 515 << 3 # arity == 3 box = execute_nonspec(cpu, rop.STRSETITEM, [box1, box2, box3]) assert box.args == ('strsetitem', box1, box2, box3)
def test__make_virtual(): b1, b2 = BoxInt(), BoxInt() vbox = BoxPtr() modifier = ResumeDataVirtualAdder(None, None) modifier.liveboxes_from_env = {} modifier.liveboxes = {} modifier.virtuals = [] modifier.vfieldboxes = [] modifier.make_virtual(vbox, None, ['a', 'b'], [b1, b2]) assert modifier.liveboxes == { vbox: tag(0, TAGVIRTUAL), b1: UNASSIGNED, b2: UNASSIGNED } assert len(modifier.virtuals) == 1 assert modifier.vfieldboxes == [[b1, b2]] modifier = ResumeDataVirtualAdder(None, None) modifier.liveboxes_from_env = {vbox: tag(0, TAGVIRTUAL)} modifier.liveboxes = {} modifier.virtuals = [None] modifier.vfieldboxes = [None] modifier.make_virtual(vbox, None, ['a', 'b', 'c'], [b1, b2, vbox]) assert modifier.liveboxes == { b1: UNASSIGNED, b2: UNASSIGNED, vbox: tag(0, TAGVIRTUAL) } assert len(modifier.virtuals) == 1 assert modifier.vfieldboxes == [[b1, b2, vbox]]
def test_overflow_mc(self): from pypy.jit.backend.x86.assembler import MachineCodeBlockWrapper orig_size = MachineCodeBlockWrapper.MC_SIZE MachineCodeBlockWrapper.MC_SIZE = 1024 old_mc = self.cpu.assembler.mc old_mc2 = self.cpu.assembler.mc2 self.cpu.assembler.mc = None try: ops = [] base_v = BoxInt() v = base_v for i in range(1024): next_v = BoxInt() ops.append(ResOperation(rop.INT_ADD, [v, ConstInt(1)], next_v)) v = next_v ops.append( ResOperation(rop.FINISH, [v], None, descr=BasicFailDescr())) looptoken = LoopToken() self.cpu.compile_loop([base_v], ops, looptoken) assert self.cpu.assembler.mc != old_mc # overflowed self.cpu.set_future_value_int(0, base_v.value) self.cpu.execute_token(looptoken) assert self.cpu.get_latest_value_int(0) == 1024 finally: MachineCodeBlockWrapper.MC_SIZE = orig_size self.cpu.assembler.mc = old_mc self.cpu.assembler.mc2 = old_mc2
def test_ops_offset(self): from pypy.rlib import debug i0 = BoxInt() i1 = BoxInt() i2 = BoxInt() looptoken = JitCellToken() targettoken = TargetToken() operations = [ ResOperation(rop.LABEL, [i0], None, descr=targettoken), ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1), ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2), ResOperation(rop.JUMP, [i1], None, descr=targettoken), ] inputargs = [i0] debug._log = dlog = debug.DebugLog() info = self.cpu.compile_loop(inputargs, operations, looptoken) ops_offset = info.ops_offset debug._log = None # assert ops_offset is looptoken._x86_ops_offset # 2*(getfield_raw/int_add/setfield_raw) + ops + None assert len(ops_offset) == 2*3 + len(operations) + 1 assert (ops_offset[operations[0]] <= ops_offset[operations[1]] <= ops_offset[operations[2]] <= ops_offset[None])
def box_for_var(self, elem): try: return self._cache[self.type_system, elem] except KeyError: pass if elem.startswith('i'): # integer box = BoxInt() _box_counter_more_than(elem[1:]) elif elem.startswith('f'): box = BoxFloat() _box_counter_more_than(elem[1:]) elif elem.startswith('p'): # pointer ts = getattr(self.cpu, 'ts', llhelper) box = ts.BoxRef() _box_counter_more_than(elem[1:]) else: for prefix, boxclass in self.boxkinds.iteritems(): if elem.startswith(prefix): box = boxclass() break else: raise ParseError("Unknown variable type: %s" % elem) self._cache[self.type_system, elem] = box box._str = elem return box
def get_token_for_call(self, cpu): if self.loop_token is not None: return self.loop_token args = [BoxInt()] + self.instantiate_arg_classes() if self.get_result_size(cpu.translate_support_code) == 0: result = None result_list = [] else: if self.returns_a_pointer(): result = BoxPtr() elif self.returns_a_float(): result = BoxFloat() else: result = BoxInt() result_list = [result] operations = [ ResOperation(rop.CALL, args, result, self), ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=BasicFailDescr()), ResOperation(rop.FINISH, result_list, None, descr=BasicFailDescr())] operations[1].fail_args = [] loop_token = LoopToken() cpu.compile_loop(args, operations, loop_token) self.loop_token = loop_token return loop_token
def test_unwrap(): S = lltype.GcStruct('S') p = lltype.malloc(S) po = lltype.cast_opaque_ptr(llmemory.GCREF, p) assert unwrap(lltype.Void, BoxInt(42)) is None assert unwrap(lltype.Signed, BoxInt(42)) == 42 assert unwrap(lltype.Char, BoxInt(42)) == chr(42) assert unwrap(lltype.Float, BoxFloat(42.5)) == 42.5 assert unwrap(lltype.Ptr(S), BoxPtr(po)) == p
def test_call_with_singlefloats(self): cpu = self.cpu if not cpu.supports_floats or not cpu.supports_singlefloats: py.test.skip('requires floats and singlefloats') import random from pypy.rlib.libffi import types from pypy.rlib.rarithmetic import r_singlefloat def func(*args): res = 0.0 for i, x in enumerate(args): res += (i + 1.1) * float(x) return res F = lltype.Float S = lltype.SingleFloat I = lltype.Signed floats = [random.random() - 0.5 for i in range(8)] singlefloats = [r_singlefloat(random.random() - 0.5) for i in range(8)] ints = [random.randrange(-99, 99) for i in range(8)] for repeat in range(100): args = [] argvalues = [] argslist = [] local_floats = list(floats) local_singlefloats = list(singlefloats) local_ints = list(ints) for i in range(8): case = random.randrange(0, 3) if case == 0: args.append(F) arg = local_floats.pop() argslist.append(boxfloat(arg)) elif case == 1: args.append(S) arg = local_singlefloats.pop() argslist.append(BoxInt(longlong.singlefloat2int(arg))) else: args.append(I) arg = local_ints.pop() argslist.append(BoxInt(arg)) argvalues.append(arg) FUNC = self.FuncType(args, F) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo.MOST_GENERAL) funcbox = self.get_funcbox(cpu, func_ptr) res = self.execute_operation(rop.CALL, [funcbox] + argslist, 'float', descr=calldescr) expected = func(*argvalues) assert abs(res.getfloat() - expected) < 0.0001
def test_allocations(self): from pypy.rpython.lltypesystem import rstr allocs = [None] all = [] def f(size): allocs.insert(0, size) buf = ctypes.create_string_buffer(size) all.append(buf) return ctypes.cast(buf, ctypes.c_void_p).value func = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)(f) addr = ctypes.cast(func, ctypes.c_void_p).value try: saved_addr = self.cpu.assembler.malloc_func_addr self.cpu.assembler.malloc_func_addr = addr ofs = symbolic.get_field_token(rstr.STR, 'chars', False)[0] res = self.execute_operation(rop.NEWSTR, [ConstInt(7)], 'ref') assert allocs[0] == 7 + ofs + WORD resbuf = self._resbuf(res) assert resbuf[ofs / WORD] == 7 # ------------------------------------------------------------ res = self.execute_operation(rop.NEWSTR, [BoxInt(7)], 'ref') assert allocs[0] == 7 + ofs + WORD resbuf = self._resbuf(res) assert resbuf[ofs / WORD] == 7 # ------------------------------------------------------------ TP = lltype.GcArray(lltype.Signed) ofs = symbolic.get_field_token(TP, 'length', False)[0] descr = self.cpu.arraydescrof(TP) res = self.execute_operation(rop.NEW_ARRAY, [ConstInt(10)], 'ref', descr) assert allocs[0] == 10 * WORD + ofs + WORD resbuf = self._resbuf(res) assert resbuf[ofs / WORD] == 10 # ------------------------------------------------------------ res = self.execute_operation(rop.NEW_ARRAY, [BoxInt(10)], 'ref', descr) assert allocs[0] == 10 * WORD + ofs + WORD resbuf = self._resbuf(res) assert resbuf[ofs / WORD] == 10 finally: self.cpu.assembler.malloc_func_addr = saved_addr
def test_execute_varargs(): cpu = FakeCPU() descr = FakeCallDescr() argboxes = [BoxInt(99999), BoxInt(321), constfloat(2.25), ConstInt(123), BoxPtr(), boxfloat(5.5)] box = execute_varargs(cpu, FakeMetaInterp(), rop.CALL, argboxes, descr) assert box.getfloat() == 42.5 assert cpu.fakecalled == (99999, descr, [321, 123], [ConstPtr.value], [longlong.getfloatstorage(2.25), longlong.getfloatstorage(5.5)])
def get_int_tests(): for opnum, args, retvalue in (list(_int_binary_operations()) + list(_int_comparison_operations()) + list(_int_unary_operations())): yield opnum, [BoxInt(x) for x in args], retvalue if len(args) > 1: assert len(args) == 2 yield opnum, [BoxInt(args[0]), ConstInt(args[1])], retvalue yield opnum, [ConstInt(args[0]), BoxInt(args[1])], retvalue if args[0] == args[1]: commonbox = BoxInt(args[0]) yield opnum, [commonbox, commonbox], retvalue
def compile_tmp_callback(cpu, jitdriver_sd, greenboxes, redargtypes, memory_manager=None): """Make a LoopToken that corresponds to assembler code that just calls back the interpreter. Used temporarily: a fully compiled version of the code may end up replacing it. """ jitcell_token = make_jitcell_token(jitdriver_sd) nb_red_args = jitdriver_sd.num_red_args assert len(redargtypes) == nb_red_args inputargs = [] for kind in redargtypes: if kind == history.INT: box = BoxInt() elif kind == history.REF: box = BoxPtr() elif kind == history.FLOAT: box = BoxFloat() else: raise AssertionError inputargs.append(box) k = jitdriver_sd.portal_runner_adr funcbox = history.ConstInt(heaptracker.adr2int(k)) callargs = [funcbox] + greenboxes + inputargs # result_type = jitdriver_sd.result_type if result_type == history.INT: result = BoxInt() elif result_type == history.REF: result = BoxPtr() elif result_type == history.FLOAT: result = BoxFloat() elif result_type == history.VOID: result = None else: assert 0, "bad result_type" if result is not None: finishargs = [result] else: finishargs = [] # jd = jitdriver_sd faildescr = PropagateExceptionDescr() operations = [ ResOperation(rop.CALL, callargs, result, descr=jd.portal_calldescr), ResOperation(rop.GUARD_NO_EXCEPTION, [], None, descr=faildescr), ResOperation(rop.FINISH, finishargs, None, descr=jd.portal_finishtoken) ] operations[1].setfailargs([]) operations = get_deep_immutable_oplist(operations) cpu.compile_loop(inputargs, operations, jitcell_token, log=False) if memory_manager is not None: # for tests memory_manager.keep_loop_alive(jitcell_token) return jitcell_token
def test_stringitems(self): from pypy.rpython.lltypesystem.rstr import STR ofs = symbolic.get_field_token(STR, 'chars', False)[0] ofs_items = symbolic.get_field_token(STR.chars, 'items', False)[0] res = self.execute_operation(rop.NEWSTR, [ConstInt(10)], 'ref') self.execute_operation(rop.STRSETITEM, [res, ConstInt(2), ConstInt(ord('d'))], 'void') resbuf = self._resbuf(res, ctypes.c_char) assert resbuf[ofs + ofs_items + 2] == 'd' self.execute_operation(rop.STRSETITEM, [res, BoxInt(2), ConstInt(ord('z'))], 'void') assert resbuf[ofs + ofs_items + 2] == 'z' r = self.execute_operation(rop.STRGETITEM, [res, BoxInt(2)], 'int') assert r.value == ord('z')
def handle_fail(self, metainterp_sd): if self.no == 0: raise metainterp_sd.warmrunnerdesc.DoneWithThisFrameInt(3) if self.no == 1: raise metainterp_sd.warmrunnerdesc.ContinueRunningNormally( [BoxInt(0), BoxInt(1)]) if self.no == 3: exc = lltype.malloc(OBJECT) exc.typeptr = exc_vtable raise metainterp_sd.warmrunnerdesc.ExitFrameWithExceptionRef( metainterp_sd.cpu, lltype.cast_opaque_ptr(llmemory.GCREF, exc)) return self.no
def test_virtual_adder_make_varray(): b2s, b4s = [BoxPtr(), BoxInt(4)] c1s = ConstInt(111) storage = Storage() memo = ResumeDataLoopMemo(FakeMetaInterpStaticData()) modifier = ResumeDataVirtualAdder(storage, memo) modifier.liveboxes_from_env = {} modifier.liveboxes = {} modifier.vfieldboxes = {} class FakeOptimizer(object): class cpu: pass def new_const_item(self, descr): return None v2 = VArrayValue(FakeOptimizer(), LLtypeMixin.arraydescr, 2, b2s) v2._items = [b4s, c1s] modifier.register_virtual_fields(b2s, [b4s, c1s]) liveboxes = [] values = {b2s: v2} modifier._number_virtuals(liveboxes, values, 0) dump_storage(storage, liveboxes) storage.rd_consts = memo.consts[:] storage.rd_numb = None # resume b1t, b3t, b4t = [BoxInt(11), BoxInt(33), BoxInt(44)] newboxes = _resume_remap(liveboxes, [#b2s -- virtual b4s], b4t) # resume metainterp = MyMetaInterp() reader = ResumeDataReader(storage, newboxes, metainterp) assert len(reader.virtuals) == 1 b2t = reader._decode_box(tag(0, TAGVIRTUAL)) trace = metainterp.trace expected = [ (rop.NEW_ARRAY, [ConstInt(2)], b2t, LLtypeMixin.arraydescr), (rop.SETARRAYITEM_GC, [b2t,ConstInt(0), b4t],None, LLtypeMixin.arraydescr), (rop.SETARRAYITEM_GC, [b2t,ConstInt(1), c1s], None, LLtypeMixin.arraydescr), ] for x, y in zip(expected, trace): assert x == y # ptr = b2t.value._obj.container._as_ptr() assert lltype.typeOf(ptr) == lltype.Ptr(lltype.GcArray(lltype.Signed)) assert len(ptr) == 2 assert ptr[0] == 44 assert ptr[1] == 111
def make_guards(self, box, guards): if self.has_lower and self.lower > MININT: bound = self.lower res = BoxInt() op = ResOperation(rop.INT_GE, [box, ConstInt(bound)], res) guards.append(op) op = ResOperation(rop.GUARD_TRUE, [res], None) guards.append(op) if self.has_upper and self.upper < MAXINT: bound = self.upper res = BoxInt() op = ResOperation(rop.INT_LE, [box, ConstInt(bound)], res) guards.append(op) op = ResOperation(rop.GUARD_TRUE, [res], None) guards.append(op)
def test_getfield_setfield(self): TP = lltype.GcStruct('x', ('s', lltype.Signed), ('i', rffi.INT), ('f', lltype.Float), ('u', rffi.USHORT), ('c1', lltype.Char), ('c2', lltype.Char), ('c3', lltype.Char)) res = self.execute_operation(rop.NEW, [], 'ref', self.cpu.sizeof(TP)) ofs_s = self.cpu.fielddescrof(TP, 's') ofs_i = self.cpu.fielddescrof(TP, 'i') #ofs_f = self.cpu.fielddescrof(TP, 'f') ofs_u = self.cpu.fielddescrof(TP, 'u') ofsc1 = self.cpu.fielddescrof(TP, 'c1') ofsc2 = self.cpu.fielddescrof(TP, 'c2') ofsc3 = self.cpu.fielddescrof(TP, 'c3') self.execute_operation(rop.SETFIELD_GC, [res, ConstInt(3)], 'void', ofs_s) # XXX ConstFloat #self.execute_operation(rop.SETFIELD_GC, [res, ofs_f, 1e100], 'void') # XXX we don't support shorts (at all) #self.execute_operation(rop.SETFIELD_GC, [res, ofs_u, ConstInt(5)], 'void') s = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofs_s) assert s.value == 3 self.execute_operation(rop.SETFIELD_GC, [res, BoxInt(3)], 'void', ofs_s) s = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofs_s) assert s.value == 3 self.execute_operation(rop.SETFIELD_GC, [res, BoxInt(1234)], 'void', ofs_i) i = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofs_i) assert i.value == 1234 #u = self.execute_operation(rop.GETFIELD_GC, [res, ofs_u], 'int') #assert u.value == 5 self.execute_operation(rop.SETFIELD_GC, [res, ConstInt(1)], 'void', ofsc1) self.execute_operation(rop.SETFIELD_GC, [res, ConstInt(3)], 'void', ofsc3) self.execute_operation(rop.SETFIELD_GC, [res, ConstInt(2)], 'void', ofsc2) c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc1) assert c.value == 1 c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc2) assert c.value == 2 c = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofsc3) assert c.value == 3
def test_record_constptrs(self): class MyFakeCPU(object): def cast_adr_to_int(self, adr): assert adr == "some fake address" return 43 class MyFakeGCRefList(object): def get_address_of_gcref(self, s_gcref1): assert s_gcref1 == s_gcref return "some fake address" S = lltype.GcStruct('S') s = lltype.malloc(S) s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s) v_random_box = BoxPtr() v_result = BoxInt() operations = [ ResOperation(rop.PTR_EQ, [v_random_box, ConstPtr(s_gcref)], v_result), ] gc_ll_descr = self.gc_ll_descr gc_ll_descr.gcrefs = MyFakeGCRefList() gcrefs = [] operations = get_deep_immutable_oplist(operations) operations2 = gc_ll_descr.rewrite_assembler(MyFakeCPU(), operations, gcrefs) assert operations2 == operations assert gcrefs == [s_gcref]
def do_strgetitem(self, stringbox, indexbox): basesize, itemsize, ofs_length = symbolic.get_array_token( rstr.STR, self.translate_support_code) gcref = stringbox.getref_base() i = indexbox.getint() v = rffi.cast(rffi.CArrayPtr(lltype.Char), gcref)[basesize + i] return BoxInt(ord(v))
def do_strlen(self, stringbox): basesize, itemsize, ofs_length = symbolic.get_array_token( TP, self.translate_support_code) gcref = stringbox.getref_base() v = rffi.cast(rffi.CArrayPtr(lltype.Signed), gcref)[ofs_length / WORD] return BoxInt(v)
def do_getarrayitem_gc(self, arraybox, indexbox, arraydescr): itemindex = indexbox.getint() gcref = arraybox.getref_base() ofs, size, ptr, float = self.unpack_arraydescr(arraydescr) # --- start of GC unsafe code (no GC operation!) --- items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs) # if ptr: items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items) pval = self._cast_int_to_gcref(items[itemindex]) # --- end of GC unsafe code --- return BoxPtr(pval) # if float: items = rffi.cast(rffi.CArrayPtr(lltype.Float), items) fval = items[itemindex] # --- end of GC unsafe code --- return BoxFloat(fval) # for TYPE, itemsize in unroll_basic_sizes: if size == itemsize: items = rffi.cast(rffi.CArrayPtr(TYPE), items) val = items[itemindex] # --- end of GC unsafe code --- return BoxInt(rffi.cast(lltype.Signed, val)) else: raise NotImplementedError("size = %d" % size)
def test_execute(): cpu = FakeCPU() descr = FakeDescr() box = execute(cpu, rop.INT_ADD, None, BoxInt(40), ConstInt(2)) assert box.value == 42 box = execute(cpu, rop.NEW, descr) assert box.args == ('new', descr)
def new_box_item(self, arraydescr): if arraydescr.is_array_of_pointers(): return self.new_ptr_box() elif arraydescr.is_array_of_floats(): return BoxFloat() else: return BoxInt()
def new_box(self, fieldofs): if fieldofs.is_pointer_field(): return self.new_ptr_box() elif fieldofs.is_float_field(): return BoxFloat() else: return BoxInt()
def __init__(self, cpu, cliloop): self.setoptions() self.cpu = cpu self.name = cliloop.get_fresh_cli_name() self.cliloop = cliloop self.boxes = {} # box --> local var self.branches = [] self.branchlabels = [] self.consts = {} # object --> index self.meth_wrapper = self._get_meth_wrapper() self.il = self.meth_wrapper.get_il_generator() self.av_consts = MethodArgument(0, System.Type.GetType("System.Object[]")) t_InputArgs = dotnet.typeof(InputArgs) self.av_inputargs = MethodArgument(1,t_InputArgs ) self.av_ovf_flag = BoxInt() self.exc_value_field = t_InputArgs.GetField('exc_value') if cpu.rtyper: self.av_OverflowError = ConstObj(ootype.cast_to_object(cpu.ll_ovf_exc)) self.av_ZeroDivisionError = ConstObj(ootype.cast_to_object(cpu.ll_zero_exc)) else: self.av_OverflowError = None self.av_ZeroDivisionError = None self.box2type = {}
class Method(object): operations = [] # overwritten at the end of the module debug = False tailcall = True nocast = True def __init__(self, cpu, cliloop): self.setoptions() self.cpu = cpu self.name = cliloop.get_fresh_cli_name() self.cliloop = cliloop self.boxes = {} # box --> local var self.branches = [] self.branchlabels = [] self.consts = {} # object --> index self.meth_wrapper = self._get_meth_wrapper() self.il = self.meth_wrapper.get_il_generator() self.av_consts = MethodArgument(0, System.Type.GetType("System.Object[]")) t_InputArgs = dotnet.typeof(InputArgs) self.av_inputargs = MethodArgument(1,t_InputArgs ) self.av_ovf_flag = BoxInt() self.exc_value_field = t_InputArgs.GetField('exc_value') if cpu.rtyper: self.av_OverflowError = ConstObj(ootype.cast_to_object(cpu.ll_ovf_exc)) self.av_ZeroDivisionError = ConstObj(ootype.cast_to_object(cpu.ll_zero_exc)) else: self.av_OverflowError = None self.av_ZeroDivisionError = None self.box2type = {} def compile(self): # ---- debug_start('jit-backend-emit_ops') if self.nocast: self.compute_types() self.emit_load_inputargs() self.emit_preamble() self.emit_operations(self.cliloop.operations) self.emit_branches() self.emit_end() debug_stop('jit-backend-emit_ops') # ---- debug_start('jit-backend-finish_code') res = self.finish_code() debug_stop('jit-backend-finish_code') return res def _parseopt(self, text): text = text.lower() if text[0] == '-': return text[1:], False elif text[0] == '+': return text[1:], True else: return text, True def setoptions(self): opts = os.environ.get('PYPYJITOPT') if not opts: return parts = opts.split(' ') for part in parts: name, value = self._parseopt(part) if name == 'debug': self.debug = value elif name == 'tailcall': self.tailcall = value elif name == 'nocast': self.nocast = value else: os.write(2, 'Warning: invalid option name: %s\n' % name) def _collect_types(self, operations, box2classes): for op in operations: if op.opnum in (rop.GETFIELD_GC, rop.SETFIELD_GC): box = op.args[0] descr = op.descr assert isinstance(descr, runner.FieldDescr) box2classes.setdefault(box, []).append(descr.selfclass) if op in self.cliloop.guard2ops: _, suboperations = self.cliloop.guard2ops[op] self._collect_types(suboperations, box2classes) def compute_types(self): box2classes = {} # box --> [ootype.Class] self._collect_types(self.cliloop.operations, box2classes) for box, classes in box2classes.iteritems(): cls = classes[0] for cls2 in classes[1:]: if ootype.subclassof(cls, cls2): cls = cls2 else: assert ootype.subclassof(cls2, cls) self.box2type[box] = dotnet.class2type(cls) def finish_code(self): delegatetype = dotnet.typeof(LoopDelegate) # initialize the array of genconsts consts = dotnet.new_array(System.Object, len(self.consts)) for av_const, i in self.consts.iteritems(): consts[i] = av_const.get_cliobj() # build the delegate func = self.meth_wrapper.create_delegate(delegatetype, consts) return dotnet.clidowncast(func, LoopDelegate) def _get_meth_wrapper(self): restype = dotnet.class2type(cVoid) args = self._get_args_array([dotnet.typeof(InputArgs)]) return get_method_wrapper(self.name, restype, args) def _get_args_array(self, arglist): array = dotnet.new_array(System.Type, len(arglist)+1) array[0] = System.Type.GetType("System.Object[]") for i in range(len(arglist)): array[i+1] = arglist[i] return array def var_for_box(self, box): try: return self.boxes[box] except KeyError: v = self.il.DeclareLocal(box.getCliType(self)) self.boxes[box] = v return v def match_var_fox_boxes(self, failargs, inputargs): failargs = [arg for arg in failargs if arg is not None] assert len(failargs) == len(inputargs) for i in range(len(failargs)): v = self.boxes[failargs[i]] self.boxes[inputargs[i]] = v def get_index_for_failing_op(self, op): try: return self.cpu.failing_ops.index(op) except ValueError: self.cpu.failing_ops.append(op) return len(self.cpu.failing_ops)-1 def get_index_for_constant(self, obj): try: return self.consts[obj] except KeyError: index = len(self.consts) self.consts[obj] = index return index def newbranch(self, op): # sanity check, maybe we can remove it later for myop in self.branches: assert myop is not op il_label = self.il.DefineLabel() self.branches.append(op) self.branchlabels.append(il_label) return il_label def get_inputarg_field(self, type): t = dotnet.typeof(InputArgs) if type == history.INT: fieldname = 'ints' elif type == history.FLOAT: fieldname = 'floats' elif type == history.REF: fieldname = 'objs' else: assert False, 'Unknown type %s' % type return t.GetField(fieldname) def load_inputarg(self, i, type, clitype): field = self.get_inputarg_field(type) self.av_inputargs.load(self) self.il.Emit(OpCodes.Ldfld, field) self.il.Emit(OpCodes.Ldc_I4, i) self.il.Emit(OpCodes.Ldelem, clitype) def store_inputarg(self, i, type, clitype, valuebox): field = self.get_inputarg_field(type) self.av_inputargs.load(self) self.il.Emit(OpCodes.Ldfld, field) self.il.Emit(OpCodes.Ldc_I4, i) valuebox.load(self) self.il.Emit(OpCodes.Stelem, clitype) def emit_load_inputargs(self): self.emit_debug("executing: " + self.name) i = 0 for box in self.cliloop.inputargs: self.load_inputarg(i, box.type, box.getCliType(self)) box.store(self) i+=1 def emit_preamble(self): self.il_loop_start = self.il.DefineLabel() self.il.MarkLabel(self.il_loop_start) def emit_operations(self, oplist): self.i = 0 self.oplist = oplist N = len(oplist) while self.i < N: op = oplist[self.i] self.emit_debug(op.repr()) func = self.operations[op.opnum] assert func is not None func(self, op) self.i += 1 def emit_branches(self): while self.branches: branches = self.branches branchlabels = self.branchlabels self.branches = [] self.branchlabels = [] assert len(branches) == len(branchlabels) for i in range(len(branches)): op = branches[i] il_label = branchlabels[i] self.il.MarkLabel(il_label) self.emit_guard_subops(op) def emit_guard_subops(self, op): assert op.is_guard() if op in self.cliloop.guard2ops: inputargs, suboperations = self.cliloop.guard2ops[op] self.match_var_fox_boxes(op.fail_args, inputargs) self.emit_operations(suboperations) else: self.emit_return_failed_op(op, op.fail_args) def emit_end(self): assert self.branches == [] self.il.Emit(OpCodes.Ret) # ----------------------------- def push_all_args(self, op): for box in op.args: box.load(self) def push_arg(self, op, n): op.args[n].load(self) def store_result(self, op): op.result.store(self) def emit_debug(self, msg): if self.debug: self.il.EmitWriteLine(msg) def emit_clear_exception(self): self.av_inputargs.load(self) self.il.Emit(OpCodes.Ldnull) self.il.Emit(OpCodes.Stfld, self.exc_value_field) # clear the overflow flag self.il.Emit(OpCodes.Ldc_I4_0) self.av_ovf_flag.store(self) def emit_raising_op(self, op, emit_op, exctypes): self.emit_clear_exception() lbl = self.il.BeginExceptionBlock() emit_op(self, op) self.il.Emit(OpCodes.Leave, lbl) for exctype in exctypes: v = self.il.DeclareLocal(exctype) self.il.BeginCatchBlock(exctype) if exctype == dotnet.typeof(System.OverflowException) and self.av_OverflowError: self.il.Emit(OpCodes.Ldc_I4_1) self.av_ovf_flag.store(self) else: self.il.Emit(OpCodes.Stloc, v) self.av_inputargs.load(self) self.il.Emit(OpCodes.Ldloc, v) self.il.Emit(OpCodes.Stfld, self.exc_value_field) self.il.EndExceptionBlock() def emit_ovf_op(self, op, emit_op): next_op = self.oplist[self.i+1] if next_op.opnum == rop.GUARD_NO_OVERFLOW: self.i += 1 self.emit_ovf_op_and_guard(op, next_op, emit_op) return # clear the overflow flag self.il.Emit(OpCodes.Ldc_I4_0) self.av_ovf_flag.store(self) lbl = self.il.BeginExceptionBlock() emit_op(self, op) self.il.Emit(OpCodes.Leave, lbl) self.il.BeginCatchBlock(dotnet.typeof(System.OverflowException)) self.il.Emit(OpCodes.Ldc_I4_1) self.av_ovf_flag.store(self) self.il.EndExceptionBlock() def emit_ovf_op_and_guard(self, op, opguard, emit_op): # emit the checked operation lbl = self.il.BeginExceptionBlock() emit_op(self, op) self.il.Emit(OpCodes.Leave, lbl) self.il.BeginCatchBlock(dotnet.typeof(System.OverflowException)) # emit the guard assert len(opguard.args) == 0 il_label = self.newbranch(opguard) self.il.Emit(OpCodes.Leave, il_label) self.il.EndExceptionBlock() def mark(self, msg): self.il.Emit(OpCodes.Ldstr, msg) self.il.Emit(OpCodes.Pop) # -------------------------------- def emit_return_failed_op(self, op, args): # store the index of the failed op index_op = self.get_index_for_failing_op(op) self.av_inputargs.load(self) self.il.Emit(OpCodes.Ldc_I4, index_op) field = dotnet.typeof(InputArgs).GetField('failed_op') self.il.Emit(OpCodes.Stfld, field) self.emit_store_opargs(args) self.il.Emit(OpCodes.Ret) def emit_op_finish(self, op): self.emit_return_failed_op(op, op.args) def emit_store_opargs(self, args): # store the latest values i = 0 for box in args: if box is not None: self.store_inputarg(i, box.type, box.getCliType(self), box) i+=1 def emit_guard_bool(self, op, opcode): assert len(op.args) == 1 il_label = self.newbranch(op) op.args[0].load(self) self.il.Emit(opcode, il_label) def emit_op_guard_true(self, op): self.emit_guard_bool(op, OpCodes.Brfalse) def emit_op_guard_false(self, op): self.emit_guard_bool(op, OpCodes.Brtrue) def emit_op_guard_nonnull(self, op): self.emit_guard_bool(op, OpCodes.Brfalse) def emit_op_guard_isnull(self, op): self.emit_guard_bool(op, OpCodes.Brtrue) def emit_op_guard_value(self, op): assert len(op.args) == 2 il_label = self.newbranch(op) self.push_all_args(op) self.il.Emit(OpCodes.Bne_Un, il_label) def emit_op_guard_class(self, op): assert len(op.args) == 2 il_label = self.newbranch(op) self.push_arg(op, 0) meth = dotnet.typeof(System.Object).GetMethod("GetType") self.il.Emit(OpCodes.Callvirt, meth) self.push_arg(op, 1) self.il.Emit(OpCodes.Bne_Un, il_label) def emit_op_guard_nonnull_class(self, op): assert len(op.args) == 2 il_label = self.newbranch(op) # nonnull check self.push_arg(op, 0) self.il.Emit(OpCodes.Brfalse, il_label) # class check self.push_arg(op, 0) meth = dotnet.typeof(System.Object).GetMethod("GetType") self.il.Emit(OpCodes.Callvirt, meth) self.push_arg(op, 1) self.il.Emit(OpCodes.Bne_Un, il_label) def emit_op_guard_no_exception(self, op): il_label = self.newbranch(op) self.av_inputargs.load(self) self.il.Emit(OpCodes.Ldfld, self.exc_value_field) self.il.Emit(OpCodes.Brtrue, il_label) def emit_op_guard_exception(self, op): il_label = self.newbranch(op) classbox = op.args[0] assert isinstance(classbox, ConstObj) oocls = classbox.getref(ootype.Class) clitype = dotnet.class2type(oocls) self.av_inputargs.load(self) self.il.Emit(OpCodes.Ldfld, self.exc_value_field) self.il.Emit(OpCodes.Isinst, clitype) self.il.Emit(OpCodes.Brfalse, il_label) # the guard succeeded, store the result self.av_inputargs.load(self) self.il.Emit(OpCodes.Ldfld, self.exc_value_field) self.store_result(op) def emit_guard_overflow_impl(self, op, opcode): assert len(op.args) == 0 il_label = self.newbranch(op) self.av_ovf_flag.load(self) self.il.Emit(opcode, il_label) def emit_op_guard_no_overflow(self, op): self.emit_guard_overflow_impl(op, OpCodes.Brtrue) def emit_op_guard_overflow(self, op): self.emit_guard_overflow_impl(op, OpCodes.Brfalse) def emit_op_jump(self, op): target_token = op.descr assert isinstance(target_token, LoopToken) if target_token.cliloop is self.cliloop: # jump to the beginning of the loop i = 0 for i in range(len(op.args)): op.args[i].load(self) self.cliloop.inputargs[i].store(self) self.il.Emit(OpCodes.Br, self.il_loop_start) else: # it's a real bridge cliloop = target_token.cliloop assert len(op.args) == len(cliloop.inputargs) self.emit_debug('jumping to ' + cliloop.name) self.emit_store_opargs(op.args) cliloop.funcbox.load(self) self.av_inputargs.load(self) methinfo = dotnet.typeof(LoopDelegate).GetMethod('Invoke') if self.tailcall: self.il.Emit(OpCodes.Tailcall) self.il.Emit(OpCodes.Callvirt, methinfo) self.il.Emit(OpCodes.Ret) def emit_op_new_with_vtable(self, op): clsbox = op.args[0] assert isinstance(clsbox, ConstObj) cls = clsbox.getref_base() descr = self.cpu.class_sizes[cls] assert isinstance(descr, runner.TypeDescr) clitype = descr.get_clitype() ctor_info = descr.get_constructor_info() self.il.Emit(OpCodes.Newobj, ctor_info) self.store_result(op) def emit_op_runtimenew(self, op): clitype_utils = dotnet.typeof(Utils) methinfo = clitype_utils.GetMethod('RuntimeNew') op.args[0].load(self) self.il.Emit(OpCodes.Call, methinfo) self.store_result(op) def emit_op_instanceof(self, op): descr = op.descr assert isinstance(descr, runner.TypeDescr) clitype = descr.get_clitype() op.args[0].load(self) self.il.Emit(OpCodes.Isinst, clitype) self.il.Emit(OpCodes.Ldnull) self.il.Emit(OpCodes.Cgt_Un) self.store_result(op) def emit_op_subclassof(self, op): clitype_utils = dotnet.typeof(Utils) methinfo = clitype_utils.GetMethod('SubclassOf') op.args[0].load(self) op.args[1].load(self) self.il.Emit(OpCodes.Call, methinfo) self.store_result(op) def emit_op_call_impl(self, op): descr = op.descr assert isinstance(descr, runner.StaticMethDescr) delegate_type = descr.get_delegate_clitype() meth_invoke = descr.get_meth_info() self._emit_call(op, OpCodes.Callvirt, delegate_type, meth_invoke, descr.has_result) def emit_op_call(self, op): emit_op = Method.emit_op_call_impl.im_func exctypes = [dotnet.typeof(System.Exception)] self.emit_raising_op(op, emit_op, exctypes) emit_op_call_pure = emit_op_call def emit_op_oosend(self, op): descr = op.descr assert isinstance(descr, runner.MethDescr) clitype = descr.get_self_clitype() methinfo = descr.get_meth_info() opcode = descr.get_call_opcode() self._emit_call(op, opcode, clitype, methinfo, descr.has_result) emit_op_oosend_pure = emit_op_oosend def _emit_call(self, op, opcode, clitype, methinfo, has_result): av_sm, args_av = op.args[0], op.args[1:] av_sm.load(self) self.il.Emit(OpCodes.Castclass, clitype) for av_arg in args_av: av_arg.load(self) self.il.Emit(opcode, methinfo) if has_result: self.store_result(op) def emit_op_getfield_gc(self, op): descr = op.descr assert isinstance(descr, runner.FieldDescr) clitype = descr.get_self_clitype() fieldinfo = descr.get_field_info() obj = op.args[0] obj.load(self) if obj.getCliType(self) is not clitype: self.il.Emit(OpCodes.Castclass, clitype) self.il.Emit(OpCodes.Ldfld, fieldinfo) self.store_result(op) emit_op_getfield_gc_pure = emit_op_getfield_gc def emit_op_setfield_gc(self, op): descr = op.descr assert isinstance(descr, runner.FieldDescr) clitype = descr.get_self_clitype() fieldinfo = descr.get_field_info() obj = op.args[0] obj.load(self) if obj.getCliType(self) is not clitype: self.il.Emit(OpCodes.Castclass, clitype) op.args[1].load(self) self.il.Emit(OpCodes.Stfld, fieldinfo) def emit_op_getarrayitem_gc(self, op): descr = op.descr assert isinstance(descr, runner.TypeDescr) clitype = descr.get_array_clitype() itemtype = descr.get_clitype() op.args[0].load(self) self.il.Emit(OpCodes.Castclass, clitype) op.args[1].load(self) self.il.Emit(OpCodes.Ldelem, itemtype) self.store_result(op) emit_op_getarrayitem_gc_pure = emit_op_getarrayitem_gc def emit_op_setarrayitem_gc(self, op): descr = op.descr assert isinstance(descr, runner.TypeDescr) clitype = descr.get_array_clitype() itemtype = descr.get_clitype() op.args[0].load(self) self.il.Emit(OpCodes.Castclass, clitype) op.args[1].load(self) op.args[2].load(self) self.il.Emit(OpCodes.Stelem, itemtype) def emit_op_arraylen_gc(self, op): descr = op.descr assert isinstance(descr, runner.TypeDescr) clitype = descr.get_array_clitype() op.args[0].load(self) self.il.Emit(OpCodes.Castclass, clitype) self.il.Emit(OpCodes.Ldlen) self.store_result(op) def emit_op_new_array(self, op): descr = op.descr assert isinstance(descr, runner.TypeDescr) item_clitype = descr.get_clitype() if item_clitype is None: return self.emit_new_arrayofvoids(op) op.args[0].load(self) self.il.Emit(OpCodes.Newarr, item_clitype) self.store_result(op) def emit_new_arrayofvoids(self, op): clitype = dotnet.typeof(ListOfVoid) ctor = clitype.GetConstructor(dotnet.new_array(System.Type, 0)) _ll_resize = clitype.GetMethod('_ll_resize') self.il.Emit(OpCodes.Newobj, ctor) self.il.Emit(OpCodes.Dup) op.args[0].load(self) self.il.Emit(OpCodes.Callvirt, _ll_resize) self.store_result(op) def emit_op_debug_merge_point(self, op): pass def lltype_only(self, op): print 'Operation %s is lltype specific, should not get here!' % op.getopname() raise NotImplementedError emit_op_new = lltype_only emit_op_setfield_raw = lltype_only emit_op_getfield_raw = lltype_only emit_op_getfield_raw_pure = lltype_only emit_op_strsetitem = lltype_only emit_op_unicodesetitem = lltype_only emit_op_cast_int_to_ptr = lltype_only emit_op_cast_ptr_to_int = lltype_only emit_op_newstr = lltype_only emit_op_strlen = lltype_only emit_op_strgetitem = lltype_only emit_op_newunicode = lltype_only emit_op_unicodelen = lltype_only emit_op_unicodegetitem = lltype_only emit_op_cond_call_gc_wb = lltype_only emit_op_setarrayitem_raw = lltype_only