[pypy-svn] r70714 - in pypy/trunk/pypy/jit/metainterp: . test
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Jan 19 18:01:17 CET 2010
Author: cfbolz
Date: Tue Jan 19 18:01:16 2010
New Revision: 70714
Modified:
pypy/trunk/pypy/jit/metainterp/compile.py
pypy/trunk/pypy/jit/metainterp/history.py
pypy/trunk/pypy/jit/metainterp/optimizeopt.py
pypy/trunk/pypy/jit/metainterp/pyjitpl.py
pypy/trunk/pypy/jit/metainterp/resoperation.py
pypy/trunk/pypy/jit/metainterp/test/test_basic.py
pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py
pypy/trunk/pypy/jit/metainterp/test/test_virtualref.py
Log:
Fix the bug that the previous test showed: optimizeopt can mutate operations in
ways that become a problem when the loop later proves to be invalid. This fix is
conservative in the sense that it always makes a copy of all operations, instead
of trying to make optimizeopt more careful. I wasn't sure enough that I would
catch all cases I I had tried that.
Modified: pypy/trunk/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/compile.py (original)
+++ pypy/trunk/pypy/jit/metainterp/compile.py Tue Jan 19 18:01:16 2010
@@ -54,9 +54,11 @@
for box in loop.inputargs:
assert isinstance(box, Box)
if start > 0:
- loop.operations = history.operations[start:]
+ ops = history.operations[start:]
else:
- loop.operations = history.operations
+ ops = history.operations
+ # make a copy, because optimize_loop can mutate the ops and descrs
+ loop.operations = [op.clone() for op in ops]
metainterp_sd = metainterp.staticdata
loop_token = make_loop_token(len(loop.inputargs))
loop.token = loop_token
@@ -203,11 +205,18 @@
class ResumeDescr(AbstractFailDescr):
def __init__(self, original_greenkey):
self.original_greenkey = original_greenkey
+ def _clone_if_mutable(self):
+ raise NotImplementedError
class ResumeGuardDescr(ResumeDescr):
counter = 0
- # this class also gets attributes stored by resume.py code
+ # this class also gets the following attributes stored by resume.py code
+ rd_snapshot = None
+ rd_frame_info_list = None
rd_numb = None
+ rd_consts = None
+ rd_virtuals = None
+ rd_pendingfields = None
def __init__(self, metainterp_sd, original_greenkey):
ResumeDescr.__init__(self, original_greenkey)
@@ -232,6 +241,17 @@
new_loop.operations)
+ def _clone_if_mutable(self):
+ res = self.__class__(self.metainterp_sd, self.original_greenkey)
+ # XXX a bit ugly to have to list them all here
+ res.rd_snapshot = self.rd_snapshot
+ res.rd_frame_info_list = self.rd_frame_info_list
+ res.rd_numb = self.rd_numb
+ res.rd_consts = self.rd_consts
+ res.rd_virtuals = self.rd_virtuals
+ res.rd_pendingfields = self.rd_pendingfields
+ return res
+
class ResumeGuardForcedDescr(ResumeGuardDescr):
def handle_fail(self, metainterp_sd):
@@ -337,13 +357,15 @@
# it does not work -- i.e. none of the existing old_loop_tokens match.
new_loop = create_empty_loop(metainterp)
new_loop.inputargs = metainterp.history.inputargs
- new_loop.operations = metainterp.history.operations
+ # clone ops, as optimize_bridge can mutate the ops
+ new_loop.operations = [op.clone() for op in metainterp.history.operations]
metainterp_sd = metainterp.staticdata
try:
target_loop_token = metainterp_sd.state.optimize_bridge(metainterp_sd,
old_loop_tokens,
new_loop)
except InvalidLoop:
+ assert 0
return None
# Did it work?
if target_loop_token is not None:
Modified: pypy/trunk/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/history.py (original)
+++ pypy/trunk/pypy/jit/metainterp/history.py Tue Jan 19 18:01:16 2010
@@ -122,6 +122,9 @@
def repr_of_descr(self):
return '%r' % (self,)
+ def _clone_if_mutable(self):
+ return self
+
class AbstractFailDescr(AbstractDescr):
index = -1
Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/optimizeopt.py (original)
+++ pypy/trunk/pypy/jit/metainterp/optimizeopt.py Tue Jan 19 18:01:16 2010
@@ -515,20 +515,16 @@
# accumulate counters
self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
- def emit_operation(self, op, must_clone=True):
+ def emit_operation(self, op):
self.heap_op_optimizer.emitting_operation(op)
- self._emit_operation(op, must_clone)
+ self._emit_operation(op)
- def _emit_operation(self, op, must_clone=True):
+ def _emit_operation(self, op):
for i in range(len(op.args)):
arg = op.args[i]
if arg in self.values:
box = self.values[arg].force_box()
- if box is not arg:
- if must_clone:
- op = op.clone()
- must_clone = False
- op.args[i] = box
+ op.args[i] = box
self.metainterp_sd.profiler.count(jitprof.OPT_OPS)
if op.is_guard():
self.metainterp_sd.profiler.count(jitprof.OPT_GUARDS)
@@ -588,9 +584,8 @@
for i in range(len(specnodes)):
value = self.getvalue(op.args[i])
specnodes[i].teardown_virtual_node(self, value, exitargs)
- op2 = op.clone()
- op2.args = exitargs[:]
- self.emit_operation(op2, must_clone=False)
+ op.args = exitargs[:]
+ self.emit_operation(op)
def optimize_guard(self, op, constbox, emit_operation=True):
value = self.getvalue(op.args[0])
Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Tue Jan 19 18:01:16 2010
@@ -1613,17 +1613,9 @@
# we cannot reconstruct the beginning of the proper loop
raise GiveUp
- oldops = self.history.operations[:]
# raises in case it works -- which is the common case
self.compile(original_boxes, live_arg_boxes, start)
- # creation of the loop was cancelled! Patch
- # history.operations so that it contains again
- # exactly its old list of operations...
- # xxx maybe we could patch history.operations with
- # Nones after calling self.compile() instead of
- # before... xxx maybe we should just raise GiveUp
- del self.history.operations[:]
- self.history.operations.extend(oldops)
+ # creation of the loop was cancelled!
# Otherwise, no loop found so far, so continue tracing.
start = len(self.history.operations)
@@ -1661,6 +1653,7 @@
greenkey, start)
if loop_token is not None: # raise if it *worked* correctly
raise GenerateMergePoint(live_arg_boxes, loop_token)
+ self.history.operations.pop() # remove the JUMP
def compile_bridge(self, live_arg_boxes):
num_green_args = self.staticdata.num_green_args
Modified: pypy/trunk/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/resoperation.py (original)
+++ pypy/trunk/pypy/jit/metainterp/resoperation.py Tue Jan 19 18:01:16 2010
@@ -31,7 +31,11 @@
self.descr = descr
def clone(self):
- op = ResOperation(self.opnum, self.args, self.result, self.descr)
+ descr = self.descr
+ if descr is not None:
+ descr = descr._clone_if_mutable()
+ op = ResOperation(self.opnum, self.args, self.result, descr)
+ op.fail_args = self.fail_args
if not we_are_translated():
op.name = self.name
op.pc = self.pc
Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_basic.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py Tue Jan 19 18:01:16 2010
@@ -1249,7 +1249,6 @@
assert res == 3 * 21
self.check_loops(call=1)
- @py.test.mark.xfail
def test_bug_optimizeopt_mutates_ops(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'res', 'a', 'const'])
class A(object):
@@ -1284,7 +1283,7 @@
const = 1
return res
res = self.meta_interp(f, [21])
- assert res == 120
+ assert res == f(21)
class TestOOtype(BasicTests, OOJitMixin):
Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py Tue Jan 19 18:01:16 2010
@@ -207,8 +207,9 @@
class Storage(compile.ResumeGuardDescr):
"for tests."
- def __init__(self):
- pass
+ def __init__(self, metainterp_sd=None, original_greenkey=None):
+ self.metainterp_sd = metainterp_sd
+ self.original_greenkey = original_greenkey
def store_final_boxes(self, op, boxes):
op.fail_args = boxes
def __eq__(self, other):
Modified: pypy/trunk/pypy/jit/metainterp/test/test_virtualref.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_virtualref.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_virtualref.py Tue Jan 19 18:01:16 2010
@@ -69,7 +69,8 @@
assert res == 5
self.check_operations_history(virtual_ref=1, guard_not_forced=1)
#
- [guard_op] = [op for op in self.metainterp.history.operations
+ ops = self.metainterp.staticdata.stats.loops[0].operations
+ [guard_op] = [op for op in ops
if op.opnum == rop.GUARD_NOT_FORCED]
bxs1 = [box for box in guard_op.fail_args
if str(box._getrepr_()).endswith('.X')]
More information about the Pypy-commit
mailing list