[pypy-commit] pypy default: Merged in clean-exported-state (pull request #490)
arigo
pypy.commits at gmail.com
Thu Nov 17 08:15:41 EST 2016
Author: Armin Rigo <armin.rigo at gmail.com>
Branch:
Changeset: r88431:ab8a0b092d2d
Date: 2016-11-17 13:14 +0000
http://bitbucket.org/pypy/pypy/changeset/ab8a0b092d2d/
Log: Merged in clean-exported-state (pull request #490)
Clean exported state
diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -108,7 +108,7 @@
"""
log_noopt = False
- def __init__(self, trace, celltoken, state,
+ def __init__(self, trace, celltoken, state, runtime_boxes,
call_pure_results=None, enable_opts=None,
inline_short_preamble=True):
self.trace = trace
@@ -117,6 +117,8 @@
self.state = state
self.call_pure_results = call_pure_results
self.inline_short_preamble = inline_short_preamble
+ assert runtime_boxes is not None
+ self.runtime_boxes = runtime_boxes
def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll):
from rpython.jit.metainterp.optimizeopt.unroll import UnrollOptimizer
@@ -124,7 +126,11 @@
assert unroll # we should not be here if it's disabled
opt = UnrollOptimizer(metainterp_sd, jitdriver_sd, optimizations)
return opt.optimize_peeled_loop(self.trace, self.celltoken, self.state,
- self.call_pure_results, self.inline_short_preamble)
+ self.runtime_boxes, self.call_pure_results, self.inline_short_preamble)
+
+ def forget_optimization_info(self):
+ self.state.forget_optimization_info()
+ CompileData.forget_optimization_info(self)
def show_procedures(metainterp_sd, procedure=None, error=None):
# debugging
@@ -290,7 +296,7 @@
start_descr = TargetToken(jitcell_token,
original_jitcell_token=jitcell_token)
jitcell_token.target_tokens = [start_descr]
- loop_data = UnrolledLoopData(trace, jitcell_token, start_state,
+ loop_data = UnrolledLoopData(trace, jitcell_token, start_state, jumpargs,
call_pure_results=call_pure_results,
enable_opts=enable_opts)
try:
@@ -360,7 +366,7 @@
history.record(rop.JUMP, jumpargs[:], None, descr=loop_jitcell_token)
enable_opts = jitdriver_sd.warmstate.enable_opts
call_pure_results = metainterp.call_pure_results
- loop_data = UnrolledLoopData(trace, loop_jitcell_token, start_state,
+ loop_data = UnrolledLoopData(trace, loop_jitcell_token, start_state, jumpargs,
call_pure_results=call_pure_results,
enable_opts=enable_opts)
try:
@@ -372,6 +378,7 @@
history.cut(cut)
history.record(rop.JUMP, jumpargs[:], None, descr=loop_jitcell_token)
loop_data = UnrolledLoopData(trace, loop_jitcell_token, start_state,
+ jumpargs,
call_pure_results=call_pure_results,
enable_opts=enable_opts,
inline_short_preamble=False)
@@ -516,7 +523,7 @@
for item in lst:
item.set_forwarded(None)
# XXX we should really do it, but we need to remember the values
- # somehoe for ContinueRunningNormally
+ # somehow for ContinueRunningNormally
if reset_values:
item.reset_value()
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -12,7 +12,7 @@
from rpython.jit.metainterp.optimize import InvalidLoop
from rpython.jit.metainterp.resoperation import rop, ResOperation, OpHelpers,\
AbstractResOp, GuardResOp
-from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.objectmodel import we_are_translated, we_are_debug
from rpython.jit.metainterp.optimizeopt import info
@@ -172,7 +172,7 @@
def _getfield(self, opinfo, descr, optheap, true_force=True):
res = opinfo.getfield(descr, optheap)
- if not we_are_translated() and res:
+ if we_are_debug() and res:
if isinstance(opinfo, info.AbstractStructPtrInfo):
assert opinfo in self.cached_infos
if isinstance(res, PreambleOp):
@@ -202,7 +202,7 @@
def _getfield(self, opinfo, descr, optheap, true_force=True):
res = opinfo.getitem(descr, self.index, optheap)
- if not we_are_translated() and res:
+ if we_are_debug() and res:
if isinstance(opinfo, info.ArrayPtrInfo):
assert opinfo in self.cached_infos
if (isinstance(res, PreambleOp) and
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -24,9 +24,20 @@
llhelper.CONST_NULLREF = llhelper.CONST_NULL
REMOVED = AbstractResOp()
+def check_no_forwarding(lsts):
+ for lst in lsts:
+ for op in lst:
+ assert op.get_forwarded() is None
+
class LoopInfo(object):
label_op = None
+ def _check_no_forwarding(self):
+ pass
+
+ def forget_optimization_info(self):
+ pass
+
class BasicLoopInfo(LoopInfo):
def __init__(self, inputargs, quasi_immutable_deps, jump_op):
self.inputargs = inputargs
@@ -555,7 +566,8 @@
return (BasicLoopInfo(trace.inputargs, self.quasi_immutable_deps, last_op),
self._newoperations)
- def _clean_optimization_info(self, lst):
+ @staticmethod
+ def _clean_optimization_info(lst):
for op in lst:
if op.get_forwarded() is not None:
op.set_forwarded(None)
diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py b/rpython/jit/metainterp/optimizeopt/shortpreamble.py
--- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py
+++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py
@@ -5,6 +5,7 @@
rop, AbstractResOp, AbstractInputArg
from rpython.jit.metainterp.history import Const, make_hashable_int,\
TreeLoop
+from rpython.jit.metainterp.optimize import InvalidLoop
from rpython.jit.metainterp.optimizeopt import info
class PreambleOp(AbstractResOp):
@@ -18,7 +19,7 @@
See force_op_from_preamble for details how the extra things are put.
"""
op = None
-
+
def __init__(self, op, preamble_op, invented_name):
self.op = op
self.preamble_op = preamble_op
@@ -51,7 +52,13 @@
class AbstractShortOp(object):
""" An operation that is potentially produced by the short preamble
"""
- pass
+ res = None
+
+ def _check_no_forwarding(self):
+ assert self.res.get_forwarded() is None
+
+ def forget_optimization_info(self):
+ self.res.clear_forwarded()
class HeapOp(AbstractShortOp):
def __init__(self, res, getfield_op):
@@ -101,6 +108,14 @@
descr=sop.getdescr())
return ProducedShortOp(self, preamble_op)
+ def _check_no_forwarding(self):
+ AbstractShortOp._check_no_forwarding(self)
+ assert self.getfield_op.get_forwarded() is None
+
+ def forget_optimization_info(self):
+ AbstractShortOp.forget_optimization_info(self)
+ self.getfield_op.clear_forwarded()
+
def __repr__(self):
return "HeapOp(%r)" % (self.res,)
@@ -193,6 +208,16 @@
l.append(pop)
return l
+ def _check_no_forwarding(self):
+ AbstractShortOp._check_no_forwarding(self)
+ self.one._check_no_forwarding()
+ self.two._check_no_forwarding()
+
+ def forget_optimization_info(self):
+ AbstractShortOp.forget_optimization_info(self)
+ self.one.forget_optimization_info()
+ self.two.forget_optimization_info()
+
def repr(self, memo):
return "CompoundOp(%s, %s, %s)" % (self.res.repr(memo),
self.one.repr(memo),
@@ -203,7 +228,7 @@
class ProducedShortOp(AbstractProducedShortOp):
invented_name = False
-
+
def __init__(self, short_op, preamble_op):
self.short_op = short_op
self.preamble_op = preamble_op
@@ -215,6 +240,14 @@
def repr(self, memo):
return self.short_op.repr(memo)
+ def _check_no_forwarding(self):
+ self.short_op._check_no_forwarding()
+ assert self.preamble_op.get_forwarded() is None
+
+ def forget_optimization_info(self):
+ self.short_op.forget_optimization_info()
+ self.preamble_op.clear_forwarded()
+
def __repr__(self):
return "%r -> %r" % (self.short_op, self.preamble_op)
@@ -235,6 +268,14 @@
def repr(self, memo):
return "INP(%s)" % (self.res.repr(memo),)
+ def _check_no_forwarding(self):
+ AbstractShortOp._check_no_forwarding(self)
+ assert self.preamble_op.get_forwarded() is None
+
+ def forget_optimization_info(self):
+ AbstractShortOp.forget_optimization_info(self)
+ self.preamble_op.clear_forwarded()
+
def __repr__(self):
return "INP(%r -> %r)" % (self.res, self.preamble_op)
@@ -454,16 +495,23 @@
self.sb = sb
self.extra_same_as = self.sb.extra_same_as
self.target_token = target_token
+ self.build_inplace = False
def setup(self, jump_args, short, label_args):
self.jump_args = jump_args
self.short = short
self.label_args = label_args
+ self.build_inplace = True
def add_preamble_op(self, preamble_op):
""" Notice that we're actually using the preamble_op, add it to
label and jump
"""
+ # Could this be considered a speculative error?
+ # This check should only fail when trying to jump to an existing trace
+ # by forcing portions of the virtualstate.
+ if not self.build_inplace:
+ raise InvalidLoop("Forcing boxes would modify an existing short preamble")
op = preamble_op.op.get_box_replacement()
if preamble_op.invented_name:
self.extra_same_as.append(op)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -573,6 +573,7 @@
#
compile_data.enable_opts = self.enable_opts
state = optimize_trace(metainterp_sd, None, compile_data)
+ state[0]._check_no_forwarding()
return state
def _convert_call_pure_results(self, d):
@@ -621,7 +622,7 @@
start_state, preamble_ops = self._do_optimize_loop(preamble_data)
preamble_data.forget_optimization_info()
loop_data = compile.UnrolledLoopData(preamble_data.trace,
- celltoken, start_state, call_pure_results)
+ celltoken, start_state, runtime_boxes, call_pure_results)
loop_info, ops = self._do_optimize_loop(loop_data)
preamble = TreeLoop('preamble')
preamble.inputargs = start_state.renamed_inputargs
diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py
--- a/rpython/jit/metainterp/optimizeopt/unroll.py
+++ b/rpython/jit/metainterp/optimizeopt/unroll.py
@@ -6,7 +6,7 @@
from rpython.jit.metainterp.optimizeopt import info, intutils
from rpython.jit.metainterp.optimize import InvalidLoop, SpeculativeError
from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer,\
- Optimization, LoopInfo, MININT, MAXINT, BasicLoopInfo
+ Optimization, LoopInfo, MININT, MAXINT, BasicLoopInfo, check_no_forwarding
from rpython.jit.metainterp.optimizeopt.vstring import StrPtrInfo
from rpython.jit.metainterp.optimizeopt.virtualstate import (
VirtualStateConstructor, VirtualStatesCantMatch)
@@ -35,7 +35,7 @@
def setinfo_from_preamble_list(self, lst, infos):
for item in lst:
- if item is None:
+ if item is None or isinstance(item, Const):
continue
i = infos.get(item, None)
if i is not None:
@@ -97,7 +97,6 @@
elif isinstance(preamble_info, info.FloatConstInfo):
op.set_forwarded(preamble_info._const)
-
class UnrollOptimizer(Optimization):
"""Unroll the loop into two iterations. The first one will
become the preamble or entry bridge (don't think there is a
@@ -115,26 +114,22 @@
return modifier.get_virtual_state(args)
def _check_no_forwarding(self, lsts, check_newops=True):
- for lst in lsts:
- for op in lst:
- assert op.get_forwarded() is None
+ check_no_forwarding(lsts)
if check_newops:
assert not self.optimizer._newoperations
-
def optimize_preamble(self, trace, runtime_boxes, call_pure_results, memo):
info, newops = self.optimizer.propagate_all_forward(
trace.get_iter(), call_pure_results, flush=False)
exported_state = self.export_state(info.jump_op.getarglist(),
- info.inputargs,
- runtime_boxes, memo)
+ info.inputargs, memo)
exported_state.quasi_immutable_deps = info.quasi_immutable_deps
# we need to absolutely make sure that we've cleaned up all
# the optimization info
self.optimizer._clean_optimization_info(self.optimizer._newoperations)
return exported_state, self.optimizer._newoperations
- def optimize_peeled_loop(self, trace, celltoken, state,
+ def optimize_peeled_loop(self, trace, celltoken, state, runtime_boxes,
call_pure_results, inline_short_preamble=True):
trace = trace.get_iter()
try:
@@ -186,7 +181,7 @@
try:
new_virtual_state = self.jump_to_existing_trace(
- end_jump, label_op, state.runtime_boxes, force_boxes=False)
+ end_jump, label_op, runtime_boxes, force_boxes=False)
except InvalidLoop:
# inlining short preamble failed, jump to preamble
self.jump_to_preamble(celltoken, end_jump, info)
@@ -199,7 +194,7 @@
# to the preamble.
try:
new_virtual_state = self.jump_to_existing_trace(
- end_jump, label_op, state.runtime_boxes, force_boxes=True)
+ end_jump, label_op, runtime_boxes, force_boxes=True)
except InvalidLoop:
pass
@@ -276,8 +271,7 @@
debug_print("Retrace count reached, jumping to preamble")
return self.jump_to_preamble(cell_token, jump_op, info)
exported_state = self.export_state(info.jump_op.getarglist(),
- info.inputargs, runtime_boxes,
- box_names_memo)
+ info.inputargs, box_names_memo)
exported_state.quasi_immutable_deps = self.optimizer.quasi_immutable_deps
self.optimizer._clean_optimization_info(self.optimizer._newoperations)
return exported_state, self.optimizer._newoperations
@@ -440,8 +434,7 @@
continue
self._expand_info(item, infos)
- def export_state(self, original_label_args, renamed_inputargs,
- runtime_boxes, memo):
+ def export_state(self, original_label_args, renamed_inputargs, memo):
end_args = [self.optimizer.force_box_for_end_of_preamble(a)
for a in original_label_args]
self.optimizer.flush()
@@ -462,16 +455,17 @@
op = produced_op.short_op.res
if not isinstance(op, Const):
self._expand_info(op, infos)
- self.optimizer._clean_optimization_info(end_args)
return ExportedState(label_args, end_args, virtual_state, infos,
short_boxes, renamed_inputargs,
- short_inputargs, runtime_boxes, memo)
+ short_inputargs, memo)
def import_state(self, targetargs, exported_state):
# the mapping between input args (from old label) and what we need
# to actually emit. Update the info
assert (len(exported_state.next_iteration_args) ==
len(targetargs))
+ self._check_no_forwarding([targetargs])
+ exported_state._check_no_forwarding()
for i, target in enumerate(exported_state.next_iteration_args):
source = targetargs[i]
assert source is not target
@@ -527,13 +521,11 @@
* renamed_inputargs - the start label arguments in optimized version
* short_inputargs - the renamed inputargs for short preamble
* quasi_immutable_deps - for tracking quasi immutables
- * runtime_boxes - runtime values for boxes, necessary when generating
- guards to jump to
"""
def __init__(self, end_args, next_iteration_args, virtual_state,
exported_infos, short_boxes, renamed_inputargs,
- short_inputargs, runtime_boxes, memo):
+ short_inputargs, memo):
self.end_args = end_args
self.next_iteration_args = next_iteration_args
self.virtual_state = virtual_state
@@ -541,8 +533,8 @@
self.short_boxes = short_boxes
self.renamed_inputargs = renamed_inputargs
self.short_inputargs = short_inputargs
- self.runtime_boxes = runtime_boxes
self.dump(memo)
+ self.forget_optimization_info()
def dump(self, memo):
if have_debug_prints():
@@ -552,5 +544,35 @@
debug_print(" " + box.repr(memo))
debug_stop("jit-log-exported-state")
+ def _check_no_forwarding(self):
+ """ Ensures that no optimization state is attached to relevant operations
+ before importing anything. """
+ # Some of these may be redunant
+ check_no_forwarding([
+ self.end_args,
+ self.next_iteration_args,
+ self.renamed_inputargs,
+ self.short_inputargs,
+ self.exported_infos.keys()])
+ for box in self.short_boxes:
+ box._check_no_forwarding()
+
+ def forget_optimization_info(self):
+ """ Clean up optimization info on all operations stored in the ExportedState.
+
+ This function needs to be called when exporting the optimizer state to
+ prevent leaking of optimization information between invocations of the
+ optimizer.
+
+ That includes cleaning up in the event that optimize_peeled_loop() fails
+ with an InvalidLoop exception, as optimize_peeled_loop() mutates the
+ contents of ExportedState.
+ """
+ Optimizer._clean_optimization_info(self.renamed_inputargs)
+ for box in self.exported_infos.iterkeys():
+ box.clear_forwarded()
+ for box in self.short_boxes:
+ box.forget_optimization_info()
+
def final(self):
return False
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1976,6 +1976,8 @@
self.aborted_tracing_greenkey = None
def retrace_needed(self, trace, exported_state):
+ if not we_are_translated():
+ exported_state._check_no_forwarding()
self.partial_trace = trace
self.retracing_from = self.potential_retrace_position
self.exported_state = exported_state
diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -52,6 +52,10 @@
llop.debug_print(lltype.Void, "setting forwarded on:", self.__class__.__name__)
raise SettingForwardedOnAbstractValue()
+ def clear_forwarded(self):
+ if self.get_forwarded() is not None:
+ self.set_forwarded(None)
+
@specialize.arg(1)
def get_box_replacement(op, not_const=False):
# Read the chain "op, op._forwarded, op._forwarded._forwarded..."
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -295,10 +295,15 @@
malloc_zero_filled = CDefinedIntSymbolic('MALLOC_ZERO_FILLED', default=0)
_translated_to_c = CDefinedIntSymbolic('1 /*_translated_to_c*/', default=0)
+_rpy_assert_value = CDefinedIntSymbolic('RPY_ASSERT_VALUE', default=1)
def we_are_translated_to_c():
return we_are_translated() and _translated_to_c
+def we_are_debug():
+ """ Returns True when not translated or translated with debugging enabled. """
+ return not we_are_translated() or (_translated_to_c and _rpy_assert_value)
+
# ____________________________________________________________
def instantiate(cls, nonmovable=False):
diff --git a/rpython/translator/c/src/support.h b/rpython/translator/c/src/support.h
--- a/rpython/translator/c/src/support.h
+++ b/rpython/translator/c/src/support.h
@@ -31,8 +31,10 @@
RPY_EXTERN
void RPyAssertFailed(const char* filename, long lineno,
const char* function, const char *msg);
+# define RPY_ASSERT_VALUE 1
#else
# define RPyAssert(x, msg) /* nothing */
+# define RPY_ASSERT_VALUE 0
#endif
RPY_EXTERN
More information about the pypy-commit
mailing list