Author: Armin Rigo <[email protected]>
Branch: heapcache-refactor
Changeset: r83109:4ed062f45f76
Date: 2016-03-17 15:31 +0100
http://bitbucket.org/pypy/pypy/changeset/4ed062f45f76/

Log:    replace_box(), limited version (enough to support almost all cases
        that pyjitpl calls it with)

diff --git a/rpython/jit/metainterp/heapcache.py 
b/rpython/jit/metainterp/heapcache.py
--- a/rpython/jit/metainterp/heapcache.py
+++ b/rpython/jit/metainterp/heapcache.py
@@ -1,5 +1,8 @@
-from rpython.jit.metainterp.history import ConstInt, RefFrontendOp
+from rpython.jit.metainterp.history import Const, ConstInt
+from rpython.jit.metainterp.history import FrontendOp, RefFrontendOp
+from rpython.jit.metainterp.history import FO_REPLACED_WITH_CONST
 from rpython.jit.metainterp.resoperation import rop, OpHelpers
+from rpython.jit.metainterp.executor import constant_from_op
 from rpython.rlib.rarithmetic import r_uint32, r_uint
 from rpython.rlib.objectmodel import always_inline
 
@@ -12,23 +15,32 @@
 HF_IS_UNESCAPED    = 0x10
 HF_NONSTD_VABLE    = 0x20
 
+_HF_VERSION_INC    = 0x40   # must be last
+_HF_VERSION_MAX    = r_uint(2 ** 32 - _HF_VERSION_INC)
+
 @always_inline
 def add_flags(ref_frontend_op, flags):
-    f = r_uint(ref_frontend_op._heapc_flags)
+    f = ref_frontend_op._get_heapc_flags()
     f |= r_uint(flags)
-    ref_frontend_op._heapc_flags = r_uint32(f)
+    ref_frontend_op._set_heapc_flags(f)
 
 @always_inline
 def remove_flags(ref_frontend_op, flags):
-    f = r_uint(ref_frontend_op._heapc_flags)
+    f = ref_frontend_op._get_heapc_flags()
     f &= r_uint(~flags)
-    ref_frontend_op._heapc_flags = r_uint32(f)
+    ref_frontend_op._set_heapc_flags(f)
 
 @always_inline
 def test_flags(ref_frontend_op, flags):
-    f = r_uint(ref_frontend_op._heapc_flags)
+    f = ref_frontend_op._get_heapc_flags()
     return bool(f & r_uint(flags))
 
+def maybe_replace_with_const(box):
+    if box.is_replaced_with_const():
+        return constant_from_op(box)
+    else:
+        return box
+
 
 class CacheEntry(object):
     def __init__(self, heapcache):
@@ -62,7 +74,12 @@
         self._getdict(seen_alloc)[ref_box] = fieldbox
 
     def read(self, ref_box):
-        return self._getdict(self._seen_alloc(ref_box)).get(ref_box, None)
+        dict = self._getdict(self._seen_alloc(ref_box))
+        try:
+            res_box = dict[ref_box]
+        except KeyError:
+            return None
+        return maybe_replace_with_const(res_box)
 
     def read_now_known(self, ref_box, fieldbox):
         self._getdict(self._seen_alloc(ref_box))[ref_box] = fieldbox
@@ -98,7 +115,7 @@
         # to use a version number in each RefFrontendOp, and in order
         # to reset the flags globally, we increment the global version
         # number in this class.  Then when we read '_heapc_flags' we
-        # also check if the associated '_heapc_version' is up-to-date
+        # also check if the associated version number is up-to-date
         # or not.  More precisely, we have two global version numbers
         # here: 'head_version' and 'likely_virtual_version'.  Normally
         # we use 'head_version'.  For is_likely_virtual() though, we
@@ -110,7 +127,8 @@
     def reset(self):
         # Global reset of all flags.  Update both version numbers so
         # that any access to '_heapc_flags' will be marked as outdated.
-        self.head_version += 1
+        assert self.head_version < _HF_VERSION_MAX
+        self.head_version += _HF_VERSION_INC
         self.likely_virtual_version = self.head_version
         #
         # maps boxes to HeapCacheValue
@@ -125,7 +143,8 @@
     def reset_keep_likely_virtuals(self):
         # Update only 'head_version', but 'likely_virtual_version' remains
         # at its older value.
-        self.head_version += 1
+        assert self.head_version < _HF_VERSION_MAX
+        self.head_version += _HF_VERSION_INC
         #
         for value in self.values.itervalues():
             value.reset_keep_likely_virtual()
@@ -134,32 +153,21 @@
 
     @always_inline
     def test_head_version(self, ref_frontend_op):
-        return r_uint(ref_frontend_op._heapc_version) == self.head_version
+        return ref_frontend_op._get_heapc_flags() >= self.head_version
 
     @always_inline
     def test_likely_virtual_version(self, ref_frontend_op):
-        return (r_uint(ref_frontend_op._heapc_version) >=
-                self.likely_virtual_version)
+        return ref_frontend_op._get_heapc_flags() >= 
self.likely_virtual_version
 
     def update_version(self, ref_frontend_op):
         if not self.test_head_version(ref_frontend_op):
-            f = 0
+            f = self.head_version
             if (self.test_likely_virtual_version(ref_frontend_op) and
                 test_flags(ref_frontend_op, HF_LIKELY_VIRTUAL)):
                 f |= HF_LIKELY_VIRTUAL
-            ref_frontend_op._heapc_flags = r_uint32(f)
-            ref_frontend_op._heapc_version = r_uint32(self.head_version)
+            ref_frontend_op._set_heapc_flags(f)
             ref_frontend_op._heapc_deps = None
 
-    def getvalue(self, box, create=True):
-        value = self.values.get(box, None)
-        if not value and create:
-            value = self.values[box] = HeapCacheValue(box)
-        return value
-
-    def getvalues(self, boxes):
-        return [self.getvalue(box) for box in boxes]
-
     def invalidate_caches(self, opnum, descr, argboxes):
         self.mark_escaped(opnum, descr, argboxes)
         self.clear_caches(opnum, descr, argboxes)
@@ -434,7 +442,9 @@
         if (isinstance(box, RefFrontendOp) and
             self.test_head_version(box) and
             box._heapc_deps is not None):
-            return box._heapc_deps[0]
+            res_box = box._heapc_deps[0]
+            if res_box is not None:
+                return maybe_replace_with_const(res_box)
         return None
 
     def arraylen_now_known(self, box, lengthbox):
@@ -446,8 +456,7 @@
         deps[0] = lengthbox
 
     def replace_box(self, oldbox, newbox):
-        value = self.getvalue(oldbox, create=False)
-        if value is None:
-            return
-        value.box = newbox
-        self.values[newbox] = value
+        # here, only for replacing a box with a const
+        if isinstance(oldbox, FrontendOp) and isinstance(newbox, Const):
+            assert newbox.same_constant(constant_from_op(oldbox))
+            oldbox.set_replaced_with_const()
diff --git a/rpython/jit/metainterp/history.py 
b/rpython/jit/metainterp/history.py
--- a/rpython/jit/metainterp/history.py
+++ b/rpython/jit/metainterp/history.py
@@ -2,7 +2,8 @@
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
 from rpython.rlib.objectmodel import we_are_translated, Symbolic
 from rpython.rlib.objectmodel import compute_unique_id, specialize
-from rpython.rlib.rarithmetic import r_uint32, r_int64, is_valid_int
+from rpython.rlib.rarithmetic import r_int64, is_valid_int
+from rpython.rlib.rarithmetic import LONG_BIT, intmask, r_uint
 
 from rpython.conftest import option
 
@@ -641,42 +642,66 @@
 # ____________________________________________________________
 
 
+FO_POSITION_MASK       = r_uint(0x7FFFFFFF)
+FO_REPLACED_WITH_CONST = r_uint(0x80000000)
+
+
 class FrontendOp(AbstractResOp):
     type = 'v'
-    _attrs_ = ('position',)
+    _attrs_ = ('position_and_flags',)
 
     def __init__(self, pos):
-        self.position = pos
+        assert pos >= 0
+        self.position_and_flags = r_uint(pos)
 
     def get_position(self):
-        return self.position
+        return intmask(self.position_and_flags & FO_POSITION_MASK)
+
+    def is_replaced_with_const(self):
+        return bool(self.position_and_flags & FO_REPLACED_WITH_CONST)
+
+    def set_replaced_with_const(self):
+        self.position_and_flags |= FO_REPLACED_WITH_CONST
 
     def __repr__(self):
         return '%s(%s)' % (self.__class__.__name__, self.position)
 
 class IntFrontendOp(IntOp, FrontendOp):
-    _attrs_ = ('position', '_resint')
+    _attrs_ = ('position_and_flags', '_resint')
 
     def copy_value_from(self, other):
         self._resint = other.getint()
 
 class FloatFrontendOp(FloatOp, FrontendOp):
-    _attrs_ = ('position', '_resfloat')
+    _attrs_ = ('position_and_flags', '_resfloat')
 
     def copy_value_from(self, other):
         self._resfloat = other.getfloatstorage()
 
 class RefFrontendOp(RefOp, FrontendOp):
-    _attrs_ = ('position', '_resref',
-               '_heapc_flags', '_heapc_version', '_heapc_deps')
-
-    _heapc_flags = r_uint32(0)
-    _heapc_version = r_uint32(0)
+    _attrs_ = ('position_and_flags', '_resref', '_heapc_deps')
+    if LONG_BIT == 32:
+        _attrs_ += ('_heapc_flags',)   # on 64 bit, this gets stored into the
+        _heapc_flags = r_uint(0)       # high 32 bits of 'position_and_flags'
     _heapc_deps = None
 
     def copy_value_from(self, other):
         self._resref = other.getref_base()
 
+    if LONG_BIT == 32:
+        def _get_heapc_flags(self):
+            return self._heapc_flags
+        def _set_heapc_flags(self, value):
+            self._heapc_flags = value
+    else:
+        def _get_heapc_flags(self):
+            return self.position_and_flags >> 32
+        def _set_heapc_flags(self, value):
+            self.position_and_flags = (
+                (self.position_and_flags & 0xFFFFFFFF) |
+                (value << 32))
+
+
 class History(object):
     ends_with_jump = False
     trace = None
