def test_call_doesnt_invalidate_unescaped_array_boxes(self): h = HeapCache() h.new_array(box1, lengthbox1) assert h.is_unescaped(box1) h.setarrayitem(box1, index1, box3, descr1) h.invalidate_caches(rop.CALL, FakeCallDescr(FakeEffectinfo.EF_CAN_RAISE), []) assert h.getarrayitem(box1, index1, descr1) is box3
def test_call_doesnt_invalidate_unescaped_boxes(self): h = HeapCache() h.new(box1) assert h.is_unescaped(box1) h.setfield(box1, box2, descr1) h.invalidate_caches(rop.CALL, FakeCallDescr(FakeEffectinfo.EF_CAN_RAISE), []) assert h.getfield(box1, descr1) is box2
def test_quasiimmut_seen_consts(self): h = HeapCache() box1 = ConstPtr(rffi.cast(llmemory.GCREF, 1)) box2 = ConstPtr(rffi.cast(llmemory.GCREF, 1)) box3 = ConstPtr(rffi.cast(llmemory.GCREF, 1)) box4 = ConstPtr(rffi.cast(llmemory.GCREF, 1)) assert not h.is_quasi_immut_known(descr1, box1) assert not h.is_quasi_immut_known(descr1, box2) assert not h.is_quasi_immut_known(descr2, box3) assert not h.is_quasi_immut_known(descr2, box4) h.quasi_immut_now_known(descr1, box1) assert h.is_quasi_immut_known(descr1, box1) assert h.is_quasi_immut_known(descr1, box2) assert not h.is_quasi_immut_known(descr2, box3) assert not h.is_quasi_immut_known(descr2, box4) h.quasi_immut_now_known(descr2, box3) assert h.is_quasi_immut_known(descr1, box1) assert h.is_quasi_immut_known(descr1, box2) assert h.is_quasi_immut_known(descr2, box3) assert h.is_quasi_immut_known(descr2, box4) # invalidate the descr1 cache vbox1 = RefFrontendOp(1) vbox2 = RefFrontendOp(2) h.setfield(vbox1, vbox2, descr1) assert not h.is_quasi_immut_known(descr1, box1) assert not h.is_quasi_immut_known(descr1, box2) # a call invalidates everything h.invalidate_caches( rop.CALL_N, FakeCallDescr(FakeEffectinfo.EF_CAN_RAISE), []) assert not h.is_quasi_immut_known(descr2, box3) assert not h.is_quasi_immut_known(descr2, box4)
def test_ll_arraycopy_differing_descrs(self): h = HeapCache() h.setarrayitem(box1, index1, box2, descr2) assert h.getarrayitem(box1, index1, descr2) is box2 h.new_array(box2, lengthbox2) h.invalidate_caches(rop.CALL, arraycopydescr1, [None, box3, box2, index1, index1, index2]) assert h.getarrayitem(box1, index1, descr2) is box2
def test_bug_heap_cache_is_cleared_but_not_is_unescaped_2(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) h.new(box1) h.new(box2) h.setfield(box1, box2, descr1) h.invalidate_caches(rop.SETFIELD_GC, None, [box1, box2]) assert h.getfield(box1, descr1) is box2 descr = BasicFailDescr() class XTra: oopspecindex = 0 OS_ARRAYCOPY = 42 extraeffect = 5 EF_LOOPINVARIANT = 1 EF_ELIDABLE_CANNOT_RAISE = 2 EF_ELIDABLE_OR_MEMORYERROR = 3 EF_ELIDABLE_CAN_RAISE = 4 descr.get_extra_info = XTra h.invalidate_caches(rop.CALL_N, descr, []) assert h.is_unescaped(box1) assert h.is_unescaped(box2) assert h.getfield(box1, descr1) is box2
def test_bug_heap_cache_is_cleared_but_not_is_unescaped_2(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) h.new(box1) h.new(box2) h.setfield(box1, box2, descr1) h.invalidate_caches(rop.SETFIELD_GC, None, [box1, box2]) assert h.getfield(box1, descr1) is box2 descr = BasicFailDescr() class XTra: oopspecindex = 0 OS_ARRAYCOPY = 42 OS_ARRAYMOVE = 49 extraeffect = 5 EF_LOOPINVARIANT = 1 EF_ELIDABLE_CANNOT_RAISE = 2 EF_ELIDABLE_OR_MEMORYERROR = 3 EF_ELIDABLE_CAN_RAISE = 4 descr.get_extra_info = XTra h.invalidate_caches(rop.CALL_N, descr, []) assert h.is_unescaped(box1) assert h.is_unescaped(box2) assert h.getfield(box1, descr1) is box2
def test_circular_virtuals(self): h = HeapCache() h.new(box1) h.new(box2) h.invalidate_caches(rop.SETFIELD_GC, None, [box1, box2]) h.invalidate_caches(rop.SETFIELD_GC, None, [box2, box1]) h.invalidate_caches(rop.SETFIELD_GC, None, [box3, box1]) # does not crash
def test_ll_arraycopy_differing_descrs_nonconst_index(self): h = HeapCache() h.setarrayitem(box1, index1, box2, descr2) assert h.getarrayitem(box1, index1, descr2) is box2 h.invalidate_caches(rop.CALL, arraycopydescr1, [None, box3, box2, index1, index1, BoxInt()]) assert h.getarrayitem(box1, index1, descr2) is box2
def test_ll_arraycopy_result_propogated(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) box3 = RefFrontendOp(3) h.setarrayitem(box1, index1, box2, descr1) h.invalidate_caches(rop.CALL_N, arraycopydescr1, [None, box1, box3, index1, index1, index2]) assert h.getarrayitem(box3, index1, descr1) is box2
def test_ll_arraycopy_differing_descrs_nonconst_index(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) box3 = RefFrontendOp(3) h.setarrayitem(box1, index1, box2, descr2) assert h.getarrayitem(box1, index1, descr2) is box2 h.invalidate_caches(rop.CALL_N, arraycopydescr1, [None, box3, box2, index1, index1, InputArgInt()]) assert h.getarrayitem(box1, index1, descr2) is box2
def test_ll_arraycopy_dest_new(self): h = HeapCache() h.new_array(box1, lengthbox1) h.setarrayitem(box3, index1, box4, descr1) h.invalidate_caches( rop.CALL, arraycopydescr1, [None, box2, box1, index1, index1, index2] )
def test_ll_arraycopy_result_propogated(self): h = HeapCache() h.setarrayitem(box1, index1, box2, descr1) h.invalidate_caches( rop.CALL, arraycopydescr1, [None, box1, box3, index1, index1, index2] ) assert h.getarrayitem(box3, index1, descr1) is box2
def test_ll_arraycopy_dest_new(self): h = HeapCache() h.new_array(box1, lengthbox1) h.setarrayitem(box3, index1, box4, descr1) h.invalidate_caches( rop.CALL, FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]), [None, box2, box1, index1, index1, index2] )
def test_ll_arraycopy_result_propogated(self): h = HeapCache() h.setarrayitem(box1, index1, box2, descr1) h.invalidate_caches( rop.CALL, FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]), [None, box1, box3, index1, index1, index2] ) assert h.getarrayitem(box3, index1, descr1) is box2
def test_unescaped(self): h = HeapCache() assert not h.is_unescaped(box1) h.new(box2) assert h.is_unescaped(box2) h.invalidate_caches(rop.SETFIELD_GC, None, [box2, box1]) assert h.is_unescaped(box2) h.invalidate_caches(rop.SETFIELD_GC, None, [box1, box2]) assert not h.is_unescaped(box2)
def test_ll_arraycopy_doesnt_escape_arrays(self): h = HeapCache() h.new_array(box1, lengthbox1) h.new_array(box2, lengthbox2) h.invalidate_caches(rop.CALL, arraycopydescr1, [None, box2, box1, index1, index1, index2]) assert h.is_unescaped(box1) assert h.is_unescaped(box2) h.invalidate_caches(rop.CALL, arraycopydescr1, [None, box2, box1, index1, index1, BoxInt()]) assert not h.is_unescaped(box1) assert not h.is_unescaped(box2)
def test_ll_arraycopy_dest_new(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) box3 = RefFrontendOp(3) box4 = RefFrontendOp(4) lengthbox1 = IntFrontendOp(11) h.new_array(box1, lengthbox1) h.setarrayitem(box3, index1, box4, descr1) h.invalidate_caches(rop.CALL_N, arraycopydescr1, [None, box2, box1, index1, index1, index2])
def test_ll_arraycopy_differing_descrs_nonconst_index(self): h = HeapCache() h.setarrayitem(box1, index1, box2, descr2) assert h.getarrayitem(box1, index1, descr2) is box2 h.invalidate_caches( rop.CALL, arraycopydescr1, [None, box3, box2, index1, index1, BoxInt()] ) assert h.getarrayitem(box1, index1, descr2) is box2
def test_circular_virtuals(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) box3 = RefFrontendOp(3) h.new(box1) h.new(box2) h.invalidate_caches(rop.SETFIELD_GC, None, [box1, box2]) h.invalidate_caches(rop.SETFIELD_GC, None, [box2, box1]) h.invalidate_caches(rop.SETFIELD_GC, None, [box3, box1]) # does not crash
def test_ll_arraycopy_differing_descrs(self): h = HeapCache() h.setarrayitem(box1, index1, box2, descr1) assert h.getarrayitem(box1, index1, descr1) is box2 h.new_array(box2, lengthbox2) h.invalidate_caches( rop.CALL, FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr2]), [None, box3, box2, index1, index1, index2] ) assert h.getarrayitem(box1, index1, descr1) is box2
def test_ll_arraycopy_differing_descrs(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) box3 = RefFrontendOp(3) lengthbox2 = IntFrontendOp(12) h.setarrayitem(box1, index1, box2, descr2) assert h.getarrayitem(box1, index1, descr2) is box2 h.new_array(box2, lengthbox2) h.invalidate_caches(rop.CALL_N, arraycopydescr1, [None, box3, box2, index1, index1, index2]) assert h.getarrayitem(box1, index1, descr2) is box2
def test_ops_dont_escape(self): h = HeapCache() h.new(box1) h.new(box2) assert h.is_unescaped(box1) assert h.is_unescaped(box2) h.invalidate_caches(rop.INSTANCE_PTR_EQ, None, [box1, box2]) assert h.is_unescaped(box1) assert h.is_unescaped(box2) h.invalidate_caches(rop.INSTANCE_PTR_NE, None, [box1, box2]) assert h.is_unescaped(box1) assert h.is_unescaped(box2)
def test_unescaped_array(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) lengthbox1 = IntFrontendOp(11) lengthbox2 = IntFrontendOp(12) h.new_array(box1, lengthbox1) assert h.is_unescaped(box1) h.invalidate_caches(rop.SETARRAYITEM_GC, None, [box1, index1, box2]) assert h.is_unescaped(box1) h.invalidate_caches(rop.SETARRAYITEM_GC, None, [box2, index1, box1]) assert not h.is_unescaped(box1) h = HeapCache() h.new_array(box1, lengthbox1) h.new(box2) assert h.is_unescaped(box1) assert h.is_unescaped(box2) h.invalidate_caches(rop.SETARRAYITEM_GC, None, [box1, lengthbox2, box2]) assert h.is_unescaped(box1) assert h.is_unescaped(box2) h.invalidate_caches( rop.CALL_N, FakeCallDescr(FakeEffectinfo.EF_RANDOM_EFFECTS), [box1] ) assert not h.is_unescaped(box1) assert not h.is_unescaped(box2)
def test_ll_arraycopy_doesnt_escape_arrays(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) lengthbox1 = IntFrontendOp(11) lengthbox2 = IntFrontendOp(12) h.new_array(box1, lengthbox1) h.new_array(box2, lengthbox2) h.invalidate_caches(rop.CALL_N, arraycopydescr1, [None, box2, box1, index1, index1, index2]) assert h.is_unescaped(box1) assert h.is_unescaped(box2) h.invalidate_caches(rop.CALL_N, arraycopydescr1, [None, box2, box1, index1, index1, InputArgInt()]) assert not h.is_unescaped(box1) assert not h.is_unescaped(box2)
def test_bug_heap_cache_is_cleared_but_not_is_unescaped_1(self): # bug if only the getfield() link is cleared (heap_cache) but not # the is_unescaped() flags: we can do later a GETFIELD(box1) which # will give us a fresh box3, which is actually equal to box2. This # box3 is escaped, but box2 is still unescaped. Bug shown e.g. by # calling some residual code that changes the values on box3: then # the content of box2 is still cached at the old value. h = HeapCache() h.new(box1) h.new(box2) h.setfield(box1, box2, descr1) h.invalidate_caches(rop.SETFIELD_GC, None, [box1, box2]) assert h.getfield(box1, descr1) is box2 h.invalidate_caches(rop.CALL_MAY_FORCE, None, []) assert not h.is_unescaped(box1) assert not h.is_unescaped(box2) assert h.getfield(box1, descr1) is None
def test_ll_arraycopy_doesnt_escape_arrays(self): h = HeapCache() h.new_array(box1, lengthbox1) h.new_array(box2, lengthbox2) h.invalidate_caches( rop.CALL, FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]), [None, box2, box1, index1, index1, index2] ) assert h.is_unescaped(box1) assert h.is_unescaped(box2) h.invalidate_caches( rop.CALL, FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]), [None, box2, box1, index1, index1, BoxInt()] ) assert not h.is_unescaped(box1) assert not h.is_unescaped(box2)
def test_quasiimmut_seen(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) box3 = RefFrontendOp(3) box4 = RefFrontendOp(4) assert not h.is_quasi_immut_known(descr1, box1) assert not h.is_quasi_immut_known(descr1, box2) assert not h.is_quasi_immut_known(descr2, box3) assert not h.is_quasi_immut_known(descr2, box4) h.quasi_immut_now_known(descr1, box1) assert h.is_quasi_immut_known(descr1, box1) assert not h.is_quasi_immut_known(descr1, box2) assert not h.is_quasi_immut_known(descr2, box3) assert not h.is_quasi_immut_known(descr2, box4) h.quasi_immut_now_known(descr1, box2) assert h.is_quasi_immut_known(descr1, box1) assert h.is_quasi_immut_known(descr1, box2) assert not h.is_quasi_immut_known(descr2, box3) assert not h.is_quasi_immut_known(descr2, box4) h.quasi_immut_now_known(descr2, box3) assert h.is_quasi_immut_known(descr1, box1) assert h.is_quasi_immut_known(descr1, box2) assert h.is_quasi_immut_known(descr2, box3) assert not h.is_quasi_immut_known(descr2, box4) h.quasi_immut_now_known(descr2, box4) assert h.is_quasi_immut_known(descr1, box1) assert h.is_quasi_immut_known(descr1, box2) assert h.is_quasi_immut_known(descr2, box3) assert h.is_quasi_immut_known(descr2, box4) # invalidate the descr1 cache h.setfield(box1, box3, descr1) assert not h.is_quasi_immut_known(descr1, box1) assert not h.is_quasi_immut_known(descr1, box2) # a call invalidates everything h.invalidate_caches( rop.CALL_N, FakeCallDescr(FakeEffectinfo.EF_CAN_RAISE), []) assert not h.is_quasi_immut_known(descr2, box3) assert not h.is_quasi_immut_known(descr2, box4)
def test_ll_arraycopy(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) box3 = RefFrontendOp(3) box4 = RefFrontendOp(4) box5 = RefFrontendOp(5) lengthbox1 = IntFrontendOp(11) lengthbox2 = IntFrontendOp(12) h.new_array(box1, lengthbox1) h.setarrayitem(box1, index1, box2, descr1) h.new_array(box2, lengthbox1) # Just need the destination box for this call h.invalidate_caches( rop.CALL_N, arraycopydescr1, [None, box5, box2, index1, index1, index1] ) assert h.getarrayitem(box1, index1, descr1) is box2 h.invalidate_caches( rop.CALL_N, arraycopydescr1, [None, box5, box3, index1, index1, index1] ) assert h.getarrayitem(box1, index1, descr1) is box2 h.setarrayitem(box4, index1, box2, descr1) assert h.getarrayitem(box4, index1, descr1) is box2 h.invalidate_caches( rop.CALL_N, arraycopydescr1, [None, box3, box5, index1, index1, index2] ) assert h.getarrayitem(box4, index1, descr1) is None
def test_ll_arraycopy(self): h = HeapCache() h.new_array(box1, lengthbox1) h.setarrayitem(box1, index1, box2, descr1) h.new_array(box2, lengthbox1) # Just need the destination box for this call h.invalidate_caches( rop.CALL, arraycopydescr1, [None, box5, box2, index1, index1, index1] ) assert h.getarrayitem(box1, index1, descr1) is box2 h.invalidate_caches( rop.CALL, arraycopydescr1, [None, box5, box3, index1, index1, index1] ) assert h.getarrayitem(box1, index1, descr1) is box2 h.setarrayitem(box4, index1, box2, descr1) assert h.getarrayitem(box4, index1, descr1) is box2 h.invalidate_caches( rop.CALL, arraycopydescr1, [None, box3, box5, index1, index1, index2] ) assert h.getarrayitem(box4, index1, descr1) is None
def test_ll_arraycopy(self): h = HeapCache() h.new_array(box1, lengthbox1) h.setarrayitem(box1, index1, box2, descr1) h.new_array(box2, lengthbox1) # Just need the destination box for this call h.invalidate_caches( rop.CALL, FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]), [None, box5, box2, index1, index1, index1] ) assert h.getarrayitem(box1, index1, descr1) is box2 h.invalidate_caches( rop.CALL, FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]), [None, box5, box3, index1, index1, index1] ) assert h.getarrayitem(box1, index1, descr1) is box2 h.setarrayitem(box4, index1, box2, descr1) assert h.getarrayitem(box4, index1, descr1) is box2 h.invalidate_caches( rop.CALL, FakeCallDescr(FakeEffectinfo.EF_CANNOT_RAISE, FakeEffectinfo.OS_ARRAYCOPY, write_descrs_arrays=[descr1]), [None, box3, box5, index1, index1, index2] ) assert h.getarrayitem(box4, index1, descr1) is None
def test_unescaped_testing(self): h = HeapCache() h.new(box1) h.new(box2) assert h.is_unescaped(box1) assert h.is_unescaped(box2) # Putting a virtual inside of another virtual doesn't escape it. h.invalidate_caches(rop.SETFIELD_GC, None, [box1, box2]) assert h.is_unescaped(box2) # Reading a field from a virtual doesn't escape it. h.invalidate_caches(rop.GETFIELD_GC, None, [box1]) assert h.is_unescaped(box1) # Escaping a virtual transitively escapes anything inside of it. assert not h.is_unescaped(box3) h.invalidate_caches(rop.SETFIELD_GC, None, [box3, box1]) assert not h.is_unescaped(box1) assert not h.is_unescaped(box2)
def test_invalidate_cache(self): h = HeapCache() h.setfield(box1, box2, descr1) h.setarrayitem(box1, index1, box2, descr1) h.setarrayitem(box1, index2, box4, descr1) h.invalidate_caches(rop.INT_ADD, None, []) h.invalidate_caches(rop.INT_ADD_OVF, None, []) h.invalidate_caches(rop.SETFIELD_RAW, None, []) h.invalidate_caches(rop.SETARRAYITEM_RAW, None, []) assert h.getfield(box1, descr1) is box2 assert h.getarrayitem(box1, index1, descr1) is box2 assert h.getarrayitem(box1, index2, descr1) is box4 h.invalidate_caches( rop.CALL, FakeCallDescr(FakeEffectinfo.EF_ELIDABLE_CANNOT_RAISE), []) assert h.getfield(box1, descr1) is box2 assert h.getarrayitem(box1, index1, descr1) is box2 assert h.getarrayitem(box1, index2, descr1) is box4 h.invalidate_caches(rop.GUARD_TRUE, None, []) assert h.getfield(box1, descr1) is box2 assert h.getarrayitem(box1, index1, descr1) is box2 assert h.getarrayitem(box1, index2, descr1) is box4 h.invalidate_caches( rop.CALL_LOOPINVARIANT, FakeCallDescr(FakeEffectinfo.EF_LOOPINVARIANT), []) h.invalidate_caches( rop.CALL, FakeCallDescr(FakeEffectinfo.EF_RANDOM_EFFECTS), []) assert h.getfield(box1, descr1) is None assert h.getarrayitem(box1, index1, descr1) is None assert h.getarrayitem(box1, index2, descr1) is None
def test_bug_missing_ignored_operations(self): h = HeapCache() box1 = RefFrontendOp(1) box2 = RefFrontendOp(2) h.new(box1) h.new(box2) h.setfield(box1, box2, descr1) assert h.getfield(box1, descr1) is box2 h.invalidate_caches(rop.STRSETITEM, None, []) h.invalidate_caches(rop.UNICODESETITEM, None, []) h.invalidate_caches(rop.SETFIELD_RAW, None, []) h.invalidate_caches(rop.SETARRAYITEM_RAW, None, []) h.invalidate_caches(rop.SETINTERIORFIELD_RAW, None, []) h.invalidate_caches(rop.RAW_STORE, None, []) assert h.is_unescaped(box1) assert h.is_unescaped(box2) assert h.getfield(box1, descr1) is box2
def test_bug_missing_ignored_operations(self): h = HeapCache() h.new(box1) h.new(box2) h.setfield(box1, box2, descr1) assert h.getfield(box1, descr1) is box2 h.invalidate_caches(rop.STRSETITEM, None, []) h.invalidate_caches(rop.UNICODESETITEM, None, []) h.invalidate_caches(rop.SETFIELD_RAW, None, []) h.invalidate_caches(rop.SETARRAYITEM_RAW, None, []) h.invalidate_caches(rop.SETINTERIORFIELD_RAW, None, []) h.invalidate_caches(rop.RAW_STORE, None, []) assert h.is_unescaped(box1) assert h.is_unescaped(box2) assert h.getfield(box1, descr1) is box2