[pypy-commit] pypy no-failargs: hg merge result-in-resops
arigo
noreply at buildbot.pypy.org
Mon Oct 29 17:42:43 CET 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: no-failargs
Changeset: r58595:b138acc8137f
Date: 2012-10-29 17:42 +0100
http://bitbucket.org/pypy/pypy/changeset/b138acc8137f/
Log: hg merge result-in-resops
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
@@ -25,6 +25,8 @@
# value pending in the ResOperation is *not* visible in
# 'cached_fields'.
#
+
+ # XXXX kill dicts here
self._cached_fields = {}
self._cached_fields_getfield_op = {}
self._lazy_setfield = None
@@ -32,8 +34,8 @@
def do_setfield(self, optheap, op):
# Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'.
- structvalue = optheap.getvalue(op.getarg(0))
- fieldvalue = optheap.getvalue(op.getarglist()[-1])
+ structvalue = optheap.getforwarded(op.getarg(0))
+ fieldvalue = optheap.getforwarded(op.getarglist()[-1])
if self.possible_aliasing(optheap, structvalue):
self.force_lazy_setfield(optheap)
assert not self.possible_aliasing(optheap, structvalue)
@@ -44,7 +46,7 @@
optheap.optimizer.ensure_imported(cached_fieldvalue)
cached_fieldvalue = self._cached_fields.get(structvalue, None)
- if not fieldvalue.same_value(cached_fieldvalue):
+ if not optheap.optimizer.same_value(fieldvalue, cached_fieldvalue):
# common case: store the 'op' as lazy_setfield, and register
# myself in the optheap's _lazy_setfields_and_arrayitems list
self._lazy_setfield = op
@@ -94,14 +96,15 @@
# possible aliasing).
self.clear()
self._lazy_setfield = None
- optheap.next_optimization.propagate_forward(op)
+ # XXX should we push it through the optimizer chain?
+ optheap.optimizer.emit_operation(op)
if not can_cache:
return
# Once it is done, we can put at least one piece of information
# back in the cache: the value of this particular structure's
# field.
- structvalue = optheap.getvalue(op.getarg(0))
- fieldvalue = optheap.getvalue(op.getarglist()[-1])
+ structvalue = optheap.getforwarded(op.getarg(0))
+ fieldvalue = optheap.getforwarded(op.getarglist()[-1])
self.remember_field_value(structvalue, fieldvalue, op)
elif not can_cache:
self.clear()
@@ -294,7 +297,7 @@
# of virtualref_info and virtualizable_info are not gcptrs.
def turned_constant(self, value):
- value = self.getforwarded(value)
+ newvalue = self.getforwarded(value)
for cf in self.cached_fields.itervalues():
cf.turned_constant(newvalue, value)
for submap in self.cached_arrayitems.itervalues():
@@ -365,21 +368,29 @@
return pendingfields
def optimize_GETFIELD_GC_i(self, op):
- structvalue = self.getvalue(op.getarg(0))
+ structvalue = self.getforwarded(op.getarg(0))
cf = self.field_cache(op.getdescr())
fieldvalue = cf.getfield_from_cache(self, structvalue)
if fieldvalue is not None:
self.replace(op, fieldvalue.op)
return
# default case: produce the operation
- structvalue.ensure_nonnull()
- self.emit_operation(op)
- # then remember the result of reading the field
- fieldvalue = self.getvalue(op)
- cf.remember_field_value(structvalue, fieldvalue, op)
+ structvalue.setknownnonnull(True)
+ return op
+
optimize_GETFIELD_GC_r = optimize_GETFIELD_GC_i
optimize_GETFIELD_GC_f = optimize_GETFIELD_GC_i
+ def postprocess_GETFIELD_GC_i(self, op):
+ # then remember the result of reading the field
+ structvalue = self.getforwarded(op.getarg(0))
+ fieldvalue = self.getforwarded(op)
+ cf = self.field_cache(op.getdescr())
+ cf.remember_field_value(structvalue, fieldvalue, op)
+
+ postprocess_GETFIELD_GC_r = postprocess_GETFIELD_GC_i
+ postprocess_GETFIELD_GC_f = postprocess_GETFIELD_GC_i
+
def optimize_GETFIELD_GC_PURE_i(self, op):
structvalue = self.getvalue(op.getarg(0))
cf = self.field_cache(op.getdescr())
@@ -394,6 +405,7 @@
optimize_GETFIELD_GC_PURE_r = optimize_GETFIELD_GC_PURE_i
def optimize_SETFIELD_GC(self, op):
+ # XXX this is just debugging, should we comment it out somehow?
if op.type == INT:
op_key = create_resop_1(rop.GETFIELD_GC_PURE_i, 0, op.getarg(0),
op.getdescr())
diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py
--- a/pypy/jit/metainterp/optimizeopt/intbounds.py
+++ b/pypy/jit/metainterp/optimizeopt/intbounds.py
@@ -36,7 +36,8 @@
dispatch_bounds_ops(self, op)
def postprocess_GUARD_TRUE(self, op):
- self.propagate_bounds_backward(op.getarg(0))
+ if op.getarg(0).type == INT:
+ self.propagate_bounds_backward(op.getarg(0))
postprocess_GUARD_FALSE = postprocess_GUARD_TRUE
postprocess_GUARD_VALUE = postprocess_GUARD_TRUE
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -158,13 +158,6 @@
return not op.nonnull()
return False
- def same_value(self, other):
- if not other:
- return False
- if self.is_constant() and other.is_constant():
- return self.box.same_constant(other.box)
- return self is other
-
def make_constant_class(self, classbox, guardop, index):
assert self.level < LEVEL_KNOWNCLASS
self.known_class = classbox
@@ -257,13 +250,6 @@
def __init__(self):
pass # make rpython happy
- #def propagate_forward(self, op):
- # raise NotImplementedError
-
- #def emit_operation(self, op):
- # self.last_emitted_operation = op
- # self.next_optimization.propagate_forward(op)
-
def process_inputargs(self, args):
pass
@@ -423,21 +409,6 @@
def replace(self, op, with_):
self.getforwarded(op)._forwarded = with_
- def copy_op_if_modified_by_optimization(self, op):
- xxxx
- new_op = op.copy_if_modified_by_optimization(self)
- if new_op is not op:
- self.replace(op, new_op)
- return new_op
-
- # XXX some RPython magic needed
- def copy_and_change(self, op, *args, **kwds):
- xxx
- new_op = op.copy_and_change(*args, **kwds)
- if new_op is not op:
- self.replace(op, new_op)
- return new_op
-
def ensure_imported(self, value):
pass
@@ -469,6 +440,15 @@
if not op.is_constant():
op._forwarded = ConstInt(intvalue)
+ def same_value(self, op1, op2):
+ if op1 is op2:
+ return True
+ if op2 is None:
+ return False
+ if op1.is_constant() and op2.is_constant():
+ return op1.same_constant(op2)
+ return False
+
def new_ptr_box(self):
return self.cpu.ts.BoxRef()
@@ -511,10 +491,11 @@
for opt in self.optimizations:
opt.process_inputargs(self.loop.inputargs)
while i < len(self.loop.operations):
- op = self.loop.operations[i]
- orig_op = op
+ orig_op = self.loop.operations[i]
+ op = orig_op
for opt in self.optimizations:
op = opt.optimize_operation(op)
+ # result can be either None, the same thing or a new operation
if op is None:
break
else:
@@ -539,6 +520,7 @@
dispatch_opt(self, op)
def emit_operation(self, op):
+ op = self.getforwarded(op)
assert op.getopnum() not in opgroups.CALL_PURE
assert not op._forwarded
if isinstance(op, Const):
@@ -558,6 +540,7 @@
def store_final_boxes_in_guard(self, op):
return op # XXX we disable it for tests
+ xxxx
assert op.getdescr() is None
descr = op.invent_descr(self.jitdriver_sd, self.metainterp_sd)
op.setdescr(descr)
@@ -570,28 +553,6 @@
raise compile.giveup()
descr.store_final_boxes(op, newboxes)
#
- if op.getopnum() == rop.GUARD_VALUE:
- xxx
- if self.getvalue(op.getarg(0)).is_bool_box:
- # Hack: turn guard_value(bool) into guard_true/guard_false.
- # This is done after the operation is emitted to let
- # store_final_boxes_in_guard set the guard_opnum field of the
- # descr to the original rop.GUARD_VALUE.
- constvalue = op.getarg(1).getint()
- if constvalue == 0:
- newop = create_resop_1(rop.GUARD_FALSE, None,
- op.getarg(0))
- elif constvalue == 1:
- newop = create_resop_1(rop.GUARD_TRUE, None,
- op.getarg(0))
- else:
- raise AssertionError("uh?")
- newop.set_extra("failargs", op.get_extra("failargs"))
- self.replace(op, newop)
- return newop
- else:
- # a real GUARD_VALUE. Make it use one counter per value.
- descr.make_a_counter_per_value(op)
return op
def optimize_default(self, op):
@@ -617,9 +578,6 @@
# self.emit_operation(op)
# FIXME: Is this still needed?
- def optimize_DEBUG_MERGE_POINT(self, op):
- self.emit_operation(op)
-
def optimize_GETARRAYITEM_GC_PURE_i(self, op):
indexvalue = self.getvalue(op.getarg(1))
if indexvalue.is_constant():
diff --git a/pypy/jit/metainterp/optimizeopt/pure.py b/pypy/jit/metainterp/optimizeopt/pure.py
--- a/pypy/jit/metainterp/optimizeopt/pure.py
+++ b/pypy/jit/metainterp/optimizeopt/pure.py
@@ -12,6 +12,7 @@
self.emitted_pure_operations = []
def optimize_default(self, op):
+ orig_op = op
op = self.getforwarded(op)
canfold = op.is_always_pure()
if op.is_ovf():
@@ -38,14 +39,13 @@
return
# did we do the exact same operation already?
- oldop = self.pure_operations.get(op)
+ oldop = self.pure_operations.get(orig_op)
if oldop is not None:
- self.replace(op, oldop)
+ self.optimizer.replace(op, oldop)
return
else:
- self.pure_operations.set(op, op)
+ self.pure_operations.set(orig_op, op)
self.remember_emitting_pure(op)
-
# otherwise, the operation remains
if nextop:
return nextop
@@ -61,13 +61,11 @@
self.replace(op, oldop)
self.last_emitted_operation = REMOVED
return
- else:
- new_op = op.copy_if_modified_by_optimization(self.optimizer)
- self.pure_operations.set(new_op, op)
- self.remember_emitting_pure(op)
-
+ new_op = self.optimizer.getforwarded(op)
+ self.pure_operations.set(op, new_op)
+ self.remember_emitting_pure(new_op)
# replace CALL_PURE with just CALL
- self.emit_operation(self.optimizer.copy_and_change(op, opnum))
+ return new_op.make_forwarded_copy(opnum)
return optimize_CALL_PURE
optimize_CALL_PURE_i = _new_optimize_call_pure(rop.CALL_i)
optimize_CALL_PURE_f = _new_optimize_call_pure(rop.CALL_f)
@@ -79,7 +77,7 @@
# it was a CALL_PURE that was killed; so we also kill the
# following GUARD_NO_EXCEPTION
return
- self.emit_operation(op)
+ return op
def flush(self):
assert self.posponedop is None
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -2,10 +2,11 @@
from pypy.jit.metainterp.optimize import InvalidLoop
from pypy.jit.metainterp.optimizeopt.intutils import IntBound
from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1,\
- CONST_0
+ CONST_0, REMOVED
from pypy.jit.metainterp.resoperation import (opboolinvers, opboolreflex, rop,
ConstInt, make_hashable_int,
- create_resop_2, Const)
+ create_resop_2, Const,
+ create_resop_1)
from pypy.rlib.rarithmetic import highest_bit
@@ -52,7 +53,7 @@
arg1=op.getarg(0))
oldop = self.get_pure_result(key_op)
if oldop is not None and oldop.getdescr() is op.getdescr():
- self.replace(op, oldop)
+ self.optimizer.replace(op, oldop)
return True
oldopnum = opboolinvers[opboolreflex[op.getopnum()]]
@@ -76,16 +77,16 @@
v1 = self.getvalue(op.getarg(0))
v2 = self.getvalue(op.getarg(1))
if v1.is_null():
- self.replace(op, op.getarg(1))
+ self.optimizer.replace(op, op.getarg(1))
elif v2.is_null():
- self.replace(op, op.getarg(0))
+ self.optimizer.replace(op, op.getarg(0))
else:
- self.emit_operation(op)
+ return op
def optimize_INT_SUB(self, op):
v2 = self.getforwarded(op.getarg(1))
if v2.is_constant() and v2.getint() == 0:
- self.replace(op, op.getarg(0))
+ self.optimizer.replace(op, op.getarg(0))
else:
# Synthesize the reverse ops for optimize_default to reuse
self.pure(op.getarg(0), rop.INT_ADD, op.getarg(1), op)
@@ -101,9 +102,9 @@
# If one side of the op is 0 the result is the other side.
if v1.is_constant() and v1.getint() == 0:
- self.replace(op, arg2)
+ self.optimizer.replace(op, arg2)
elif v2.is_constant() and v2.getint() == 0:
- self.replace(op, arg1)
+ self.optimizer.replace(op, arg1)
else:
# Synthesize the reverse op for optimize_default to reuse
self.pure(op.getarg(0), rop.INT_SUB, op, op.getarg(1))
@@ -172,11 +173,11 @@
if v1.is_constant():
if v1.op.getfloat() == 1.0:
- self.replace(op, rhs)
+ self.optimizer.replace(op, rhs)
return
elif v1.op.getfloat() == -1.0:
new_op = create_resop_1(rop.FLOAT_NEG, 0.0, rhs)
- self.replace(op, new_op)
+ self.optimizer.replace(op, new_op)
self.emit_operation(new_op)
return
self.emit_operation(op)
@@ -194,7 +195,7 @@
'always fail')
return
if emit_operation:
- return self.getforwarded(op)
+ return op
def postprocess_guard(self, op, constbox):
value = self.getforwarded(op.getarg(0))
@@ -212,31 +213,27 @@
def postprocess_GUARD_FALSE(self, op):
self.postprocess_guard(op, CONST_0)
- def postprocess_GUARD_NO_OVERFLOW(self, op):
- pass # to be killed
-
- def postprocess_default(self, op):
- if op.is_guard():
- xxx
-
def optimize_GUARD_ISNULL(self, op):
- value = self.getvalue(op.getarg(0))
+ value = self.getforwarded(op.getarg(0))
if value.is_null():
return
elif value.is_nonnull():
raise InvalidLoop('A GUARD_ISNULL was proven to always fail')
- self.emit_operation(op)
- value.make_constant(self.optimizer.cpu.ts.CONST_NULL)
+ return op
+
+ def postprocess_GUARD_ISNULL(self, op):
+ self.optimizer.make_constant(op.getarg(0),
+ self.optimizer.cpu.ts.CONST_NULL)
def optimize_GUARD_NONNULL(self, op):
- value = self.getvalue(op.getarg(0))
+ value = self.getforwarded(op.getarg(0))
if value.is_nonnull():
return
elif value.is_null():
raise InvalidLoop('A GUARD_NONNULL was proven to always fail')
- pos = self.optimizer.get_pos()
- self.emit_operation(op)
- value.make_nonnull(op, pos)
+ value.setknownnonnull(True)
+ value.setlastguardpos(self.optimizer.get_pos())
+ return op
def optimize_GUARD_VALUE(self, op):
value = self.getforwarded(op.getarg(0))
@@ -274,6 +271,17 @@
value.last_guard = None
emit_operation = False
else:
+ if not value.is_constant() and value.returns_bool_result():
+ constvalue = op.getarg(1).getint()
+ if constvalue == 0:
+ newop = create_resop_1(rop.GUARD_FALSE, None,
+ op.getarg(0))
+ elif constvalue == 1:
+ newop = create_resop_1(rop.GUARD_TRUE, None,
+ op.getarg(0))
+ else:
+ raise AssertionError("uh?")
+ return newop
emit_operation = True
constbox = op.getarg(1)
assert isinstance(constbox, Const)
@@ -354,7 +362,7 @@
resop = self.loop_invariant_results.get(key, None)
if resop is not None:
- self.replace(op, resop)
+ self.optimizer.replace(op, resop)
self.last_emitted_operation = REMOVED
return
# change the op to be a normal call, from the backend's point of view
@@ -371,25 +379,25 @@
def _optimize_nullness(self, op, arg, expect_nonnull):
value = self.getforwarded(arg)
- if value.nonnull():
+ if value.is_nonnull():
self.make_constant_int(op, expect_nonnull)
- elif not value.nonnull():
+ elif value.is_null():
self.make_constant_int(op, not expect_nonnull)
else:
return op
def optimize_INT_IS_TRUE(self, op):
if op.getarg(0).returns_bool_result():
- self.replace(op, op.getarg(0))
+ self.optimizer.replace(op, op.getarg(0))
return
return self._optimize_nullness(op, op.getarg(0), True)
def optimize_INT_IS_ZERO(self, op):
- self._optimize_nullness(op, op.getarg(0), False)
+ return self._optimize_nullness(op, op.getarg(0), False)
def _optimize_oois_ooisnot(self, op, expect_isnot, instance):
- value0 = self.getvalue(op.getarg(0))
- value1 = self.getvalue(op.getarg(1))
+ value0 = self.getforwarded(op.getarg(0))
+ value1 = self.getforwarded(op.getarg(1))
if value0.is_virtual():
if value1.is_virtual():
intres = (value0 is value1) ^ expect_isnot
@@ -449,7 +457,7 @@
if oopspecindex == EffectInfo.OS_ARRAYCOPY:
if self._optimize_CALL_ARRAYCOPY(op):
return
- self.emit_operation(op)
+ return op
optimize_CALL_p = optimize_CALL_i
optimize_CALL_f = optimize_CALL_i
optimize_CALL_v = optimize_CALL_i
@@ -490,14 +498,14 @@
# it's being done by someone else)
for i in range(op.numargs()):
arg = op.getarg(i)
- const = self.get_constant_box(arg)
+ const = self.get_constant_op(arg)
if const is None or not const.eq_value(arg):
break
else:
self.make_constant(op, op.constbox())
self.last_emitted_operation = REMOVED
return
- self.emit_operation(op)
+ return op
optimize_CALL_PURE_f = optimize_CALL_PURE_i
optimize_CALL_PURE_p = optimize_CALL_PURE_i
optimize_CALL_PURE_v = optimize_CALL_PURE_i
@@ -507,7 +515,7 @@
# it was a CALL_PURE or a CALL_LOOPINVARIANT that was killed;
# so we also kill the following GUARD_NO_EXCEPTION
return
- self.emit_operation(op)
+ return op
def optimize_INT_FLOORDIV(self, op):
v1 = self.getvalue(op.getarg(0))
@@ -542,6 +550,14 @@
optimize_SAME_AS_r = optimize_SAME_AS_i
optimize_SAME_AS_f = optimize_SAME_AS_i
+ def optimize_JUMP(self, op):
+ self.optimizer.flush()
+ return op
+
+ def optimize_FINISH(self, op):
+ self.optimizer.flush()
+ return op
+
#dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_',
# default=OptRewrite.emit_operation)
#optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD')
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -1,4 +1,7 @@
+import random
+
import py
+
from pypy.rlib.objectmodel import instantiate
from pypy.jit.metainterp.optimizeopt.test.test_util import (
LLtypeMixin, BaseTest, FakeMetaInterpStaticData, convert_old_style_to_targets)
@@ -13,6 +16,7 @@
from pypy.jit.metainterp.test.support import boxint
from pypy.rlib.rarithmetic import LONG_BIT
+
def test_store_final_boxes_in_guard():
from pypy.jit.metainterp.resume import tag, TAGBOX
b0 = boxint()
@@ -185,9 +189,9 @@
self.optimize_loop(ops, expected)
def test_constfold_all(self):
- from pypy.jit.backend.llgraph.llimpl import TYPES # xxx fish
+ from pypy.jit.metainterp.optimizeopt.test.types import TYPES
from pypy.jit.metainterp.executor import execute_nonspec
- import random
+
for opnum in [rop._ALWAYS_PURE_FIRST, rop._ALWAYS_PURE_NO_PTR_LAST]:
try:
op = opname[opnum]
@@ -195,8 +199,6 @@
continue
if op.startswith('_'):
continue
- if 'FLOAT' in op:
- continue
argtypes, restype = TYPES[op.lower()]
args = []
for argtype in argtypes:
@@ -350,29 +352,16 @@
"""
self.optimize_loop(ops, expected)
- def test_remove_guard_value_if_constant(self):
- ops = """
- [p1]
- guard_value(p1, ConstPtr(myptr))
- jump(ConstPtr(myptr))
- """
- expected = """
- []
- jump()
- """
- py.test.skip("XXX")
- self.optimize_loop(ops, 'Constant(myptr)', expected)
-
def test_ooisnull_oononnull_1(self):
ops = """
[p0]
- guard_class(p0, ConstClass(node_vtable)) []
- guard_nonnull(p0) []
+ guard_class(p0, ConstClass(node_vtable))
+ guard_nonnull(p0)
jump(p0)
"""
expected = """
[p0]
- guard_class(p0, ConstClass(node_vtable)) []
+ guard_class(p0, ConstClass(node_vtable))
jump(p0)
"""
self.optimize_loop(ops, expected)
@@ -381,15 +370,15 @@
ops = """
[i0]
i1 = int_is_true(i0)
- guard_true(i1) []
+ guard_true(i1)
i2 = int_is_true(i0)
- guard_true(i2) []
+ guard_true(i2)
jump(i0)
"""
expected = """
[i0]
i1 = int_is_true(i0)
- guard_true(i1) []
+ guard_true(i1)
jump(i0)
"""
self.optimize_loop(ops, expected)
@@ -416,15 +405,15 @@
ops = """
[i0]
i1 = int_is_zero(i0)
- guard_true(i1) []
+ guard_true(i1)
i2 = int_is_true(i0)
- guard_false(i2) []
+ guard_false(i2)
jump(i0)
"""
expected = """
[i0]
i1 = int_is_zero(i0)
- guard_true(i1) []
+ guard_true(i1)
jump(0)
"""
self.optimize_loop(ops, expected)
@@ -432,13 +421,13 @@
def test_ooisnull_oononnull_2(self):
ops = """
[p0]
- guard_nonnull(p0) []
- guard_nonnull(p0) []
+ guard_nonnull(p0)
+ guard_nonnull(p0)
jump(p0)
"""
expected = """
[p0]
- guard_nonnull(p0) []
+ guard_nonnull(p0)
jump(p0)
"""
self.optimize_loop(ops, expected)
@@ -446,13 +435,13 @@
def test_ooisnull_on_null_ptr_1(self):
ops = """
[p0, p1]
- guard_isnull(p0) []
- guard_isnull(p0) []
+ guard_isnull(p0)
+ guard_isnull(p0)
jump(p1, p1)
"""
expected = """
[p0, p1]
- guard_isnull(p0) []
+ guard_isnull(p0)
jump(p1, p1)
"""
self.optimize_loop(ops, expected)
@@ -462,14 +451,14 @@
[p0]
pv = new_with_vtable(ConstClass(node_vtable))
setfield_gc(pv, p0, descr=valuedescr)
- guard_nonnull(p0) []
+ guard_nonnull(p0)
p1 = getfield_gc_r(pv, descr=valuedescr)
- guard_nonnull(p1) []
+ guard_nonnull(p1)
jump(p0)
"""
expected = """
[p0]
- guard_nonnull(p0) []
+ guard_nonnull(p0)
jump(p0)
"""
self.optimize_loop(ops, expected)
@@ -477,20 +466,20 @@
def test_oois_1(self):
ops = """
[p0]
- guard_class(p0, ConstClass(node_vtable)) []
+ guard_class(p0, ConstClass(node_vtable))
i0 = instance_ptr_ne(p0, NULL)
- guard_true(i0) []
+ guard_true(i0)
i1 = instance_ptr_eq(p0, NULL)
- guard_false(i1) []
+ guard_false(i1)
i2 = instance_ptr_ne(NULL, p0)
- guard_true(i0) []
+ guard_true(i0)
i3 = instance_ptr_eq(NULL, p0)
- guard_false(i1) []
+ guard_false(i1)
jump(p0)
"""
expected = """
[p0]
- guard_class(p0, ConstClass(node_vtable)) []
+ guard_class(p0, ConstClass(node_vtable))
jump(p0)
"""
self.optimize_loop(ops, expected)
@@ -500,14 +489,14 @@
[p0]
setfield_gc(p0, 5, descr=valuedescr) # forces p0 != NULL
i0 = ptr_ne(p0, NULL)
- guard_true(i0) []
+ guard_true(i0)
i1 = ptr_eq(p0, NULL)
- guard_false(i1) []
+ guard_false(i1)
i2 = ptr_ne(NULL, p0)
- guard_true(i0) []
+ guard_true(i0)
i3 = ptr_eq(NULL, p0)
- guard_false(i1) []
- guard_nonnull(p0) []
+ guard_false(i1)
+ guard_nonnull(p0)
jump(p0)
"""
expected = """
@@ -520,14 +509,14 @@
def test_const_guard_value(self):
ops = """
[i0]
- guard_value(i0, 2) []
+ guard_value(i0, 2)
i = int_add(5, i0)
- guard_value(i, 7) []
+ guard_value(i, 7)
jump(i0)
"""
expected = """
[i0]
- guard_value(i0, 2) []
+ guard_value(i0, 2)
jump(2)
"""
self.optimize_loop(ops, expected)
@@ -535,12 +524,12 @@
def test_constptr_guard_value(self):
ops = """
[p1]
- guard_value(p1, ConstPtr(myptr)) []
+ guard_value(p1, ConstPtr(myptr))
jump(p1)
"""
expected = """
[p1]
- guard_value(p1, ConstPtr(myptr)) []
+ guard_value(p1, ConstPtr(myptr))
jump(ConstPtr(myptr))
"""
self.optimize_loop(ops, expected)
@@ -549,13 +538,13 @@
ops = """
[i]
i1 = int_lt(i, 3)
- guard_value(i1, 1) [i]
+ guard_value(i1, 1)
jump(i)
"""
expected = """
[i]
i1 = int_lt(i, 3)
- guard_true(i1) [i]
+ guard_true(i1)
jump(i)
"""
self.optimize_loop(ops, expected)
@@ -564,13 +553,13 @@
ops = """
[i]
i1 = int_is_true(i)
- guard_value(i1, 0) [i]
+ guard_value(i1, 0)
jump(i)
"""
expected = """
[i]
i1 = int_is_true(i)
- guard_false(i1) [i]
+ guard_false(i1)
jump(i)
"""
self.optimize_loop(ops, expected)
@@ -579,13 +568,13 @@
ops = """
[i]
i1 = int_add(i, 3)
- guard_value(i1, 0) [i]
+ guard_value(i1, 0)
jump(i)
"""
expected = """
[i]
i1 = int_add(i, 3)
- guard_value(i1, 0) [i]
+ guard_value(i1, 0)
jump(-3)
"""
self.optimize_loop(ops, expected)
@@ -596,20 +585,17 @@
i2 = int_gt(i0, i1)
i3 = int_is_true(i2)
i4 = int_is_true(i3)
- guard_value(i4, 0) [i0, i1]
+ guard_value(i4, 0)
jump(i0, i1)
"""
expected = """
[i0, i1]
i2 = int_gt(i0, i1)
- guard_false(i2) [i0, i1]
+ guard_false(i2)
jump(i0, i1)
"""
self.optimize_loop(ops, expected)
-
-
-
def test_p123_simple(self):
ops = """
[i1, p2, p3]
@@ -629,9 +615,9 @@
escape(i3)
p1 = new_with_vtable(ConstClass(node_vtable))
p1sub = new_with_vtable(ConstClass(node_vtable2))
- setfield_gc(p1, i1, descr=valuedescr)
setfield_gc(p1sub, i1, descr=valuedescr)
setfield_gc(p1, p1sub, descr=nextdescr)
+ setfield_gc(p1, i1, descr=valuedescr)
jump(i1, p1, p2)
"""
# The same as test_p123_simple, but with a virtual containing another
@@ -644,10 +630,10 @@
p3sub = getfield_gc_r(p3, descr=nextdescr)
i3 = getfield_gc_i(p3sub, descr=valuedescr)
escape(i3)
- p1 = new_with_vtable(ConstClass(node_vtable))
p2sub = new_with_vtable(ConstClass(node_vtable2))
setfield_gc(p2sub, i1, descr=valuedescr)
setfield_gc(p2, p2sub, descr=nextdescr)
+ p1 = new_with_vtable(ConstClass(node_vtable))
jump(i1, p1, p2)
"""
# The same as test_p123_simple, but in the end the "old" p2 contains
@@ -660,7 +646,7 @@
ops = """
[i1]
i2 = call_i(i1, descr=nonwritedescr)
- guard_no_exception() [i1, i2]
+ guard_no_exception()
jump(i2)
"""
self.optimize_loop(ops, ops)
@@ -669,13 +655,13 @@
ops = """
[i1]
i2 = call_pure_i(123456, i1, descr=nonwritedescr)
- guard_no_exception() [i1, i2]
+ guard_no_exception()
jump(i2)
"""
expected = """
[i1]
i2 = call_i(123456, i1, descr=nonwritedescr)
- guard_no_exception() [i1, i2]
+ guard_no_exception()
jump(i2)
"""
self.optimize_loop(ops, expected)
@@ -685,7 +671,7 @@
[i1]
i3 = same_as_i(81)
i2 = call_pure_i(123456, i3, descr=nonwritedescr)
- guard_no_exception() [i1, i2]
+ guard_no_exception()
jump(i2)
"""
expected = """
@@ -698,15 +684,15 @@
ops = """
[i1]
i2 = call_pure_i(123456, i1, descr=nonwritedescr)
- guard_no_exception() [i1, i2]
+ guard_no_exception()
i3 = call_pure_i(123456, i1, descr=nonwritedescr)
- guard_no_exception() [i1, i2, i3]
+ guard_no_exception()
jump(i3)
"""
expected = """
[i1]
i2 = call_i(123456, i1, descr=nonwritedescr)
- guard_no_exception() [i1, i2]
+ guard_no_exception()
jump(i2)
"""
self.optimize_loop(ops, expected)
@@ -717,26 +703,25 @@
ops = """
[i1]
i2 = call_loopinvariant_i(1, i1, descr=nonwritedescr)
- guard_no_exception() []
- guard_value(i2, 1) []
+ guard_no_exception()
+ guard_value(i2, 1)
i3 = call_loopinvariant_i(1, i1, descr=nonwritedescr)
- guard_no_exception() []
- guard_value(i3, 1) []
+ guard_no_exception()
+ guard_value(i3, 1)
i4 = call_loopinvariant_i(1, i1, descr=nonwritedescr)
- guard_no_exception() []
- guard_value(i4, 1) []
+ guard_no_exception()
+ guard_value(i4, 1)
jump(i1)
"""
expected = """
[i1]
i2 = call_i(1, i1, descr=nonwritedescr)
- guard_no_exception() []
- guard_value(i2, 1) []
+ guard_no_exception()
+ guard_value(i2, 1)
jump(i1)
"""
self.optimize_loop(ops, expected)
-
# ----------
def test_virtual_1(self):
@@ -1102,13 +1087,13 @@
def test_getfield_gc_pure_2(self):
ops = """
[p0, i]
- guard_value(p0, ConstPtr(myptr)) []
+ guard_value(p0, ConstPtr(myptr))
i1 = getfield_gc_pure_i(p0, descr=valuedescr)
jump(p0, i1)
"""
expected = """
[p0, i]
- guard_value(p0, ConstPtr(myptr)) []
+ guard_value(p0, ConstPtr(myptr))
jump(ConstPtr(myptr), 5)
"""
self.node.value = 5
@@ -1128,7 +1113,7 @@
[i1]
p1 = new_array(3, descr=arraydescr)
i3 = arraylen_gc(p1, descr=arraydescr)
- guard_value(i3, 3) []
+ guard_value(i3, 3)
setarrayitem_gc(p1, 1, i1, descr=arraydescr)
setarrayitem_gc(p1, 0, 25, descr=arraydescr)
i2 = getarrayitem_gc_i(p1, 1, descr=arraydescr)
@@ -1159,7 +1144,7 @@
[f1]
p1 = new_array(3, descr=floatarraydescr)
i3 = arraylen_gc(p1, descr=floatarraydescr)
- guard_value(i3, 3) []
+ guard_value(i3, 3)
setarrayitem_gc(p1, 1, f1, descr=floatarraydescr)
setarrayitem_gc(p1, 0, 3.5, descr=floatarraydescr)
f2 = getarrayitem_gc_f(p1, 1, descr=floatarraydescr)
diff --git a/pypy/jit/metainterp/optimizeopt/test/types.py b/pypy/jit/metainterp/optimizeopt/test/types.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/optimizeopt/test/types.py
@@ -0,0 +1,105 @@
+TYPES = {
+ 'int_add' : (('int', 'int'), 'int'),
+ 'int_sub' : (('int', 'int'), 'int'),
+ 'int_mul' : (('int', 'int'), 'int'),
+ 'int_floordiv' : (('int', 'int'), 'int'),
+ 'int_mod' : (('int', 'int'), 'int'),
+ 'int_and' : (('int', 'int'), 'int'),
+ 'int_or' : (('int', 'int'), 'int'),
+ 'int_xor' : (('int', 'int'), 'int'),
+ 'int_lshift' : (('int', 'int'), 'int'),
+ 'int_rshift' : (('int', 'int'), 'int'),
+ 'int_lt' : (('int', 'int'), 'bool'),
+ 'int_gt' : (('int', 'int'), 'bool'),
+ 'int_ge' : (('int', 'int'), 'bool'),
+ 'int_le' : (('int', 'int'), 'bool'),
+ 'int_eq' : (('int', 'int'), 'bool'),
+ 'int_ne' : (('int', 'int'), 'bool'),
+ 'int_is_true' : (('int',), 'bool'),
+ 'int_is_zero' : (('int',), 'bool'),
+ 'int_neg' : (('int',), 'int'),
+ 'int_invert' : (('int',), 'int'),
+ 'int_add_ovf' : (('int', 'int'), 'int'),
+ 'int_sub_ovf' : (('int', 'int'), 'int'),
+ 'int_mul_ovf' : (('int', 'int'), 'int'),
+ 'int_force_ge_zero':(('int',), 'int'),
+ 'uint_add' : (('int', 'int'), 'int'),
+ 'uint_sub' : (('int', 'int'), 'int'),
+ 'uint_mul' : (('int', 'int'), 'int'),
+ 'uint_lt' : (('int', 'int'), 'bool'),
+ 'uint_le' : (('int', 'int'), 'bool'),
+ 'uint_eq' : (('int', 'int'), 'bool'),
+ 'uint_ne' : (('int', 'int'), 'bool'),
+ 'uint_gt' : (('int', 'int'), 'bool'),
+ 'uint_ge' : (('int', 'int'), 'bool'),
+ 'uint_xor' : (('int', 'int'), 'int'),
+ 'uint_rshift' : (('int', 'int'), 'int'),
+ 'uint_floordiv' : (('int', 'int'), 'int'),
+ 'float_add' : (('float', 'float'), 'float'),
+ 'float_sub' : (('float', 'float'), 'float'),
+ 'float_mul' : (('float', 'float'), 'float'),
+ 'float_truediv' : (('float', 'float'), 'float'),
+ 'float_lt' : (('float', 'float'), 'bool'),
+ 'float_le' : (('float', 'float'), 'bool'),
+ 'float_eq' : (('float', 'float'), 'bool'),
+ 'float_ne' : (('float', 'float'), 'bool'),
+ 'float_gt' : (('float', 'float'), 'bool'),
+ 'float_ge' : (('float', 'float'), 'bool'),
+ 'float_neg' : (('float',), 'float'),
+ 'float_abs' : (('float',), 'float'),
+ 'cast_float_to_int':(('float',), 'int'),
+ 'cast_int_to_float':(('int',), 'float'),
+ 'same_as' : (('int',), 'int'), # could also be ptr=>ptr
+ 'new_with_vtable' : (('ref',), 'ref'),
+ 'new' : ((), 'ref'),
+ 'new_array' : (('int',), 'ref'),
+ 'oois' : (('ref', 'ref'), 'bool'),
+ 'ooisnot' : (('ref', 'ref'), 'bool'),
+ 'instanceof' : (('ref',), 'bool'),
+ 'subclassof' : (('ref', 'ref'), 'bool'),
+ 'runtimenew' : (('ref',), 'ref'),
+ 'setfield_gc' : (('ref', 'intorptr'), None),
+ 'getfield_gc' : (('ref',), 'intorptr'),
+ 'getfield_gc_pure': (('ref',), 'intorptr'),
+ 'setfield_raw' : (('ref', 'intorptr'), None),
+ 'getfield_raw' : (('ref',), 'intorptr'),
+ 'getfield_raw_pure': (('ref',), 'intorptr'),
+ 'setarrayitem_gc' : (('ref', 'int', 'intorptr'), None),
+ 'getarrayitem_gc' : (('ref', 'int'), 'intorptr'),
+ 'getarrayitem_gc_pure' : (('ref', 'int'), 'intorptr'),
+ 'setarrayitem_raw' : (('ref', 'int', 'intorptr'), None),
+ 'getarrayitem_raw' : (('ref', 'int'), 'intorptr'),
+ 'getarrayitem_raw_pure' : (('ref', 'int'), 'intorptr'),
+ 'arraylen_gc' : (('ref',), 'int'),
+ 'call' : (('ref', 'varargs'), 'intorptr'),
+ 'call_assembler' : (('varargs',), 'intorptr'),
+ 'cond_call_gc_wb' : (('ptr', 'ptr'), None),
+ 'cond_call_gc_wb_array': (('ptr', 'int', 'ptr'), None),
+ 'oosend' : (('varargs',), 'intorptr'),
+ 'oosend_pure' : (('varargs',), 'intorptr'),
+ 'guard_true' : (('bool',), None),
+ 'guard_false' : (('bool',), None),
+ 'guard_value' : (('int', 'int'), None),
+ 'guard_class' : (('ref', 'ref'), None),
+ 'guard_no_exception' : ((), None),
+ 'guard_exception' : (('ref',), 'ref'),
+ 'guard_no_overflow' : ((), None),
+ 'guard_overflow' : ((), None),
+ 'guard_nonnull' : (('ref',), None),
+ 'guard_isnull' : (('ref',), None),
+ 'guard_nonnull_class' : (('ref', 'ref'), None),
+ 'newstr' : (('int',), 'ref'),
+ 'strlen' : (('ref',), 'int'),
+ 'strgetitem' : (('ref', 'int'), 'int'),
+ 'strsetitem' : (('ref', 'int', 'int'), None),
+ 'newunicode' : (('int',), 'ref'),
+ 'unicodelen' : (('ref',), 'int'),
+ 'unicodegetitem' : (('ref', 'int'), 'int'),
+ 'unicodesetitem' : (('ref', 'int', 'int'), 'int'),
+ 'cast_ptr_to_int' : (('ref',), 'int'),
+ 'cast_int_to_ptr' : (('int',), 'ref'),
+ 'debug_merge_point': (('ref', 'int', 'int'), None),
+ 'force_token' : ((), 'int'),
+ 'call_may_force' : (('int', 'varargs'), 'intorptr'),
+ 'guard_not_forced': ((), None),
+}
diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py
--- a/pypy/jit/metainterp/optimizeopt/virtualize.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualize.py
@@ -425,7 +425,7 @@
# was already forced).
def optimize_GETFIELD_GC_i(self, op):
- value = self.getvalue(op.getarg(0))
+ value = self.getforwarded(op.getarg(0))
# If this is an immutable field (as indicated by op.is_always_pure())
# then it's safe to reuse the virtual's field, even if it has been
# forced, because it should never be written to again.
@@ -435,14 +435,13 @@
self.replace(op, fieldvalue.op)
return
if value.is_virtual():
- assert isinstance(value, AbstractVirtualValue)
fieldvalue = value.getfield(op.getdescr(), None)
if fieldvalue is None:
fieldvalue = self.optimizer.new_const(op.getdescr())
- self.replace(op, fieldvalue.op)
+ self.optimizer.replace(op, fieldvalue)
else:
- value.ensure_nonnull()
- self.emit_operation(op)
+ value.setknownnonnull(True)
+ return op
optimize_GETFIELD_GC_r = optimize_GETFIELD_GC_i
optimize_GETFIELD_GC_f = optimize_GETFIELD_GC_i
@@ -453,24 +452,23 @@
optimize_GETFIELD_GC_PURE_f = optimize_GETFIELD_GC_i
def optimize_SETFIELD_GC(self, op):
- value = self.getvalue(op.getarg(0))
+ value = self.getforwarded(op.getarg(0))
if value.is_virtual():
- fieldvalue = self.getvalue(op.getarg(1))
+ fieldvalue = self.getforwarded(op.getarg(1))
value.setfield(op.getdescr(), fieldvalue)
else:
- value.ensure_nonnull()
- self.emit_operation(op)
+ value.setknownnonnull(True)
+ return op
def optimize_NEW_WITH_VTABLE(self, op):
- value = self.getforwarded(op)
- value.setknownclass(op.getarg(0))
+ pass
def optimize_NEW(self, op):
self.make_vstruct(op.getdescr(), op)
def optimize_NEW_ARRAY(self, op):
- sizebox = self.get_constant_box(op.getarg(0))
+ sizebox = self.get_constant_op(op.getarg(0))
if sizebox is not None:
# if the original 'op' did not have a ConstInt as argument,
# build a new one with the ConstInt argument
diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py
--- a/pypy/jit/metainterp/optimizeopt/vstring.py
+++ b/pypy/jit/metainterp/optimizeopt/vstring.py
@@ -538,7 +538,7 @@
if oopspecindex == EffectInfo.OS_STR2UNICODE:
if self.opt_call_str_STR2UNICODE(op):
return
- self.emit_operation(op)
+ return op
optimize_CALL_f = optimize_CALL_i
optimize_CALL_r = optimize_CALL_i
optimize_CALL_v = optimize_CALL_i
@@ -551,7 +551,7 @@
def optimize_GUARD_NO_EXCEPTION(self, op):
if self.last_emitted_operation is REMOVED:
return
- self.emit_operation(op)
+ return op
def opt_call_str_STR2UNICODE(self, op):
# Constant-fold unicode("constant string").
diff --git a/pypy/jit/metainterp/optmodel.py b/pypy/jit/metainterp/optmodel.py
--- a/pypy/jit/metainterp/optmodel.py
+++ b/pypy/jit/metainterp/optmodel.py
@@ -4,9 +4,10 @@
from pypy.tool.sourcetools import func_with_new_name
from pypy.jit.metainterp.resoperation import opclasses, opclasses_mutable, rop,\
- VOID, INT, REF, ConstInt, Const
+ VOID, INT, REF, ConstInt, Const, ConstPtr
from pypy.jit.metainterp.optimizeopt.intutils import ImmutableIntUnbounded,\
- ConstantIntBound
+ ConstantIntBound, IntBound
+from pypy.jit.metainterp.virtualmodel import Virtual
class __extend__(ConstInt):
def getintbound(self):
@@ -15,6 +16,13 @@
def getboolres(self):
return False # for optimization
+class __extend__(ConstPtr):
+ def is_virtual(self):
+ return False
+
+ def is_forced_virtual(self):
+ return False
+
class __extend__(Const):
def getlastguardpos(self):
return -1
@@ -22,9 +30,18 @@
def force(self, _):
return self
+ def is_nonnull(self):
+ return self.nonnull()
+
+ def is_null(self):
+ return not self.nonnull()
+
+opclasses_mutable[rop.NEW_WITH_VTABLE] = Virtual
+
def create_mutable_subclasses():
def addattr(cls, attr, default_value=None):
- cls.attributes_to_copy.append('_' + attr)
+ if hasattr(cls, 'attributes_to_copy'):
+ cls.attributes_to_copy.append('_' + attr)
def getter(self):
return getattr(self, '_' + attr)
def setter(self, value):
@@ -40,22 +57,43 @@
setattr(new, attr, getattr(self, attr))
cls._copy_extra_attrs = _copy_extra_attrs
+ def int_is_null(self):
+ return False
+
+ def int_is_nonnull(self):
+ intbound = self.getintbound()
+ if intbound is not None:
+ if intbound.known_gt(IntBound(0, 0)) or \
+ intbound.known_lt(IntBound(0, 0)):
+ return True
+ return False
+ return False
+
+ def ref_is_null(self):
+ return False
+
+ def ref_is_nonnull(self):
+ return self.getknownclass() is not None or self.getknownnonnull()
+
imm_int_unbound = ImmutableIntUnbounded()
for i, cls in enumerate(opclasses):
if cls is None:
- Mutable = None
+ continue
+ elif opclasses_mutable[cls.getopnum()] is not None:
+ addattr(opclasses_mutable[cls.getopnum()], 'lastguardpos')
+ continue
else:
class Mutable(cls):
is_mutable = True
attributes_to_copy = []
- if cls.getopnum() in (rop.NEW_WITH_VTABLE, rop.NEW):
- def force(self, optimizer):
- optimizer.emit_operation(self)
- return self
- else:
- def force(self, _):
- return self
+ def force(self, _):
+ return self
+ def is_virtual(self):
+ return False
+ def is_forced_virtual(self):
+ return False
+
if cls.type != VOID:
addattr(Mutable, 'varindex', -1)
#if cls.type == REF:
@@ -66,16 +104,19 @@
# all the integers have bounds
addattr(Mutable, 'intbound', imm_int_unbound)
addattr(Mutable, 'boolres', False)
+ Mutable.is_nonnull = int_is_nonnull
+ Mutable.is_null = int_is_null
elif cls.type == REF:
addattr(Mutable, 'knownclass', None)
+ addattr(Mutable, 'knownnonnull', False)
+ Mutable.is_nonnull = ref_is_nonnull
+ Mutable.is_null = ref_is_null
# for tracking last guard and merging GUARD_VALUE with
# GUARD_NONNULL etc
addattr(Mutable, 'lastguardpos', -1)
Mutable.__name__ = cls.__name__ + '_mutable'
if Mutable.attributes_to_copy:
make_new_copy_function(Mutable, cls)
- assert len(opclasses_mutable) == i
- opclasses_mutable.append(Mutable)
- assert len(opclasses) == len(opclasses_mutable)
+ opclasses_mutable[i] = Mutable
create_mutable_subclasses()
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
@@ -485,9 +485,9 @@
# XXX this is a hack kill me
import sys
co_fname = sys._getframe(1).f_code.co_filename
- if co_fname.endswith('resume.py') or co_fname.endswith('optimizeopt/util.py') or 'backend/llgraph' in co_fname or 'backend/test' in co_fname or 'test/test_util' in co_fname:
+ if co_fname.endswith('resume.py') or co_fname.endswith('optimizeopt/util.py') or 'backend/llgraph' in co_fname or 'backend/test' in co_fname or 'test/test_util' in co_fname or co_fname.endswith('heap.py'):
return object.__hash__(self)
- raise Exception("Should not hash resops, use get/set extra instead")
+ raise Exception("Should not hash resops")
def _get_hash_(self):
""" rpython level implementation of hash, cache it because computations
@@ -1424,6 +1424,8 @@
pass
def setup(debug_print=False):
+ global opclasses_mutable
+
i = 0
for basename in _oplist:
if '/' in basename:
@@ -1466,6 +1468,7 @@
if k.startswith('CALL'):
ALLCALLS.append(v)
opgroups.ALLCALLS = tuple(ALLCALLS)
+ opclasses_mutable = [None] * len(opclasses)
def get_base_class(mixin, tpmixin, base):
try:
diff --git a/pypy/jit/metainterp/virtualmodel.py b/pypy/jit/metainterp/virtualmodel.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/virtualmodel.py
@@ -0,0 +1,57 @@
+
+from pypy.jit.metainterp.resoperation import rop, opclasses, create_resop_2
+from pypy.rlib.objectmodel import we_are_translated
+
+NEW_WITH_VTABLE = opclasses[rop.NEW_WITH_VTABLE]
+
+class Virtual(NEW_WITH_VTABLE):
+ is_mutable = True
+
+ def __init__(self, pval):
+ NEW_WITH_VTABLE.__init__(self, pval)
+ self._fields = {} # XXX convert from dict to a list
+ self._is_forced = False
+
+ def getfield(self, ofs, default):
+ return self._fields.get(ofs, default)
+
+ def setfield(self, ofs, fieldvalue):
+ self._fields[ofs] = fieldvalue
+
+ def getknownclass(self):
+ return self.getarg(0)
+
+ def setknownclass(self, cls):
+ pass # ignore
+
+ def is_nonnull(self):
+ return True
+
+ def is_null(self):
+ return False
+
+ def _copy_extra_attrs(self, new):
+ raise Exception("Virtual should not be forwarded")
+
+ def force(self, optimizer):
+ if not self._is_forced:
+ self._is_forced = True
+ optimizer.emit_operation(self)
+ iteritems = self._fields.iteritems()
+ if not we_are_translated(): #random order is fine, except for tests
+ iteritems = list(iteritems)
+ iteritems.sort(key = lambda (x,y): x.sort_key())
+ for ofs, value in iteritems:
+ if value.is_null():
+ continue
+ subbox = value.force(optimizer)
+ op = create_resop_2(rop.SETFIELD_GC, None, self, subbox,
+ descr=ofs)
+ optimizer.emit_operation(op)
+ return self
+
+ def is_virtual(self):
+ return not self._is_forced
+
+ def is_forced_virtual(self):
+ return self._is_forced
More information about the pypy-commit
mailing list