[pypy-commit] lang-smalltalk default: Switched from a context return based implementation to Exception Raising returns.
lwassermann
noreply at buildbot.pypy.org
Wed Mar 6 21:16:28 CET 2013
Author: Lars Wassermann <lars.wassermann at gmail.com>
Branch:
Changeset: r121:079f6dd1e62f
Date: 2013-03-05 17:14 +0100
http://bitbucket.org/pypy/lang-smalltalk/changeset/079f6dd1e62f/
Log: Switched from a context return based implementation to Exception
Raising returns. This way, contexts are not manipulated during
return, but on catching the exception.
diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -28,8 +28,8 @@
_last_indent = ""
jit_driver = jit.JitDriver(
greens=['pc', 'self', 'method'],
- reds=['s_active_context'],
- #virtualizables=['s_active_context'],
+ reds=['mark', 's_context'],
+ #virtualizables=['s_context'],
get_printable_location=get_printable_location
)
@@ -60,25 +60,31 @@
s_new_context = w_active_context.as_context_get_shadow(self.space)
while True:
try:
- s_new_context = self.c_loop(s_new_context)
+ s_new_context = self.c_loop(s_new_context, mark=False)
except StackOverflow, e:
self.remaining_stack_depth = self.max_stack_depth
s_new_context = e.s_context
+ except Return, nlr:
+ while s_new_context is not nlr.s_target_context:
+ s_new_context, _ = s_new_context.s_sender(), s_new_context.mark_returned()
+ s_new_context.push(nlr.value)
- def c_loop(self, s_context):
- s_active_context = s_context
+ def c_loop(self, s_context, mark=True):
while True:
- pc = s_active_context._pc
- method = s_active_context.s_method()
+ pc = s_context._pc
+ method = s_context.s_method()
self.jit_driver.jit_merge_point(
pc=pc, self=self, method=method,
- s_active_context=s_active_context)
- s_return_to_context = self.step(s_active_context)
- if (s_return_to_context is not None
- and s_return_to_context is not s_context):
- s_active_context.mark_returned()
- return s_return_to_context
+ mark=mark, s_context=s_context)
+ try:
+ self.step(s_context)
+ except Return, nlr:
+ if nlr.s_target_context is not s_context:
+ if mark: s_context.mark_returned()
+ raise nlr
+ else:
+ s_context.push(nlr.value)
def stack_frame(self, s_new_frame):
if not self._loop:
@@ -88,8 +94,10 @@
raise StackOverflow(s_new_frame)
self.remaining_stack_depth -= 1
- retval = self.c_loop(s_new_frame)
- self.remaining_stack_depth += 1
+ try:
+ retval = self.c_loop(s_new_frame)
+ finally:
+ self.remaining_stack_depth += 1
return retval
def perform(self, w_receiver, selector, *arguments_w):
@@ -109,7 +117,11 @@
s_frame.push(w_receiver)
s_frame.push_all(list(arguments_w))
try:
- s_new_frame = s_frame._sendSelfSelector(w_selector, len(arguments_w), self)
+ try:
+ s_new_frame = s_frame._sendSelfSelector(w_selector, len(arguments_w), self)
+ except Return, nlr:
+ s_new_frame = nlr.s_target_context
+ nlr.s_target_context.push(nlr.value)
if s_new_frame == None:
# which means that we tried to call a primitive method
return s_frame.pop()
@@ -125,6 +137,10 @@
class StackOverflow(Exception):
def __init__(self, s_top_context):
self.s_context = s_top_context
+class Return(Exception):
+ def __init__(self, object, s_context):
+ self.value = object
+ self.s_target_context = s_context
def make_call_primitive_bytecode(primitive, selector, argcount):
def callPrimitive(self, interp, current_bytecode):
@@ -281,11 +297,7 @@
# unfortunately, the assert below is not true for some tests
# assert self._stack_ptr == self.tempsize()
- # make this context a returned one
- self.mark_returned()
-
- s_return_to.push(return_value)
- return s_return_to
+ raise Return(return_value, s_return_to)
def returnReceiver(self, interp, current_bytecode):
return self._return(self.w_receiver(), interp, self.s_home().s_sender())
@@ -695,7 +707,7 @@
code.append(" %sif %s:" % (prefix, cond, ))
code.append(" return context.%s(self, bytecode)" % (entry[-1], ))
prefix = "el"
- code.append("bytecode_step_translated._always_inline_ = True")
+ # code.append("bytecode_step_translated._always_inline_ = True")
source = py.code.Source("\n".join(code))
#print source
miniglob = {}
diff --git a/spyvm/test/test_interpreter.py b/spyvm/test/test_interpreter.py
--- a/spyvm/test/test_interpreter.py
+++ b/spyvm/test/test_interpreter.py
@@ -8,10 +8,13 @@
interp = interpreter.Interpreter(space)
def step_in_interp(ctxt): # due to missing resets in between tests
interp._loop = False
- return_value = interp.step(ctxt)
- if return_value is not None:
- return return_value.w_self()
- return None
+ try:
+ retval = interp.step(ctxt)
+ if retval is not None:
+ return retval.w_self()
+ except interpreter.Return, nlr:
+ nlr.s_target_context.push(nlr.value)
+ return nlr.s_target_context.w_self()
# expose the bytecode's values as global constants.
# Bytecodes that have a whole range are exposed as global functions:
@@ -988,9 +991,10 @@
assert False
try:
interp = interpreter.Interpreter(space, None, "", max_stack_depth=10)
+ interp._loop = True
interp.c_loop(w_method.as_compiledmethod_get_shadow(space).create_frame(space, space.wrap_int(0), []))
except interpreter.StackOverflow, e:
- assert e.w_context.getclass(space) is space.w_MethodContext
+ assert isinstance(e.s_context, shadow.MethodContextShadow)
except interpreter.ReturnFromTopLevel, e:
assert False
More information about the pypy-commit
mailing list