def test_malloc_new_with_vtable(): vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) S = lltype.GcStruct("S", ("parent", rclass.OBJECT)) heaptracker.set_testing_vtable_for_gcstruct(S, vtable, "S") v = varoftype(lltype.Ptr(S)) op = SpaceOperation("malloc", [Constant(S, lltype.Void), Constant({"flavor": "gc"}, lltype.Void)], v) cpu = FakeCPU() op1 = Transformer(cpu).rewrite_operation(op) assert op1.opname == "new_with_vtable" assert op1.args == [("sizedescr", S)] # assert heaptracker.descr2vtable(cpu, op1.args[0]) == vtable [type check] vtable_int = heaptracker.adr2int(llmemory.cast_ptr_to_adr(vtable)) assert heaptracker.vtable2descr(cpu, vtable_int) == op1.args[0]
def test_malloc_new_with_vtable(): vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) S = lltype.GcStruct('S', ('parent', rclass.OBJECT)) heaptracker.set_testing_vtable_for_gcstruct(S, vtable, 'S') v = varoftype(lltype.Ptr(S)) op = SpaceOperation( 'malloc', [Constant(S, lltype.Void), Constant({'flavor': 'gc'}, lltype.Void)], v) cpu = FakeCPU() op1 = Transformer(cpu).rewrite_operation(op) assert op1.opname == 'new_with_vtable' assert op1.args == [('sizedescr', S)] #assert heaptracker.descr2vtable(cpu, op1.args[0]) == vtable [type check] vtable_int = heaptracker.adr2int(llmemory.cast_ptr_to_adr(vtable)) assert heaptracker.vtable2descr(cpu, vtable_int) == op1.args[0]
def test_malloc_new_with_destructor(): vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) S = lltype.GcStruct("S", ("parent", rclass.OBJECT), rtti=True) DESTRUCTOR = lltype.FuncType([lltype.Ptr(S)], lltype.Void) destructor = lltype.functionptr(DESTRUCTOR, "destructor") lltype.attachRuntimeTypeInfo(S, destrptr=destructor) heaptracker.set_testing_vtable_for_gcstruct(S, vtable, "S") v = varoftype(lltype.Ptr(S)) op = SpaceOperation("malloc", [Constant(S, lltype.Void), Constant({"flavor": "gc"}, lltype.Void)], v) tr = Transformer(FakeCPU(), FakeResidualCallControl()) oplist = tr.rewrite_operation(op) op0, op1 = oplist assert op0.opname == "residual_call_r_r" assert op0.args[0].value == "alloc_with_del" # pseudo-function as a str assert list(op0.args[2]) == [] assert op1.opname == "-live-" assert op1.args == []
def test_malloc_new_with_destructor(): vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) S = lltype.GcStruct('S', ('parent', rclass.OBJECT), rtti=True) DESTRUCTOR = lltype.FuncType([lltype.Ptr(S)], lltype.Void) destructor = lltype.functionptr(DESTRUCTOR, 'destructor') lltype.attachRuntimeTypeInfo(S, destrptr=destructor) heaptracker.set_testing_vtable_for_gcstruct(S, vtable, 'S') v = varoftype(lltype.Ptr(S)) op = SpaceOperation( 'malloc', [Constant(S, lltype.Void), Constant({'flavor': 'gc'}, lltype.Void)], v) tr = Transformer(FakeCPU(), FakeResidualCallControl()) oplist = tr.rewrite_operation(op) op0, op1 = oplist assert op0.opname == 'residual_call_r_r' assert op0.args[0].value == 'alloc_with_del' # pseudo-function as a str assert list(op0.args[2]) == [] assert op1.opname == '-live-' assert op1.args == []
class ExplicitVirtualizableTests: XY = lltype.GcStruct( 'XY', ('parent', rclass.OBJECT), ('vable_token', lltype.Signed), ('inst_x', lltype.Signed), ('inst_node', lltype.Ptr(LLtypeMixin.NODE)), hints = {'virtualizable2_accessor': FieldListAccessor()}) XY._hints['virtualizable2_accessor'].initialize( XY, {'inst_x' : IR_IMMUTABLE, 'inst_node' : IR_IMMUTABLE}) xy_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) heaptracker.set_testing_vtable_for_gcstruct(XY, xy_vtable, 'XY') def _freeze_(self): return True def setup(self): xy = lltype.malloc(self.XY) xy.vable_token = 0 xy.parent.typeptr = self.xy_vtable return xy def test_preexisting_access(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'], virtualizables = ['xy']) def f(n): xy = self.setup() xy.inst_x = 10 while n > 0: myjitdriver.can_enter_jit(xy=xy, n=n) myjitdriver.jit_merge_point(xy=xy, n=n) promote_virtualizable(xy, 'inst_x') x = xy.inst_x xy.inst_x = x + 1 n -= 1 promote_virtualizable(xy, 'inst_x') return xy.inst_x res = self.meta_interp(f, [20]) assert res == 30 self.check_simple_loop(setfield_gc=0, getfield_gc=0) def test_preexisting_access_2(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'], virtualizables = ['xy']) def f(n): xy = self.setup() xy.inst_x = 100 while n > -8: myjitdriver.can_enter_jit(xy=xy, n=n) myjitdriver.jit_merge_point(xy=xy, n=n) if n > 0: promote_virtualizable(xy, 'inst_x') x = xy.inst_x xy.inst_x = x + 1 else: promote_virtualizable(xy, 'inst_x') x = xy.inst_x xy.inst_x = x + 10 n -= 1 promote_virtualizable(xy, 'inst_x') return xy.inst_x assert f(5) == 185 res = self.meta_interp(f, [5]) assert res == 185 self.check_resops(setfield_gc=0, getfield_gc=2) # <= at the header of the loop def test_two_paths_access(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'], virtualizables = ['xy']) def f(n): xy = self.setup() xy.inst_x = 100 while n > 0: myjitdriver.can_enter_jit(xy=xy, n=n) myjitdriver.jit_merge_point(xy=xy, n=n) promote_virtualizable(xy, 'inst_x') x = xy.inst_x if n <= 10: x += 1000 promote_virtualizable(xy, 'inst_x') xy.inst_x = x + 1 n -= 1 promote_virtualizable(xy, 'inst_x') return xy.inst_x res = self.meta_interp(f, [18]) assert res == 10118 self.check_resops(setfield_gc=0, getfield_gc=2) def test_synchronize_in_return(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy'], virtualizables = ['xy']) def g(xy, n): while n > 0: myjitdriver.can_enter_jit(xy=xy, n=n) myjitdriver.jit_merge_point(xy=xy, n=n) promote_virtualizable(xy, 'inst_x') xy.inst_x += 1 n -= 1 def f(n): xy = self.setup() xy.inst_x = 10000 m = 10 while m > 0: g(xy, n) m -= 1 return xy.inst_x res = self.meta_interp(f, [18]) assert res == 10180 self.check_resops(setfield_gc=0, getfield_gc=2) def test_virtualizable_and_greens(self): myjitdriver = JitDriver(greens = ['m'], reds = ['n', 'xy'], virtualizables = ['xy']) def g(n): xy = self.setup() xy.inst_x = 10 m = 0 while n > 0: myjitdriver.can_enter_jit(xy=xy, n=n, m=m) myjitdriver.jit_merge_point(xy=xy, n=n, m=m) promote_virtualizable(xy, 'inst_x') x = xy.inst_x xy.inst_x = x + 1 m = (m+1) & 3 # the loop gets unrolled 4 times n -= 1 promote_virtualizable(xy, 'inst_x') return xy.inst_x def f(n): res = 0 k = 4 while k > 0: res += g(n) k -= 1 return res res = self.meta_interp(f, [40]) assert res == 50 * 4 self.check_resops(setfield_gc=0, getfield_gc=4) def test_double_frame(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy', 'other'], virtualizables = ['xy']) def f(n): xy = self.setup() xy.inst_x = 10 other = self.setup() other.inst_x = 15 while n > 0: myjitdriver.can_enter_jit(xy=xy, n=n, other=other) myjitdriver.jit_merge_point(xy=xy, n=n, other=other) promote_virtualizable(other, 'inst_x') value = other.inst_x # getfield_gc other.inst_x = value + 1 # setfield_gc promote_virtualizable(xy, 'inst_x') xy.inst_x = value + 100 # virtualized away n -= 1 promote_virtualizable(xy, 'inst_x') return xy.inst_x res = self.meta_interp(f, [20]) assert res == 134 self.check_simple_loop(setfield_gc=1, getfield_gc=0) self.check_resops(setfield_gc=2, getfield_gc=3) # ------------------------------ XY2 = lltype.GcStruct( 'XY2', ('parent', rclass.OBJECT), ('vable_token', lltype.Signed), ('inst_x', lltype.Signed), ('inst_l1', lltype.Ptr(lltype.GcArray(lltype.Signed))), ('inst_l2', lltype.Ptr(lltype.GcArray(lltype.Signed))), hints = {'virtualizable2_accessor': FieldListAccessor()}) XY2._hints['virtualizable2_accessor'].initialize( XY2, {'inst_x' : IR_IMMUTABLE, 'inst_l1' : IR_IMMUTABLE_ARRAY, 'inst_l2' : IR_IMMUTABLE_ARRAY}) xy2_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) heaptracker.set_testing_vtable_for_gcstruct(XY2, xy2_vtable, 'XY2') def setup2(self): xy2 = lltype.malloc(self.XY2) xy2.vable_token = 0 xy2.parent.typeptr = self.xy2_vtable return xy2 def test_access_list_fields(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'], virtualizables = ['xy2']) ARRAY = lltype.GcArray(lltype.Signed) def f(n): xy2 = self.setup2() xy2.inst_x = 100 xy2.inst_l1 = lltype.malloc(ARRAY, 3) xy2.inst_l1[0] = -9999999 xy2.inst_l1[1] = -9999999 xy2.inst_l1[2] = 3001 xy2.inst_l2 = lltype.malloc(ARRAY, 2) xy2.inst_l2[0] = 80 xy2.inst_l2[1] = -9999999 while n > 0: myjitdriver.can_enter_jit(xy2=xy2, n=n) myjitdriver.jit_merge_point(xy2=xy2, n=n) promote_virtualizable(xy2, 'inst_l1') promote_virtualizable(xy2, 'inst_l2') xy2.inst_l1[2] += xy2.inst_l2[0] n -= 1 promote_virtualizable(xy2, 'inst_l1') return xy2.inst_l1[2] res = self.meta_interp(f, [16]) assert res == 3001 + 16 * 80 self.check_simple_loop(setarrayitem_gc=0, setfield_gc=0, getarrayitem_gc=0, getfield_gc=0) def test_synchronize_arrays_in_return(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'], virtualizables = ['xy2']) ARRAY = lltype.GcArray(lltype.Signed) def g(xy2, n): while n > 0: myjitdriver.can_enter_jit(xy2=xy2, n=n) myjitdriver.jit_merge_point(xy2=xy2, n=n) promote_virtualizable(xy2, 'inst_x') promote_virtualizable(xy2, 'inst_l2') xy2.inst_l2[0] += xy2.inst_x n -= 1 def f(n): xy2 = self.setup2() xy2.inst_x = 2 xy2.inst_l1 = lltype.malloc(ARRAY, 2) xy2.inst_l1[0] = 1941309 xy2.inst_l1[1] = 2941309 xy2.inst_l2 = lltype.malloc(ARRAY, 1) xy2.inst_l2[0] = 10000 m = 10 while m > 0: g(xy2, n) m -= 1 return xy2.inst_l2[0] assert f(18) == 10360 res = self.meta_interp(f, [18]) assert res == 10360 self.check_simple_loop(setfield_gc=0, getarrayitem_gc=0, getfield_gc=0, setarrayitem_gc=0) def test_array_length(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'], virtualizables = ['xy2']) ARRAY = lltype.GcArray(lltype.Signed) def g(xy2, n): while n > 0: myjitdriver.can_enter_jit(xy2=xy2, n=n) myjitdriver.jit_merge_point(xy2=xy2, n=n) promote_virtualizable(xy2, 'inst_l1') promote_virtualizable(xy2, 'inst_l2') xy2.inst_l1[1] += len(xy2.inst_l2) n -= 1 def f(n): xy2 = self.setup2() xy2.inst_x = 2 xy2.inst_l1 = lltype.malloc(ARRAY, 2) xy2.inst_l1[0] = 1941309 xy2.inst_l1[1] = 2941309 xy2.inst_l2 = lltype.malloc(ARRAY, 1) xy2.inst_l2[0] = 10000 g(xy2, n) return xy2.inst_l1[1] res = self.meta_interp(f, [18]) assert res == 2941309 + 18 self.check_simple_loop(setfield_gc=0, getarrayitem_gc=0, arraylen_gc=0, getfield_gc=0) def test_residual_function(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'], virtualizables = ['xy2']) ARRAY = lltype.GcArray(lltype.Signed) # @dont_look_inside def h(xy2): # this function is marked for residual calls because # it does something with a virtualizable's array that is not # just accessing an item return xy2.inst_l2 # def g(xy2, n): while n > 0: myjitdriver.can_enter_jit(xy2=xy2, n=n) myjitdriver.jit_merge_point(xy2=xy2, n=n) promote_virtualizable(xy2, 'inst_l1') xy2.inst_l1[1] = xy2.inst_l1[1] + len(h(xy2)) n -= 1 def f(n): xy2 = self.setup2() xy2.inst_x = 2 xy2.inst_l1 = lltype.malloc(ARRAY, 2) xy2.inst_l1[0] = 1941309 xy2.inst_l1[1] = 2941309 xy2.inst_l2 = lltype.malloc(ARRAY, 1) xy2.inst_l2[0] = 10000 g(xy2, n) return xy2.inst_l1[1] res = self.meta_interp(f, [18]) assert res == 2941309 + 18 self.check_simple_loop(call=1, setfield_gc=0, getarrayitem_gc=0, arraylen_gc=1, getfield_gc=0) def test_double_frame_array(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2', 'other'], virtualizables = ['xy2']) ARRAY = lltype.GcArray(lltype.Signed) def f(n): xy2 = self.setup2() xy2.inst_x = 10 xy2.inst_l1 = lltype.malloc(ARRAY, 1) xy2.inst_l1[0] = 1982731 xy2.inst_l2 = lltype.malloc(ARRAY, 1) xy2.inst_l2[0] = 10000 other = self.setup2() other.inst_x = 15 other.inst_l1 = lltype.malloc(ARRAY, 2) other.inst_l1[0] = 189182 other.inst_l1[1] = 58421 other.inst_l2 = lltype.malloc(ARRAY, 2) other.inst_l2[0] = 181 other.inst_l2[1] = 189 while n > 0: myjitdriver.can_enter_jit(xy2=xy2, n=n, other=other) myjitdriver.jit_merge_point(xy2=xy2, n=n, other=other) promote_virtualizable(other, 'inst_l2') length = len(other.inst_l2) # getfield_gc/arraylen_gc value = other.inst_l2[0] # getfield_gc/getarrayitem_gc other.inst_l2[0] = value + length # getfield_gc/setarrayitem_gc promote_virtualizable(xy2, 'inst_l2') xy2.inst_l2[0] = value + 100 # virtualized away n -= 1 promote_virtualizable(xy2, 'inst_l2') return xy2.inst_l2[0] expected = f(20) res = self.meta_interp(f, [20], enable_opts='') assert res == expected self.check_simple_loop(setarrayitem_gc=1, setfield_gc=0, getarrayitem_gc=1, arraylen_gc=1, getfield_gc=1) # ------------------------------ XY2SUB = lltype.GcStruct( 'XY2SUB', ('parent', XY2)) xy2sub_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) heaptracker.set_testing_vtable_for_gcstruct(XY2SUB, xy2sub_vtable, 'XY2SUB') def setup2sub(self): xy2 = lltype.malloc(self.XY2SUB) xy2.parent.vable_token = 0 xy2.parent.parent.typeptr = self.xy2_vtable return xy2 def test_subclass(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'xy2'], virtualizables = ['xy2']) ARRAY = lltype.GcArray(lltype.Signed) def g(xy2, n): while n > 0: myjitdriver.can_enter_jit(xy2=xy2, n=n) myjitdriver.jit_merge_point(xy2=xy2, n=n) parent = xy2.parent promote_virtualizable(parent, 'inst_x') promote_virtualizable(parent, 'inst_l2') parent.inst_l2[0] += parent.inst_x n -= 1 def f(n): xy2 = self.setup2sub() xy2.parent.inst_x = 2 xy2.parent.inst_l1 = lltype.malloc(ARRAY, 2) xy2.parent.inst_l1[0] = 1941309 xy2.parent.inst_l1[1] = 2941309 xy2.parent.inst_l2 = lltype.malloc(ARRAY, 1) xy2.parent.inst_l2[0] = 10000 m = 10 while m > 0: g(xy2, n) m -= 1 return xy2.parent.inst_l2[0] assert f(18) == 10360 res = self.meta_interp(f, [18]) assert res == 10360 self.check_simple_loop(getfield_gc=0, getarrayitem_gc=0, setfield_gc=0, setarrayitem_gc=0)
@staticmethod def _new(): return ootype.new(OONODE) # ____________________________________________________________ # Run 3: all the tests use lltype.malloc to make a NODE2 # (same as Run 2 but it is part of the OBJECT hierarchy) NODE2 = lltype.GcStruct('NODE2', ('parent', rclass.OBJECT), ('floatval', lltype.Float), ('value', lltype.Signed), ('extra', lltype.Signed)) vtable2 = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True) heaptracker.set_testing_vtable_for_gcstruct(NODE2, vtable2, 'NODE2') class TestLLtype_Object(VirtualTests, LLJitMixin): _new_op = 'new_with_vtable' _field_prefix = '' @staticmethod def _new(): p = lltype.malloc(NODE2) p.parent.typeptr = vtable2 return p # misc class TestOOTypeMisc(VirtualMiscTests, OOJitMixin): pass