Author: Armin Rigo <[email protected]>
Branch: optresult-unroll
Changeset: r79500:6da38340bd1a
Date: 2015-09-07 12:11 +0200
http://bitbucket.org/pypy/pypy/changeset/6da38340bd1a/
Log: Add and test cpu.check_is_object() and cpu.get_actual_typeid(), to
constant-fold guard_is_object and guard_gc_type.
diff --git a/rpython/jit/backend/llgraph/runner.py
b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -517,6 +517,22 @@
self.descrs[key] = descr
return descr
+ def check_is_object(self, gcptr):
+ """Check if the given, non-null gcptr refers to an rclass.OBJECT
+ or not at all (an unrelated GcStruct or a GcArray). Only usable
+ in the llgraph backend, or after translation of a real backend."""
+ ptr = lltype.normalizeptr(gcptr._obj.container._as_ptr())
+ T = lltype.typeOf(ptr).TO
+ return heaptracker.has_gcstruct_a_vtable(T) or T is rclass.OBJECT
+
+ def get_actual_typeid(self, gcptr):
+ """Fetch the actual typeid of the given gcptr, as an integer.
+ Only usable in the llgraph backend, or after translation of a
+ real backend. (Here in the llgraph backend, returns a
+ TypeIDSymbolic instead of a real integer.)"""
+ ptr = lltype.normalizeptr(gcptr._obj.container._as_ptr())
+ return TypeIDSymbolic(lltype.typeOf(ptr).TO)
+
# ------------------------------------------------------------
def maybe_on_top_of_llinterp(self, func, args, RESULT):
diff --git a/rpython/jit/backend/llsupport/gc.py
b/rpython/jit/backend/llsupport/gc.py
--- a/rpython/jit/backend/llsupport/gc.py
+++ b/rpython/jit/backend/llsupport/gc.py
@@ -725,6 +725,24 @@
infobits_offset += self._infobits_offset_plus
return (infobits_offset, self._T_IS_RPYTHON_INSTANCE_BYTE)
+ def get_actual_typeid(self, gcptr):
+ # Read the whole GC header word. The typeid is the lower half-word.
+ hdr = rffi.cast(self.HDRPTR, gcptr)
+ type_id = llop.extract_ushort(llgroup.HALFWORD, hdr.tid)
+ return llop.combine_ushort(lltype.Signed, type_id, 0)
+
+ def check_is_object(self, gcptr):
+ # read the typeid, fetch one byte of the field 'infobits' from
+ # the big typeinfo table, and check the flag 'T_IS_RPYTHON_INSTANCE'.
+ typeid = self.get_actual_typeid(gcptr)
+ #
+ base_type_info, shift_by, sizeof_ti = (
+ self.get_translated_info_for_typeinfo())
+ infobits_offset, IS_OBJECT_FLAG = (
+ self.get_translated_info_for_guard_is_object())
+ p = base_type_info + (typeid << shift_by) + infobits_offset
+ p = rffi.cast(rffi.CCHARP, p)
+ return (ord(p[0]) & IS_OBJECT_FLAG) != 0
# ____________________________________________________________
diff --git a/rpython/jit/backend/llsupport/llmodel.py
b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -480,8 +480,24 @@
descrs = self.gc_ll_descr.getframedescrs(self)
base_ofs = self.unpack_arraydescr(descrs.arraydescr)
return base_ofs
+
# ____________________________________________________________
+ def check_is_object(self, gcptr):
+ """Check if the given, non-null gcptr refers to an rclass.OBJECT
+ or not at all (an unrelated GcStruct or a GcArray). Only usable
+ in the llgraph backend, or after translation of a real backend."""
+ assert self.supports_guard_gc_type
+ return self.gc_ll_descr.check_is_object(gcptr)
+
+ def get_actual_typeid(self, gcptr):
+ """Fetch the actual typeid of the given gcptr, as an integer.
+ Only usable in the llgraph backend, or after translation of a
+ real backend."""
+ assert self.supports_guard_gc_type
+ return self.gc_ll_descr.get_actual_typeid(gcptr)
+
+ # ____________________________________________________________
def bh_arraylen_gc(self, array, arraydescr):
assert isinstance(arraydescr, ArrayDescr)
diff --git a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py
b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py
--- a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py
+++ b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py
@@ -117,6 +117,11 @@
print 'fail'
else:
print '???'
+ #
+ if token is token2: # guard_gc_type
+ print int(cpu.get_actual_typeid(p0) == typeid_B)
+ if token is token3: # guard_is_object
+ print int(cpu.check_is_object(p0))
call_initial_function(t, g)
@@ -129,14 +134,14 @@
'match\n'
'fail\n'
- 'fail\n'
- 'match\n'
- 'fail\n'
- 'fail\n'
+ 'fail\n' '0\n'
+ 'match\n' '1\n'
+ 'fail\n' '0\n'
+ 'fail\n' '0\n'
- 'match\n'
- 'match\n'
- 'fail\n'
+ 'match\n' '1\n'
+ 'match\n' '1\n'
+ 'fail\n' '0\n'
'fail\n'
'match\n'
diff --git a/rpython/jit/backend/test/runner_test.py
b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -4888,6 +4888,9 @@
c_typeid = ConstInt(descr.get_type_id())
self.execute_operation(rop.GUARD_GC_TYPE, [t_box, c_typeid], 'void')
assert not self.guard_failed
+ #
+ got_typeid = self.cpu.get_actual_typeid(t_box.getref_base())
+ assert got_typeid == c_typeid.getint()
def test_passing_guard_gc_type_array(self):
if not self.cpu.supports_guard_gc_type:
@@ -4897,6 +4900,9 @@
c_typeid = ConstInt(arraydescr.get_type_id())
self.execute_operation(rop.GUARD_GC_TYPE, [a_box, c_typeid], 'void')
assert not self.guard_failed
+ #
+ got_typeid = self.cpu.get_actual_typeid(a_box.getref_base())
+ assert got_typeid == c_typeid.getint()
def test_failing_guard_gc_type(self):
if not self.cpu.supports_guard_gc_type:
@@ -4915,23 +4921,29 @@
]:
assert self.execute_operation(opname, args, 'void') == None
assert self.guard_failed
+ #
+ got_typeid = self.cpu.get_actual_typeid(args[0].getref_base())
+ assert got_typeid != args[1].getint()
def test_guard_is_object(self):
if not self.cpu.supports_guard_gc_type:
py.test.skip("guard_gc_type not available")
t_box, _, _ = self.alloc_instance(self.T)
self.execute_operation(rop.GUARD_IS_OBJECT, [t_box], 'void')
+ assert not self.guard_failed
+ assert self.cpu.check_is_object(t_box.getref_base())
#
- assert not self.guard_failed
a_box, _ = self.alloc_array_of(rffi.SHORT, 342)
self.execute_operation(rop.GUARD_IS_OBJECT, [a_box], 'void')
assert self.guard_failed
+ assert not self.cpu.check_is_object(a_box.getref_base())
#
S = lltype.GcStruct('S')
s = lltype.malloc(S, immortal=True, zero=True)
s_box = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, s))
self.execute_operation(rop.GUARD_IS_OBJECT, [s_box], 'void')
assert self.guard_failed
+ assert not self.cpu.check_is_object(s_box.getref_base())
def test_guard_subclass(self):
if not self.cpu.supports_guard_gc_type:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit