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