[pypy-commit] lang-smalltalk storage: Merged.
anton_gulenko
noreply at buildbot.pypy.org
Fri Jul 18 14:08:25 CEST 2014
Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage
Changeset: r900:f71c6de0dab8
Date: 2014-07-10 21:31 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/f71c6de0dab8/
Log: Merged.
diff --git a/spyvm/constants.py b/spyvm/constants.py
--- a/spyvm/constants.py
+++ b/spyvm/constants.py
@@ -190,6 +190,5 @@
# Interpreter constants
#
-MAX_LOOP_DEPTH = 100
INTERRUPT_COUNTER_SIZE = 10000
CompileTime = time.time()
diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -4,7 +4,7 @@
from spyvm import model, constants, primitives, conftest, wrapper
from spyvm.tool.bitmanipulation import splitter
-from rpython.rlib import jit
+from rpython.rlib import jit, rstackovf
from rpython.rlib import objectmodel, unroll
class MissingBytecode(Exception):
@@ -24,7 +24,7 @@
class Interpreter(object):
_immutable_fields_ = ["space", "image", "image_name",
- "max_stack_depth", "interrupt_counter_size",
+ "interrupt_counter_size",
"startup_time", "evented", "interrupts"]
jit_driver = jit.JitDriver(
@@ -35,8 +35,7 @@
)
def __init__(self, space, image=None, image_name="",
- trace=False, evented=True, interrupts=True,
- max_stack_depth=constants.MAX_LOOP_DEPTH):
+ trace=False, evented=True, interrupts=True):
import time
# === Initialize immutable variables
@@ -47,7 +46,6 @@
self.startup_time = image.startup_time
else:
self.startup_time = constants.CompileTime
- self.max_stack_depth = max_stack_depth
self.evented = evented
self.interrupts = interrupts
try:
@@ -57,7 +55,6 @@
# === Initialize mutable variables
self.interrupt_check_counter = self.interrupt_counter_size
- self.current_stack_depth = 0
self.next_wakeup_tick = 0
self.trace = trace
self.trace_proxy = False
@@ -66,7 +63,6 @@
# This is the top-level loop and is not invoked recursively.
s_new_context = w_active_context.as_context_get_shadow(self.space)
while True:
- assert self.current_stack_depth == 0
s_sender = s_new_context.s_sender()
try:
self.loop_bytecodes(s_new_context)
@@ -76,11 +72,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.s_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.s_sender()
+ s_new_context._activate_unwind_context(self)
+ s_new_context = s_sender
s_new_context.push(nlr.value)
except ProcessSwitch, p:
assert not self.space.suppress_process_switch[0], "ProcessSwitch should be disabled..."
@@ -110,11 +108,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.
@@ -122,16 +125,11 @@
try:
if s_frame._s_sender is None and s_sender is not None:
s_frame.store_s_sender(s_sender, raise_error=False)
-
- self.current_stack_depth += 1
- if self.max_stack_depth > 0:
- if self.current_stack_depth >= self.max_stack_depth:
- raise StackOverflow(s_frame)
-
# Now (continue to) execute the context bytecodes
self.loop_bytecodes(s_frame, may_context_switch)
- finally:
- self.current_stack_depth -= 1
+ except rstackovf.StackOverflow:
+ rstackovf.check_stack_overflow()
+ raise StackOverflow(s_frame)
def step(self, context):
bytecode = context.fetch_next_bytecode()
@@ -205,7 +203,7 @@
s_frame = self.create_toplevel_context(w_receiver, selector, w_selector, w_arguments)
self.interrupt_check_counter = self.interrupt_counter_size
return self.interpret_toplevel(s_frame.w_self())
-
+
def create_toplevel_context(self, w_receiver, selector="", w_selector=None, w_arguments=[]):
if w_selector is None:
assert selector, "Need either string or W_Object selector"
@@ -213,7 +211,7 @@
w_selector = self.image.w_asSymbol
else:
w_selector = self.perform(self.space.wrap_string(selector), "asSymbol")
-
+
w_method = model.W_CompiledMethod(self.space, header=512)
w_method.literalatput0(self.space, 1, w_selector)
assert len(w_arguments) <= 7
@@ -225,7 +223,7 @@
return s_frame
def padding(self, symbol=' '):
- return symbol * self.current_stack_depth
+ return symbol
class ReturnFromTopLevel(Exception):
_attrs_ = ["object"]
@@ -233,10 +231,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
@@ -632,7 +631,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()
@@ -640,36 +639,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.s_sender() is 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):
@@ -738,9 +748,7 @@
# ====== Misc ======
def _activate_unwind_context(self, interp):
- # TODO put the constant somewhere else.
- # Primitive 198 is used in BlockClosure >> ensure:
- if self.is_closure_context() or self.w_method().primitive() != 198:
+ if self.is_closure_context() or not self.is_BlockClosure_ensure():
self.mark_returned()
return
# The first temp is executed flag for both #ensure: and #ifCurtailed:
@@ -750,7 +758,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()
@@ -964,11 +973,9 @@
# in order to enable tracing/jumping for message sends etc.
def debugging():
def stepping_debugger_init(original):
- def meth(self, space, image=None, image_name="", trace=False,
- max_stack_depth=constants.MAX_LOOP_DEPTH):
+ def meth(self, space, image=None, image_name="", trace=False):
return_value = original(self, space, image=image,
- image_name=image_name, trace=trace,
- max_stack_depth=max_stack_depth)
+ image_name=image_name, trace=trace)
# ##############################################################
self.message_stepping = False
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -797,6 +797,12 @@
def is_closure_context(self):
raise NotImplementedError()
+ def is_BlockClosure_ensure(self):
+ raise NotImplementedError()
+
+ def home_is_self(self):
+ raise NotImplementedError()
+
# === Other properties of Contexts ===
def mark_returned(self):
@@ -1015,6 +1021,12 @@
def is_closure_context(self):
return True
+ def is_BlockClosure_ensure(self):
+ return False
+
+ def home_is_self(self):
+ return False
+
# === Temporary variables ===
def gettemp(self, index):
@@ -1094,7 +1106,7 @@
return '[] in %s' % self.w_method().get_identifier_string()
class MethodContextShadow(ContextPartShadow):
- _attrs_ = ['closure', '_w_receiver', '_w_method']
+ _attrs_ = ['closure', '_w_receiver', '_w_method', '_is_BlockClosure_ensure']
repr_classname = "MethodContextShadow"
# === Initialization ===
@@ -1116,6 +1128,7 @@
self.init_stack_and_temps()
else:
self._w_method = None
+ self._is_BlockClosure_ensure = False
argc = len(arguments)
for i0 in range(argc):
@@ -1188,6 +1201,9 @@
def store_w_method(self, w_method):
assert isinstance(w_method, model.W_CompiledMethod)
self._w_method = w_method
+ if w_method:
+ # Primitive 198 is used in BlockClosure >> ensure:
+ self._is_BlockClosure_ensure = (w_method.primitive() == 198)
def w_receiver(self):
return self._w_receiver
@@ -1206,6 +1222,12 @@
def is_closure_context(self):
return self.closure is not None
+ def is_BlockClosure_ensure(self):
+ return self._is_BlockClosure_ensure
+
+ def home_is_self(self):
+ return not self.is_closure_context()
+
# ______________________________________________________________________
# Marriage of MethodContextShadows with PointerObjects only when required
diff --git a/spyvm/test/jittest/base.py b/spyvm/test/jittest/base.py
--- a/spyvm/test/jittest/base.py
+++ b/spyvm/test/jittest/base.py
@@ -18,7 +18,7 @@
def run(self, spy, tmpdir, code):
logfile = str(tmpdir.join("x.pypylog"))
proc = subprocess.Popen(
- [str(spy), "-r", code.replace("\n", "\r\n"), BenchmarkImage],
+ [str(spy), BenchmarkImage, "-r", code.replace("\n", "\r\n")],
cwd=str(tmpdir),
env={"PYPYLOG": "jit-log-opt:%s" % logfile,
"SDL_VIDEODRIVER": "dummy"}
diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py
--- a/targetimageloadingsmalltalk.py
+++ b/targetimageloadingsmalltalk.py
@@ -14,13 +14,13 @@
print """
Usage: %s <path> [-r|-m] [-naHu] [-jpis] [-tlLE]
<path> - image path (default: Squeak.image)
-
+
Execution mode:
(no flags) - Image will be normally opened.
-r|--run <code> - Code will be compiled and executed, result printed.
-m|--method <selector> - Selector will be sent to a SmallInteger, result printed.
-h|--help - Output this and exit.
-
+
Execution parameters:
-n|--num <int> - Only with -m or -r, SmallInteger to be used as receiver (default: nil).
-a|--arg <arg> - Only with -m, will be used as single String argument.
@@ -30,7 +30,7 @@
in the image and execute the context directly. The image window will
probably not open. Good for benchmarking.
-u - Only with -m or -r, try to stop UI-process at startup. Can help benchmarking.
-
+
Other parameters:
-j|--jit <jitargs> - jitargs will be passed to the jit configuration.
-p|--poll - Actively poll for events. Try this if the image is not responding well.
@@ -45,8 +45,8 @@
-l|--storage-log - Output a log of storage operations.
-L|--storage-log-aggregate - Output an aggregated storage log at the end of execution.
-E|--storage-log-elements - Include classnames of elements into the storage log.
-
- """ % (argv[0], constants.MAX_LOOP_DEPTH)
+
+ """ % argv[0]
def get_parameter(argv, idx, arg):
if len(argv) < idx + 1:
@@ -78,7 +78,6 @@
# == Other parameters
poll = False
interrupts = True
- max_stack_depth = constants.MAX_LOOP_DEPTH
trace = False
space = prebuilt_space
@@ -147,13 +146,13 @@
except OSError as e:
print_error("%s -- %s (LoadError)" % (os.strerror(e.errno), path))
return 1
-
+
# Load & prepare image and environment
image_reader = squeakimage.reader_for_image(space, squeakimage.Stream(data=imagedata))
image = create_image(space, image_reader)
interp = interpreter.Interpreter(space, image, image_name=path,
trace=trace, evented=not poll,
- interrupts=interrupts, max_stack_depth=max_stack_depth)
+ interrupts=interrupts)
space.runtime_setup(argv[0])
print_error("") # Line break after image-loading characters
@@ -175,7 +174,7 @@
context = active_context(interp.space)
else:
context = active_context(interp.space)
-
+
w_result = execute_context(interp, context)
print result_string(w_result)
storage_logger.print_aggregated_log()
@@ -219,13 +218,13 @@
interp.space.suppress_process_switch[0] = False
w_receiver_class.as_class_get_shadow(space).s_methoddict().sync_method_cache()
return selector
-
+
def create_context(interp, w_receiver, selector, stringarg):
args = []
if stringarg:
args.append(interp.space.wrap_string(stringarg))
return interp.create_toplevel_context(w_receiver, selector, w_arguments = args)
-
+
def create_process(interp, s_frame):
space = interp.space
w_active_process = wrapper.scheduler(space).active_process()
@@ -242,10 +241,10 @@
priority = 7
w_benchmark_proc.store(space, 1, s_frame.w_self())
w_benchmark_proc.store(space, 2, space.wrap_int(priority))
-
+
# Make process eligible for scheduling
wrapper.ProcessWrapper(space, w_benchmark_proc).put_to_sleep()
-
+
def active_context(space):
w_active_process = wrapper.scheduler(space).active_process()
active_process = wrapper.ProcessWrapper(space, w_active_process)
@@ -260,7 +259,7 @@
except error.Exit, e:
print_error("Exited: %s" % e.msg)
return None
-
+
# _____ Target and Main _____
def target(driver, *args):
More information about the pypy-commit
mailing list