[pypy-commit] lang-smalltalk storage-vrefs-rstackovf-localreturn: avoid forcing s_sender for local returns (that is, all returns from methods and return top from block)
timfel
noreply at buildbot.pypy.org
Thu Jul 10 15:29:26 CEST 2014
Author: Tim Felgentreff <timfelgentreff at gmail.com>
Branch: storage-vrefs-rstackovf-localreturn
Changeset: r886:71d4742bcc58
Date: 2014-07-10 14:08 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/71d4742bcc58/
Log: avoid forcing s_sender for local returns (that is, all returns from
methods and return top from block)
diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -75,11 +75,13 @@
print "====== StackOverflow, contexts forced to heap at: %s" % e.s_new_context.short_str()
s_new_context = e.s_new_context
except Return, nlr:
+ assert nlr.s_target_context or nlr.is_local
s_new_context = s_sender
- while s_new_context is not nlr.s_target_context:
- s_sender = s_new_context.direct_sender
- s_new_context._activate_unwind_context(self)
- s_new_context = s_sender
+ if not nlr.is_local:
+ while s_new_context is not nlr.s_target_context:
+ s_sender = s_new_context.direct_sender
+ s_new_context._activate_unwind_context(self)
+ s_new_context = s_sender
s_new_context.push(nlr.value)
except ProcessSwitch, p:
if self.trace:
@@ -108,11 +110,16 @@
try:
self.step(s_context)
except Return, nlr:
- if nlr.s_target_context is not s_context:
+ if nlr.s_target_context is s_context or nlr.is_local:
+ s_context.push(nlr.value)
+ else:
+ if nlr.s_target_context is None:
+ # This is the case where we are returning to our sender.
+ # Mark the return as local, so our sender will take it
+ nlr.is_local = True
s_context._activate_unwind_context(self)
raise nlr
- else:
- s_context.push(nlr.value)
+
# This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame
# and handles the stack overflow protection mechanism.
@@ -237,10 +244,11 @@
self.object = object
class Return(Exception):
- _attrs_ = ["value", "s_target_context"]
+ _attrs_ = ["value", "s_target_context", "is_local"]
def __init__(self, s_target_context, w_result):
self.value = w_result
self.s_target_context = s_target_context
+ self.is_local = False
class ContextSwitchException(Exception):
"""General Exception that causes the interpreter to leave
@@ -636,7 +644,7 @@
interp.padding(), code, w_method.safe_identifier_string(), w_selector.str_content())
raise e
- def _return(self, return_value, interp, s_return_to):
+ def _return(self, return_value, interp, local_return=False):
# unfortunately, this assert is not true for some tests. TODO fix this.
# assert self._stack_ptr == self.tempsize()
@@ -644,36 +652,47 @@
if interp.trace:
print '%s<- %s' % (interp.padding(), return_value.as_repr_string())
- if s_return_to is None:
- # This should never happen while executing a normal image.
- raise ReturnFromTopLevel(return_value)
+ if self.home_is_self() or local_return:
+ # a local return just needs to go up the stack once. there
+ # it will find the sender as a local, and we don't have to
+ # force the reference
+ s_return_to = None
+ if self.direct_sender is None and self.virtual_sender is jit.vref_None:
+ # This should never happen while executing a normal image.
+ raise ReturnFromTopLevel(return_value)
+ else:
+ s_return_to = self.s_home().s_sender()
+ if s_return_to is None:
+ # This should never happen while executing a normal image.
+ raise ReturnFromTopLevel(return_value)
+
raise Return(s_return_to, return_value)
# ====== Send/Return bytecodes ======
@bytecode_implementation()
def returnReceiverBytecode(self, interp, current_bytecode):
- return self._return(self.w_receiver(), interp, self.s_home().s_sender())
+ return self._return(self.w_receiver(), interp)
@bytecode_implementation()
def returnTrueBytecode(self, interp, current_bytecode):
- return self._return(interp.space.w_true, interp, self.s_home().s_sender())
+ return self._return(interp.space.w_true, interp)
@bytecode_implementation()
def returnFalseBytecode(self, interp, current_bytecode):
- return self._return(interp.space.w_false, interp, self.s_home().s_sender())
+ return self._return(interp.space.w_false, interp)
@bytecode_implementation()
def returnNilBytecode(self, interp, current_bytecode):
- return self._return(interp.space.w_nil, interp, self.s_home().s_sender())
+ return self._return(interp.space.w_nil, interp)
@bytecode_implementation()
def returnTopFromMethodBytecode(self, interp, current_bytecode):
- return self._return(self.pop(), interp, self.s_home().s_sender())
+ return self._return(self.pop(), interp)
@bytecode_implementation()
def returnTopFromBlockBytecode(self, interp, current_bytecode):
- return self._return(self.pop(), interp, self.s_sender())
+ return self._return(self.pop(), interp, local_return=True)
@bytecode_implementation()
def sendLiteralSelectorBytecode(self, interp, current_bytecode):
@@ -754,7 +773,8 @@
try:
self.bytecodePrimValue(interp, 0)
except Return, nlr:
- if self is not nlr.s_target_context:
+ assert nlr.s_target_context or nlr.is_local
+ if self is not nlr.s_target_context and not nlr.is_local:
raise nlr
finally:
self.mark_returned()
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -800,6 +800,9 @@
def is_closure_context(self):
raise NotImplementedError()
+ def home_is_self(self):
+ raise NotImplementedError()
+
# === Other properties of Contexts ===
def mark_returned(self):
@@ -1018,6 +1021,9 @@
def is_closure_context(self):
return True
+ def home_is_self(self):
+ return False
+
# === Temporary variables ===
def gettemp(self, index):
@@ -1209,6 +1215,9 @@
def is_closure_context(self):
return self.closure is not None
+ def home_is_self(self):
+ return not self.is_closure_context()
+
# ______________________________________________________________________
# Marriage of MethodContextShadows with PointerObjects only when required
More information about the pypy-commit
mailing list