[pypy-svn] r79936 - in pypy/branch/out-of-line-guards/pypy: jit/backend/llgraph jit/codewriter jit/codewriter/test jit/metainterp jit/metainterp/test rpython/lltypesystem
fijal at codespeak.net
fijal at codespeak.net
Thu Dec 9 17:07:15 CET 2010
Author: fijal
Date: Thu Dec 9 17:07:12 2010
New Revision: 79936
Modified:
pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/llimpl.py
pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/runner.py
pypy/branch/out-of-line-guards/pypy/jit/codewriter/call.py
pypy/branch/out-of-line-guards/pypy/jit/codewriter/effectinfo.py
pypy/branch/out-of-line-guards/pypy/jit/codewriter/jtransform.py
pypy/branch/out-of-line-guards/pypy/jit/codewriter/test/test_jtransform.py
pypy/branch/out-of-line-guards/pypy/jit/metainterp/blackhole.py
pypy/branch/out-of-line-guards/pypy/jit/metainterp/compile.py
pypy/branch/out-of-line-guards/pypy/jit/metainterp/pyjitpl.py
pypy/branch/out-of-line-guards/pypy/jit/metainterp/resoperation.py
pypy/branch/out-of-line-guards/pypy/jit/metainterp/test/test_basic.py
pypy/branch/out-of-line-guards/pypy/jit/metainterp/warmspot.py
pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/lloperation.py
pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/rclass.py
Log:
Try to merge my changes up-to-date. I'm not completely sure, since SVN
screwed me up massively on this one
Modified: pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/llimpl.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/llimpl.py Thu Dec 9 17:07:12 2010
@@ -157,6 +157,7 @@
'force_token' : ((), 'int'),
'call_may_force' : (('int', 'varargs'), 'intorptr'),
'guard_not_forced': ((), None),
+ 'guard_not_invariant': ((), None),
}
# ____________________________________________________________
@@ -925,6 +926,8 @@
if forced:
raise GuardFailed
+ def op_guard_not_invariant(self, descr):
+ pass
class OOFrame(Frame):
Modified: pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/runner.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/runner.py Thu Dec 9 17:07:12 2010
@@ -488,6 +488,10 @@
self.latest_frame = frame
return self.get_fail_descr_from_number(fail_index)
+ def get_invalidate_asm(self, TP, fieldname):
+ def invalidate_asm(arg, fieldname):
+ XXX # write me
+ return invalidate_asm
class OOtypeCPU_xxx_disabled(BaseCPU):
is_oo = True
Modified: pypy/branch/out-of-line-guards/pypy/jit/codewriter/call.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/codewriter/call.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/codewriter/call.py Thu Dec 9 17:07:12 2010
@@ -6,6 +6,7 @@
from pypy.jit.codewriter import support
from pypy.jit.codewriter.jitcode import JitCode
from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer
+from pypy.jit.codewriter.effectinfo import JitInvariantAnalyzer
from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze
from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection
from pypy.translator.simplify import get_funcobj, get_functype
@@ -30,6 +31,7 @@
self.raise_analyzer = RaiseAnalyzer(translator)
self.readwrite_analyzer = ReadWriteAnalyzer(translator)
self.virtualizable_analyzer = VirtualizableAnalyzer(translator)
+ self.jit_invariant_analyzer = JitInvariantAnalyzer(translator)
#
for index, jd in enumerate(jitdrivers_sd):
jd.index = index
@@ -216,7 +218,9 @@
assert not NON_VOID_ARGS, ("arguments not supported for "
"loop-invariant function!")
# build the extraeffect
- if self.virtualizable_analyzer.analyze(op):
+ if self.jit_invariant_analyzer.analyze(op):
+ extraeffect = EffectInfo.EF_FORCES_JIT_INVARIANT
+ elif self.virtualizable_analyzer.analyze(op):
extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
elif loopinvariant:
extraeffect = EffectInfo.EF_LOOPINVARIANT
@@ -234,7 +238,7 @@
#
if pure or loopinvariant:
assert effectinfo is not None
- assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
+ assert extraeffect < EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
#
return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT,
effectinfo)
Modified: pypy/branch/out-of-line-guards/pypy/jit/codewriter/effectinfo.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/codewriter/effectinfo.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/codewriter/effectinfo.py Thu Dec 9 17:07:12 2010
@@ -14,6 +14,7 @@
EF_CAN_RAISE = 2 #normal function (can raise)
EF_LOOPINVARIANT = 3 #special: call it only once per loop
EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 4 #can raise and force virtualizables
+ EF_FORCES_JIT_INVARIANT = 5 #can force jit invariant
# the 'oopspecindex' field is one of the following values:
OS_NONE = 0 # normal case, no oopspec
@@ -142,6 +143,10 @@
return op.opname in ('jit_force_virtualizable',
'jit_force_virtual')
+class JitInvariantAnalyzer(BoolGraphAnalyzer):
+ def analyze_simple_operation(self, op):
+ return op.opname == 'jit_invariant_setfield'
+
# ____________________________________________________________
class CallInfoCollection(object):
Modified: pypy/branch/out-of-line-guards/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/codewriter/jtransform.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/codewriter/jtransform.py Thu Dec 9 17:07:12 2010
@@ -32,6 +32,7 @@
self.cpu = cpu
self.callcontrol = callcontrol
self.portal_jd = portal_jd # non-None only for the portal graph(s)
+ self.asmcodes_appenders = {}
def transform(self, graph):
self.graph = graph
@@ -554,6 +555,7 @@
arrayfielddescr,
arraydescr)
return []
+ extrargs = []
# check for _immutable_fields_ hints
if v_inst.concretetype.TO._immutable_field(c_fieldname.value):
if (self.callcontrol is not None and
@@ -565,7 +567,10 @@
else:
jit_inv = v_inst.concretetype.TO._hints.get('jit_invariant_fields')
if jit_inv and op.args[1].value in jit_inv.fields:
- pure = '_pure'
+ pure = '_invariant'
+ c_func = self._get_appender_for_asmcode(
+ v_inst.concretetype.TO, c_fieldname.value)
+ extrargs.append(c_func)
else:
pure = ''
argname = getattr(v_inst.concretetype.TO, '_gckind', 'gc')
@@ -573,7 +578,40 @@
c_fieldname.value)
kind = getkind(RESULT)[0]
return SpaceOperation('getfield_%s_%s%s' % (argname, kind, pure),
- [v_inst, descr], op.result)
+ [v_inst, descr] + extrargs, op.result)
+
+ def _get_appender_for_asmcode(self, TP, fieldname):
+ from pypy.rpython.lltypesystem.rclass import ASMCODE
+ from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
+ from pypy.annotation.model import lltype_to_annotation
+
+ key = (TP, fieldname)
+ try:
+ return self.asmcodes_appenders[key]
+ except KeyError:
+ name = 'asmcodes_' + fieldname[len('inst_'):]
+
+ def appender(inst, v):
+ inst = lltype.cast_opaque_ptr(lltype.Ptr(TP), inst)
+ new_asmcode = lltype.malloc(ASMCODE)
+ new_asmcode.address = v
+ next = getattr(inst, name)
+ if not next:
+ setattr(inst, name, new_asmcode)
+ else:
+ prev = next
+ while next:
+ prev = next
+ next = next.next
+ prev.next = new_asmcode
+
+ args_s = [lltype_to_annotation(llmemory.GCREF)] * 2
+ s_result = lltype_to_annotation(lltype.Void)
+ mixlevelann = MixLevelHelperAnnotator(self.cpu.rtyper)
+ c_appender = mixlevelann.constfunc(appender, args_s, s_result)
+ mixlevelann.finish()
+ self.asmcodes_appenders[key] = c_appender
+ return c_appender
def rewrite_op_setfield(self, op):
if self.is_typeptr_getset(op):
Modified: pypy/branch/out-of-line-guards/pypy/jit/codewriter/test/test_jtransform.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/codewriter/test/test_jtransform.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/codewriter/test/test_jtransform.py Thu Dec 9 17:07:12 2010
@@ -956,7 +956,8 @@
Constant('inst_x', lltype.Void)], v2)
tr = Transformer(FakeCPU())
op1 = tr.rewrite_operation(op)
- assert op1.opname == 'getfield_gc_i_pure'
+ assert op1.opname == 'getfield_gc_i_invariant'
+ assert len(op1.args) == 3
def test_jit_invariant_setfield():
from pypy.rpython.rclass import FieldListAccessor
Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/blackhole.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/blackhole.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/blackhole.py Thu Dec 9 17:07:12 2010
@@ -1087,6 +1087,10 @@
bhimpl_getfield_gc_r_pure = bhimpl_getfield_gc_r
bhimpl_getfield_gc_f_pure = bhimpl_getfield_gc_f
+ bhimpl_getfield_gc_i_invariant = bhimpl_getfield_gc_i
+ bhimpl_getfield_gc_r_invariant = bhimpl_getfield_gc_r
+ bhimpl_getfield_gc_f_invariant = bhimpl_getfield_gc_f
+
bhimpl_getfield_vable_i = bhimpl_getfield_gc_i
bhimpl_getfield_vable_r = bhimpl_getfield_gc_r
bhimpl_getfield_vable_f = bhimpl_getfield_gc_f
Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/compile.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/compile.py Thu Dec 9 17:07:12 2010
@@ -101,6 +101,7 @@
if old_loop_token is not None:
metainterp.staticdata.log("reusing old loop")
return old_loop_token
+ metainterp.remember_jit_invariants(loop)
send_loop_to_backend(metainterp_sd, loop, "loop")
insert_loop_token(old_loop_tokens, loop_token)
record_loop_or_bridge(loop)
@@ -563,6 +564,7 @@
# know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr)
prepare_last_operation(new_loop, target_loop_token)
resumekey.compile_and_attach(metainterp, new_loop)
+ metainterp.remember_jit_invariants(target_loop_token)
record_loop_or_bridge(new_loop)
return target_loop_token
Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/pyjitpl.py Thu Dec 9 17:07:12 2010
@@ -1,5 +1,6 @@
import py, os, sys
from pypy.rpython.lltypesystem import lltype, llmemory, rclass
+from pypy.rpython.lltypesystem.rclass import ASMCODE
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.debug import debug_start, debug_stop, debug_print
@@ -509,6 +510,14 @@
opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any
opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any
+ @arguments("box", "descr", "box")
+ def _opimpl_getfield_gc_invariant_any(self, box, fielddescr, c_func):
+ self.metainterp.invariant_structs.append((box, c_func))
+ return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box)
+ opimpl_getfield_gc_i_invariant = _opimpl_getfield_gc_invariant_any
+ opimpl_getfield_gc_r_invariant = _opimpl_getfield_gc_invariant_any
+ opimpl_getfield_gc_f_invariant = _opimpl_getfield_gc_invariant_any
+
@arguments("orgpc", "box", "descr")
def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr):
ginfo = self.metainterp.jitdriver_sd.greenfield_info
@@ -1163,10 +1172,9 @@
assert i == len(allboxes)
#
effectinfo = descr.get_extra_info()
- if (effectinfo is None or
- effectinfo.extraeffect ==
- effectinfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE or
- assembler_call):
+ force_vir = effectinfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
+ if (effectinfo is None or effectinfo.extraeffect >= force_vir or
+ assembler_call):
# residual calls require attention to keep virtualizables in-sync
self.metainterp.clear_exception()
self.metainterp.vable_and_vrefs_before_residual_call()
@@ -1178,6 +1186,8 @@
if resbox is not None:
self.make_result_of_lastop(resbox)
self.metainterp.vable_after_residual_call()
+ if effectinfo.extraeffect >= effectinfo.EF_FORCES_JIT_INVARIANT:
+ self.generate_guard(rop.GUARD_NOT_INVARIANT, None)
self.generate_guard(rop.GUARD_NOT_FORCED, None)
self.metainterp.handle_possible_exception()
return resbox
@@ -1393,6 +1403,7 @@
self.portal_trace_positions = []
self.free_frames_list = []
self.last_exc_value_box = None
+ self.invariant_structs = []
def perform_call(self, jitcode, boxes, greenkey=None):
# causes the metainterp to enter the given subfunction
@@ -2227,6 +2238,14 @@
op = op.copy_and_change(rop.CALL_ASSEMBLER, args=args, descr=token)
self.history.operations.append(op)
+ def remember_jit_invariants(self, token):
+ lltoken = lltype.cast_opaque_ptr(llmemory.GCREF, token)
+ seen = {}
+ for b_struct, c_appender in self.invariant_structs:
+ if (b_struct, c_appender) not in seen:
+ heaptracker.int2adr(c_func.value).ptr(b_struct.value, lltoken)
+ seend[(b_struct, c_appender)] = None
+
# ____________________________________________________________
class GenerateMergePoint(JitException):
Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/resoperation.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/resoperation.py Thu Dec 9 17:07:12 2010
@@ -379,7 +379,8 @@
'GUARD_EXCEPTION/1d',
'GUARD_NO_OVERFLOW/0d',
'GUARD_OVERFLOW/0d',
- 'GUARD_NOT_FORCED/0d',
+ 'GUARD_NOT_FORCED/0d', # forcing virtualrefs/virtualizables
+ 'GUARD_NOT_INVARIANT/0d', # forcing jit invariant fields
'_GUARD_LAST', # ----- end of guard operations -----
'_NOSIDEEFFECT_FIRST', # ----- start of no_side_effect operations -----
Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/test/test_basic.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/test/test_basic.py Thu Dec 9 17:07:12 2010
@@ -723,7 +723,7 @@
def test_getfield_jit_invariant(self):
class A(object):
- _jit_invariant_fields_ = 'x'
+ _jit_invariant_fields_ = ['x']
a1 = A()
a1.x = 5
@@ -739,6 +739,31 @@
res = self.interp_operations(f, [-3])
self.check_operations_history(getfield_gc = 0)
+ def test_setfield_jit_invariant(self):
+ class A(object):
+ _jit_invariant_fields_ = ['x']
+
+ a = A()
+ a.x = 1
+
+ myjitdriver = JitDriver(greens = [], reds = ['i'])
+
+ @dont_look_inside
+ def g(i):
+ if i == 5:
+ a.x = 5
+
+ def f():
+ i = 0
+ while i < 10:
+ myjitdriver.can_enter_jit(i=i)
+ myjitdriver.jit_merge_point(i=i)
+ g(i)
+ i += a.x
+
+ self.meta_interp(f, [])
+ self.check_loop_count(2)
+
def test_setfield_bool(self):
class A:
def __init__(self):
Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/warmspot.py (original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/warmspot.py Thu Dec 9 17:07:12 2010
@@ -820,10 +820,19 @@
op.opname = 'direct_call'
op.args[:3] = [closures[key]]
+ def replace_jit_invariant_with_direct_call(self, op):
+ op.opname = 'direct_call'
+ ARG = op.args[0].concretetype
+ FUNC = lltype.Ptr(lltype.FuncType([ARG, lltype.Void], lltype.Void))
+ llptr = self.helper_func(FUNC, self.cpu.get_invalidate_asm(FUNC,
+ op.args[1].value))
+ cptr = Constant(llptr, lltype.Void)
+ op.args = [cptr, op.args[0], op.args[1]]
+
def rewrite_jit_invariant_setfield(self):
graphs = self.translator.graphs
for graph, block, i in find_jit_invariant_setfield(graphs):
- del block.operations[i] # for now
+ self.replace_jit_invariant_with_direct_call(block.operations[i])
def rewrite_force_virtual(self, vrefinfo):
if self.cpu.ts.name != 'lltype':
Modified: pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/lloperation.py (original)
+++ pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/lloperation.py Thu Dec 9 17:07:12 2010
@@ -433,6 +433,7 @@
'jit_marker': LLOp(),
'jit_force_virtualizable':LLOp(canrun=True),
'jit_force_virtual': LLOp(canrun=True),
+ 'jit_invariant_setfield': LLOp(canrun=True),
'get_exception_addr': LLOp(),
'get_exc_value_addr': LLOp(),
'do_malloc_fixedsize_clear':LLOp(canraise=(MemoryError,),canunwindgc=True),
Modified: pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/rclass.py (original)
+++ pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/rclass.py Thu Dec 9 17:07:12 2010
@@ -87,7 +87,7 @@
# a linked-list of assembler codes to invalidate in case jit_invariant_fields
# are modified
ASMCODE = lltype.GcForwardReference()
-ASMCODE.become(GcStruct('asmcode', ('address', llmemory.Address),
+ASMCODE.become(GcStruct('asmcode', ('address', llmemory.GCREF),
('next', lltype.Ptr(ASMCODE))))
def cast_vtable_to_typeptr(vtable):
@@ -148,6 +148,9 @@
#
self.rbase = getclassrepr(self.rtyper, self.classdef.basedef)
self.rbase.setup()
+ # jit_invariant_fields
+ jit_inv_fields = self.classdef.classdesc.classdict.get(
+ '_jit_invariant_fields_')
kwds = {'hints': {'immutable': True}}
vtable_type = Struct('%s_vtable' % self.classdef.name,
('super', self.rbase.vtable_type),
@@ -517,7 +520,9 @@
# for virtualizables; see rvirtualizable2.py
if (op == 'setfield' and cname.value.startswith('inst_') and
cname.value[len('inst_'):] in self.jit_invariant_fields):
- llops.genop('jit_invariant_setfield', [])
+ name = cname.value
+ cname = Constant('asmcodes_' + name[len('inst_'):], lltype.Void)
+ llops.genop('jit_invariant_setfield', [vinst, cname])
def new_instance(self, llops, classcallhop=None):
"""Build a new instance, without calling __init__."""
More information about the Pypy-commit
mailing list