diff --git a/rpython/jit/metainterp/test/test_heapcache.py 
b/rpython/jit/metainterp/test/test_heapcache.py
--- a/rpython/jit/metainterp/test/test_heapcache.py
+++ b/rpython/jit/metainterp/test/test_heapcache.py
@@ -1,11 +1,9 @@
+import py
 from rpython.jit.metainterp.heapcache import HeapCache
 from rpython.jit.metainterp.resoperation import rop, InputArgInt
-from rpython.jit.metainterp.history import ConstInt, BasicFailDescr
-from rpython.jit.metainterp.history import RefFrontendOp
+from rpython.jit.metainterp.history import ConstInt, ConstPtr, BasicFailDescr
+from rpython.jit.metainterp.history import IntFrontendOp, RefFrontendOp
 
-lengthbox1 = object()
-lengthbox2 = object()
-lengthbox3 = object()
 descr1 = object()
 descr2 = object()
 descr3 = object()
@@ -304,6 +302,8 @@
         h = HeapCache()
         box1 = RefFrontendOp(1)
         box2 = RefFrontendOp(2)
+        lengthbox1 = IntFrontendOp(11)
+        lengthbox2 = IntFrontendOp(12)
         h.new_array(box1, lengthbox1)
         assert h.arraylen(box1) is lengthbox1
 
@@ -348,8 +348,13 @@
         assert h.getarrayitem(box1, index1, descr1) is None
         assert h.getarrayitem(box1, index2, descr1) is None
 
-    def test_replace_box(self):
+    def test_replace_box_with_box(self):
+        py.test.skip("replacing a box with another box: not supported any 
more")
         h = HeapCache()
+        box1 = RefFrontendOp(1)
+        box2 = RefFrontendOp(2)
+        box3 = RefFrontendOp(3)
+        box4 = RefFrontendOp(4)
         h.setfield(box1, box2, descr1)
         h.setfield(box1, box3, descr2)
         h.setfield(box2, box3, descr3)
@@ -360,16 +365,22 @@
         h.setfield(box4, box3, descr1)
         assert h.getfield(box4, descr1) is box3
 
+    def test_replace_box_with_const(self):
         h = HeapCache()
+        box1 = RefFrontendOp(1)
+        box2 = RefFrontendOp(2)
+        box3 = RefFrontendOp(3)
+        c_box3 = ConstPtr(ConstPtr.value)
         h.setfield(box1, box2, descr1)
         h.setfield(box1, box3, descr2)
         h.setfield(box2, box3, descr3)
-        h.replace_box(box3, box4)
+        h.replace_box(box3, c_box3)
         assert h.getfield(box1, descr1) is box2
-        assert h.getfield(box1, descr2) is box4
-        assert h.getfield(box2, descr3) is box4
+        assert c_box3.same_constant(h.getfield(box1, descr2))
+        assert c_box3.same_constant(h.getfield(box2, descr3))
 
     def test_replace_box_twice(self):
+        py.test.skip("replacing a box with another box: not supported any 
more")
         h = HeapCache()
         h.setfield(box1, box2, descr1)
         h.setfield(box1, box3, descr2)
@@ -393,6 +404,7 @@
         assert h.getfield(box2, descr3) is box5
 
     def test_replace_box_array(self):
+        py.test.skip("replacing a box with another box: not supported any 
more")
         h = HeapCache()
         h.setarrayitem(box1, index1, box2, descr1)
         h.setarrayitem(box1, index1, box3, descr2)
@@ -412,6 +424,7 @@
         assert h.arraylen(box4) is lengthbox2
 
     def test_replace_box_array_twice(self):
+        py.test.skip("replacing a box with another box: not supported any 
more")
         h = HeapCache()
         h.setarrayitem(box1, index1, box2, descr1)
         h.setarrayitem(box1, index1, box3, descr2)
@@ -432,6 +445,25 @@
         h.replace_box(lengthbox2, lengthbox3)
         assert h.arraylen(box4) is lengthbox3
 
+    def test_replace_box_with_const_in_array(self):
+        h = HeapCache()
+        box1 = RefFrontendOp(1)
+        lengthbox2 = IntFrontendOp(2)
+        lengthbox2.setint(10)
+        h.arraylen_now_known(box1, lengthbox2)
+        assert h.arraylen(box1) is lengthbox2
+        c10 = ConstInt(10)
+        h.replace_box(lengthbox2, c10)
+        assert c10.same_constant(h.arraylen(box1))
+
+        box2 = IntFrontendOp(2)
+        box2.setint(12)
+        h.setarrayitem(box1, index2, box2, descr1)
+        assert h.getarrayitem(box1, index2, descr1) is box2
+        c12 = ConstInt(12)
+        h.replace_box(box2, c12)
+        assert c12.same_constant(h.getarrayitem(box1, index2, descr1))
+
     def test_ll_arraycopy(self):
         h = HeapCache()
         h.new_array(box1, lengthbox1)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to