[pypy-svn] pypy out-of-line-guards-2: Progress on out-of-line-guards-2. This is the poor-man's version, we can do
fijal
commits-noreply at bitbucket.org
Wed Apr 13 14:18:17 CEST 2011
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: out-of-line-guards-2
Changeset: r43327:6d4d86899596
Date: 2011-04-13 14:17 +0200
http://bitbucket.org/pypy/pypy/changeset/6d4d86899596/
Log: Progress on out-of-line-guards-2. This is the poor-man's version, we
can do better.
* Record a guard on each of quasi_immutable_fields
* This guard fails if the loop is invalidated (only llgraph backend so
far)
* It creates a normal bridge. This is the point where we can improve
by invalidating call assemblers for example and resetting counters
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -80,6 +80,7 @@
if loop.quasi_immutable_deps is not None:
for qmut in loop.quasi_immutable_deps:
qmut.register_loop_token(wref)
+ # XXX maybe we should clear the dictionary here
# mostly for tests: make sure we don't keep a reference to the LoopToken
loop.token = None
if not we_are_translated():
@@ -400,6 +401,12 @@
self.copy_all_attributes_into(res)
return res
+class ResumeGuardNotInvalidated(ResumeGuardDescr):
+ def _clone_if_mutable(self):
+ res = ResumeGuardNotInvalidated()
+ self.copy_all_attributes_into(res)
+ return res
+
class ResumeAtPositionDescr(ResumeGuardDescr):
def _clone_if_mutable(self):
res = ResumeAtPositionDescr()
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -286,6 +286,10 @@
raise ValueError("CALL_ASSEMBLER not supported")
llimpl.redirect_call_assembler(self, oldlooptoken, newlooptoken)
+ def invalidate_loop(self, looptoken):
+ for loop in looptoken.compiled_loop_token.loop_and_bridges:
+ loop._obj.externalobj.invalid = True
+
# ----------
def sizeof(self, S):
diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/test/test_optimizeutil.py
--- a/pypy/jit/metainterp/test/test_optimizeutil.py
+++ b/pypy/jit/metainterp/test/test_optimizeutil.py
@@ -3,6 +3,7 @@
from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr
from pypy.rpython.ootypesystem import ootype
from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
+from pypy.rpython.rclass import FieldListAccessor, IR_QUASI_IMMUTABLE
from pypy.jit.backend.llgraph import runner
from pypy.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr,
@@ -12,6 +13,7 @@
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.codewriter.heaptracker import register_known_gctype, adr2int
from pypy.jit.tool.oparser import parse
+from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr
def test_sort_descrs():
class PseudoDescr(AbstractDescr):
@@ -62,6 +64,18 @@
nextdescr = cpu.fielddescrof(NODE, 'next')
otherdescr = cpu.fielddescrof(NODE2, 'other')
+ accessor = FieldListAccessor()
+ accessor.initialize(None, {'inst_field': IR_QUASI_IMMUTABLE})
+ QUASI = lltype.GcStruct('QUASIIMMUT', ('inst_field', lltype.Signed),
+ ('mutate_field', rclass.OBJECTPTR),
+ hints={'immutable_fields': accessor})
+ quasi = lltype.malloc(QUASI, immortal=True)
+ quasifielddescr = cpu.fielddescrof(QUASI, 'inst_field')
+ quasibox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, quasi))
+ quasiimmutdescr = QuasiImmutDescr(cpu, quasibox,
+ quasifielddescr,
+ cpu.fielddescrof(QUASI, 'mutate_field'))
+
NODEOBJ = lltype.GcStruct('NODEOBJ', ('parent', OBJECT),
('ref', lltype.Ptr(OBJECT)))
nodeobj = lltype.malloc(NODEOBJ)
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -555,14 +555,15 @@
opimpl_setfield_raw_r = _opimpl_setfield_raw_any
opimpl_setfield_raw_f = _opimpl_setfield_raw_any
- @arguments("box", "descr", "descr")
+ @arguments("box", "descr", "descr", "orgpc")
def opimpl_record_quasiimmut_field(self, box, fielddescr,
- mutatefielddescr):
+ mutatefielddescr, orgpc):
from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr
cpu = self.metainterp.cpu
descr = QuasiImmutDescr(cpu, box, fielddescr, mutatefielddescr)
self.metainterp.history.record(rop.QUASIIMMUT_FIELD, [box],
None, descr=descr)
+ self.generate_guard(rop.GUARD_NOT_INVALIDATED, resumepc=orgpc)
def _nonstandard_virtualizable(self, pc, box):
# returns True if 'box' is actually not the "standard" virtualizable
@@ -1085,6 +1086,8 @@
if opnum == rop.GUARD_NOT_FORCED:
resumedescr = compile.ResumeGuardForcedDescr(metainterp_sd,
metainterp.jitdriver_sd)
+ elif opnum == rop.GUARD_NOT_INVALIDATED:
+ resumedescr = compile.ResumeGuardNotInvalidated()
else:
resumedescr = compile.ResumeGuardDescr()
guard_op = metainterp.history.record(opnum, moreargs, None,
@@ -1857,6 +1860,9 @@
self.handle_possible_exception()
except ChangeFrame:
pass
+ elif opnum == rop.GUARD_NOT_INVALIDATED:
+ pass # XXX we want to do something special in resume descr,
+ # but not now
elif opnum == rop.GUARD_NO_OVERFLOW: # an overflow now detected
self.execute_raised(OverflowError(), constant=True)
try:
diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py
--- a/pypy/jit/codewriter/test/test_jtransform.py
+++ b/pypy/jit/codewriter/test/test_jtransform.py
@@ -960,7 +960,7 @@
op = SpaceOperation('getfield', [v_x, Constant('inst_x', lltype.Void)],
v2)
tr = Transformer(FakeCPU())
- [op1, op2] = tr.rewrite_operation(op)
+ [_, op1, op2] = tr.rewrite_operation(op)
assert op1.opname == 'record_quasiimmut_field'
assert len(op1.args) == 3
assert op1.args[0] == v_x
diff --git a/pypy/jit/metainterp/test/test_quasiimmut.py b/pypy/jit/metainterp/test/test_quasiimmut.py
--- a/pypy/jit/metainterp/test/test_quasiimmut.py
+++ b/pypy/jit/metainterp/test/test_quasiimmut.py
@@ -1,3 +1,6 @@
+
+import py
+
from pypy.rpython.lltypesystem import lltype, llmemory, rclass
from pypy.rpython.rclass import FieldListAccessor, IR_QUASI_IMMUTABLE
from pypy.jit.metainterp import typesystem
diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -119,6 +119,7 @@
self._lazy_setfields = []
# cached array items: {descr: CachedArrayItems}
self.cached_arrayitems = {}
+ self._remove_guard_not_invalidated = False
def reconstruct_for_next_iteration(self, optimizer, valuemap):
new = OptHeap()
@@ -386,6 +387,7 @@
# constant-fold the following getfield_gc.
structvalue = self.getvalue(op.getarg(0))
if not structvalue.is_constant():
+ self._remove_guard_not_invalidated = True
return # not a constant at all; ignore QUASIIMMUT_FIELD
#
from pypy.jit.metainterp.quasiimmut import QuasiImmutDescr
@@ -396,6 +398,7 @@
# simply ignoring the QUASIIMMUT_FIELD hint and compiling it
# as a regular getfield.
if not qmutdescr.is_still_valid():
+ self._remove_guard_not_invalidated = True
return
# record as an out-of-line guard
if self.optimizer.quasi_immutable_deps is None:
@@ -405,6 +408,13 @@
fieldvalue = self.getvalue(qmutdescr.constantfieldbox)
cf = self.field_cache(qmutdescr.fielddescr)
cf.remember_field_value(structvalue, fieldvalue)
+ self._remove_guard_not_invalidated = False
+
+ def optimize_GUARD_NOT_INVALIDATED(self, op):
+ if self._remove_guard_not_invalidated:
+ return
+ self._remove_guard_not_invalidated = False
+ self.emit_operation(op)
def propagate_forward(self, op):
opnum = op.getopnum()
diff --git a/pypy/jit/metainterp/quasiimmut.py b/pypy/jit/metainterp/quasiimmut.py
--- a/pypy/jit/metainterp/quasiimmut.py
+++ b/pypy/jit/metainterp/quasiimmut.py
@@ -81,9 +81,7 @@
for wref in wrefs:
looptoken = wref()
if looptoken is not None:
- pass
- #
- # XXX tell the backend to mark the loop as invalid
+ self.cpu.invalidate_loop(looptoken)
class QuasiImmutDescr(AbstractDescr):
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -1292,6 +1292,8 @@
# We get here because it used to overflow, but now it no longer
# does.
pass
+ elif opnum == rop.GUARD_NOT_INVALIDATED:
+ pass
else:
from pypy.jit.metainterp.resoperation import opname
raise NotImplementedError(opname[opnum])
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -583,7 +583,8 @@
descr1 = self.cpu.fielddescrof(
v_inst.concretetype.TO,
quasiimmut.get_mutate_field_name(c_fieldname.value))
- op1 = [SpaceOperation('record_quasiimmut_field',
+ op1 = [SpaceOperation('-live-', [], None),
+ SpaceOperation('record_quasiimmut_field',
[v_inst, descr, descr1], None),
op1]
return op1
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -167,6 +167,7 @@
class CompiledLoop(object):
has_been_freed = False
+ invalid = False
def __init__(self):
self.inputargs = []
@@ -933,6 +934,9 @@
if forced:
raise GuardFailed
+ def op_guard_not_invalidated(self, descr):
+ if self.loop.invalid:
+ raise GuardFailed
class OOFrame(Frame):
diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/test/test_optimizeopt.py
@@ -5702,8 +5702,35 @@
# not obvious, because of the exception UnicodeDecodeError that
# can be raised by ll_str2unicode()
-
-
+ def test_quasi_immut(self):
+ ops = """
+ [p0, p1, i0]
+ quasiimmut_field(p0, descr=quasiimmutdescr)
+ guard_not_invalidated() []
+ i1 = getfield_gc(p0, descr=quasifielddescr)
+ jump(p1, p0, i1)
+ """
+ expected = """
+ [p0, p1, i0]
+ i1 = getfield_gc(p0, descr=quasifielddescr)
+ jump(p1, p0, i1)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_quasi_immut_2(self):
+ ops = """
+ []
+ quasiimmut_field(ConstPtr(myptr), descr=quasiimmutdescr)
+ guard_not_invalidated() []
+ i1 = getfield_gc(ConstPtr(myptr), descr=quasifielddescr)
+ jump()
+ """
+ expected = """
+ []
+ guard_not_invalidated() []
+ jump()
+ """
+ self.optimize_loop(ops, expected, expected)
##class TestOOtype(OptimizeOptTest, OOtypeMixin):
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -380,6 +380,7 @@
'GUARD_NO_OVERFLOW/0d',
'GUARD_OVERFLOW/0d',
'GUARD_NOT_FORCED/0d',
+ 'GUARD_NOT_INVALIDATED/0d',
'_GUARD_LAST', # ----- end of guard operations -----
'_NOSIDEEFFECT_FIRST', # ----- start of no_side_effect operations -----
More information about the Pypy-commit
mailing list