[pypy-commit] lang-smalltalk storage: Added a stack_deth mechanism, but only if interp.trace is set.
anton_gulenko
noreply at buildbot.pypy.org
Fri Jul 18 14:08:28 CEST 2014
Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage
Changeset: r902:4c9262d36e3b
Date: 2014-07-13 15:55 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/4c9262d36e3b/
Log: Added a stack_deth mechanism, but only if interp.trace is set. Added
a ConstantFlag class to make CLI flags (and other boolean flags)
constant for jit traces (promoted). A few code cleanups.
diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -1,7 +1,7 @@
import py
import os
from spyvm.shadow import ContextPartShadow, MethodContextShadow, BlockContextShadow, MethodNotFound
-from spyvm import model, constants, primitives, conftest, wrapper
+from spyvm import model, constants, primitives, conftest, wrapper, objspace
from spyvm.tool.bitmanipulation import splitter
from rpython.rlib import jit, rstackovf
@@ -36,8 +36,6 @@
def __init__(self, space, image=None, image_name="",
trace=False, evented=True, interrupts=True):
- import time
-
# === Initialize immutable variables
self.space = space
self.image = image
@@ -56,8 +54,9 @@
# === Initialize mutable variables
self.interrupt_check_counter = self.interrupt_counter_size
self.next_wakeup_tick = 0
- self.trace = trace
- self.trace_proxy = False
+ self.trace = objspace.ConstantFlag(trace)
+ self.trace_proxy = objspace.ConstantFlag()
+ self.stack_depth = 0
def loop(self, w_active_context):
# This is the top-level loop and is not invoked recursively.
@@ -68,7 +67,7 @@
self.loop_bytecodes(s_new_context)
raise Exception("loop_bytecodes left without raising...")
except StackOverflow, e:
- if self.trace:
+ if self.is_tracing():
print "====== StackOverflow, contexts forced to heap at: %s" % e.s_new_context.short_str()
s_new_context = e.s_new_context
except Return, nlr:
@@ -81,8 +80,8 @@
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..."
- if self.trace:
+ assert not self.space.suppress_process_switch.is_set(), "ProcessSwitch should be disabled..."
+ if self.is_tracing():
print "====== Switched process from: %s" % s_new_context.short_str()
print "====== to: %s " % p.s_new_context.short_str()
s_new_context = p.s_new_context
@@ -118,16 +117,19 @@
s_context._activate_unwind_context(self)
raise nlr
-
# This is a wrapper around loop_bytecodes that cleanly enters/leaves the frame
# and handles the stack overflow protection mechanism.
def stack_frame(self, s_frame, s_sender, may_context_switch=True):
try:
+ if self.is_tracing():
+ self.stack_depth += 1
if s_frame._s_sender is None and s_sender is not None:
s_frame.store_s_sender(s_sender, raise_error=False)
# Now (continue to) execute the context bytecodes
self.loop_bytecodes(s_frame, may_context_switch)
except rstackovf.StackOverflow:
+ if self.is_tracing():
+ self.stack_depth -= 1
rstackovf.check_stack_overflow()
raise StackOverflow(s_frame)
@@ -184,7 +186,7 @@
wrapper.SemaphoreWrapper(self.space, semaphore).signal(s_frame)
# We have no finalization process, so far.
# We do not support external semaphores.
- # In cog, the method to add such a semaphore is only called in GC.
+ # In cog, the method to add such a semaphore is only called in GC.
def time_now(self):
import time
@@ -222,8 +224,12 @@
s_frame.push_all(list(w_arguments))
return s_frame
+ def is_tracing(self):
+ return self.trace.is_set()
+
def padding(self, symbol=' '):
- return symbol
+ assert self.is_tracing()
+ return self.stack_depth * symbol
class ReturnFromTopLevel(Exception):
_attrs_ = ["object"]
@@ -245,9 +251,9 @@
self.s_new_context = s_new_context
class StackOverflow(ContextSwitchException):
- """This causes the current jit-loop to be left.
- This is an experimental mechanism to avoid stack-overflow errors
- on OS level, and we suspect it breaks jit performance at least sometimes."""
+ """This causes the current jit-loop to be left, thus avoiding stack overflows.
+ This breaks performance, so it should rarely happen.
+ In case of severe performance problems, execute with -t and check if this occurrs."""
class ProcessSwitch(ContextSwitchException):
"""This causes the interpreter to switch the executed context."""
@@ -569,7 +575,7 @@
self.pop() # receiver
# ######################################################################
- if interp.trace:
+ if interp.is_tracing():
print interp.padding() + s_frame.short_str()
return interp.stack_frame(s_frame, self)
@@ -586,7 +592,7 @@
s_frame = w_method.create_frame(interp.space, receiver, w_args)
# ######################################################################
- if interp.trace:
+ if interp.is_tracing():
print '%s %s %s: #%s' % (interp.padding('#'), special_selector, s_frame.short_str(), w_args)
if not objectmodel.we_are_translated():
import pdb; pdb.set_trace()
@@ -617,7 +623,7 @@
def _call_primitive(self, code, interp, argcount, w_method, w_selector):
# ##################################################################
- if interp.trace:
+ if interp.is_tracing():
print "%s-> primitive %d \t(in %s, named #%s)" % (
interp.padding(), code, self.w_method().get_identifier_string(), w_selector.str_content())
func = primitives.prim_holder.prim_table[code]
@@ -626,7 +632,7 @@
# the primitive pushes the result (if any) onto the stack itself
return func(interp, self, argcount, w_method)
except primitives.PrimitiveFailedError, e:
- if interp.trace:
+ if interp.is_tracing():
print "%s primitive %d FAILED\t (in %s, named %s)" % (
interp.padding(), code, w_method.safe_identifier_string(), w_selector.str_content())
raise e
@@ -636,7 +642,7 @@
# assert self._stack_ptr == self.tempsize()
# ##################################################################
- if interp.trace:
+ if interp.is_tracing():
print '%s<- %s' % (interp.padding(), return_value.as_repr_string())
if self.home_is_self() or local_return:
@@ -644,16 +650,16 @@
# 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)
+ return_from_top = self.s_sender() is None
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)
+ return_from_top = s_return_to is None
+
+ if return_from_top:
+ # This should never happen while executing a normal image.
+ raise ReturnFromTopLevel(return_value)
+ else:
+ raise Return(s_return_to, return_value)
# ====== Send/Return bytecodes ======
diff --git a/spyvm/interpreter_proxy.py b/spyvm/interpreter_proxy.py
--- a/spyvm/interpreter_proxy.py
+++ b/spyvm/interpreter_proxy.py
@@ -17,7 +17,7 @@
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.rlib.unroll import unrolling_iterable
-from spyvm import error, model
+from spyvm import error, model, objspace
sqInt = rffi.INT
sqLong = rffi.LONG
@@ -50,7 +50,7 @@
def wrapped(*c_arguments):
assert len_unwrap_spec == len(c_arguments)
args = ()
- if IProxy.trace_proxy:
+ if IProxy.trace_proxy.is_set():
print 'Called InterpreterProxy >> %s' % func.func_name,
assert IProxy.s_frame is not None and IProxy.space is not None and IProxy.interp is not None
try:
@@ -63,7 +63,7 @@
else:
args += (c_arg, )
result = func(*args)
- if IProxy.trace_proxy:
+ if IProxy.trace_proxy.is_set():
print '\t-> %s' % result
if result_type is oop:
assert isinstance(result, model.W_Object)
@@ -80,7 +80,7 @@
else:
return result
except error.PrimitiveFailedError:
- if IProxy.trace_proxy:
+ if IProxy.trace_proxy.is_set():
print '\t-> failed'
IProxy.failed()
from rpython.rlib.objectmodel import we_are_translated
@@ -999,6 +999,7 @@
self.object_map = {}
self.loaded_modules = {}
self.remappable_objects = []
+ self.trace_proxy = objspace.ConstantFlag()
self.reset()
def reset(self):
@@ -1007,7 +1008,7 @@
self.argcount = 0
self.w_method = None
self.fail_reason = 0
- self.trace_proxy = False
+ self.trace_proxy.unset()
def call(self, signature, interp, s_frame, argcount, w_method):
self.initialize_from_call(signature, interp, s_frame, argcount, w_method)
@@ -1049,7 +1050,7 @@
self.argcount = argcount
self.w_method = w_method
self.space = interp.space
- self.trace_proxy = interp.trace_proxy
+ self.trace_proxy.set_to(interp.trace_proxy.is_set())
# ensure that space.w_nil gets the first possible oop
self.object_to_oop(self.space.w_nil)
diff --git a/spyvm/objspace.py b/spyvm/objspace.py
--- a/spyvm/objspace.py
+++ b/spyvm/objspace.py
@@ -6,11 +6,33 @@
from rpython.rlib.objectmodel import instantiate, specialize
from rpython.rlib.rarithmetic import intmask, r_uint, int_between
+class ConstantFlag(object):
+ """Boolean flag that can be edited, but will be promoted
+ to a constant when jitting."""
+
+ def __init__(self, set_initially=False):
+ self.flag = [set_initially]
+
+ def is_set(self):
+ flag = jit.promote(self.flag[0])
+ return flag
+
+ def set(self):
+ self.flag[0] = True
+
+ def unset(self):
+ self.flag[0] = False
+
+ def set_to(self, flag):
+ self.flag[0] = flag
+
class ObjSpace(object):
def __init__(self):
- # If this is True, then no optimizing storage strategies will be used.
+ # If this flag is set, then no optimizing storage strategies will be used.
# Intended for performance comparisons. Breaks tests.
- self.no_specialized_storage = [False]
+ self.no_specialized_storage = ConstantFlag()
+ # This is a hack; see compile_code() in targetimageloadingsmalltalk.py
+ self.suppress_process_switch = ConstantFlag()
self.classtable = {}
self.objtable = {}
@@ -25,9 +47,6 @@
self.make_bootstrap_classes()
self.make_bootstrap_objects()
-
- # This is a hack; see compile_code() in targetimageloadingsmalltalk.py
- self.suppress_process_switch = [False]
def find_executable(self, executable):
if os.sep in executable or (os.name == "nt" and ":" in executable):
diff --git a/spyvm/plugins/vmdebugging.py b/spyvm/plugins/vmdebugging.py
--- a/spyvm/plugins/vmdebugging.py
+++ b/spyvm/plugins/vmdebugging.py
@@ -10,22 +10,22 @@
@DebuggingPlugin.expose_primitive(unwrap_spec=[object])
def trace(interp, s_frame, w_rcvr):
- interp.trace = True
+ interp.trace.set()
return w_rcvr
@DebuggingPlugin.expose_primitive(unwrap_spec=[object])
def untrace(interp, s_frame, w_rcvr):
- interp.trace = False
+ interp.trace.unset()
return w_rcvr
@DebuggingPlugin.expose_primitive(unwrap_spec=[object])
def trace_proxy(interp, s_frame, w_rcvr):
- interp.trace_proxy = True
+ interp.trace_proxy.set()
return w_rcvr
@DebuggingPlugin.expose_primitive(unwrap_spec=[object])
def untrace_proxy(interp, s_frame, w_rcvr):
- interp.trace_proxy = False
+ interp.trace_proxy.unset()
return w_rcvr
@DebuggingPlugin.expose_primitive(unwrap_spec=[object])
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -186,7 +186,7 @@
def empty_storage(space, w_self, size, weak=False):
if weak:
return WeakListStorageShadow(space, w_self, size)
- if space.no_specialized_storage[0]:
+ if space.no_specialized_storage.is_set():
return ListStorageShadow(space, w_self, size)
return AllNilStorageShadow(space, w_self, size)
@@ -194,7 +194,7 @@
def find_storage_for_objects(space, vars, weak=False):
if weak:
return WeakListStorageShadow
- if space.no_specialized_storage[0]:
+ if space.no_specialized_storage.is_set():
return ListStorageShadow
specialized_strategies = 3
all_nil_can_handle = True
diff --git a/spyvm/test/test_largeinteger.py b/spyvm/test/test_largeinteger.py
--- a/spyvm/test/test_largeinteger.py
+++ b/spyvm/test/test_largeinteger.py
@@ -8,7 +8,7 @@
space, interp, _, _ = read_image('bootstrapped.image')
w = space.w
copy_to_module(locals(), __name__)
- interp.trace = False
+ interp.trace.unset()
space.initialize_class(space.w_String, interp)
def teardown_module():
@@ -37,8 +37,8 @@
w_selector = space.get_special_selector(selector)
except Exception:
w_selector = find_symbol_in_methoddict_of(selector, w(intmask(candidates[0])).getclass(space).shadow)
-
- interp.trace=trace
+
+ interp.trace.set_to(trace)
for i, v in enumerate(candidates):
x = w_l(v)
if j is None:
@@ -50,7 +50,7 @@
y = w_l(j)
z = perform_primitive(x, w_selector, y)
assert r_uint(z.value) == r_uint(operation(v, y.value))
- interp.trace=False
+ interp.trace.unset()
def test_bitAnd():
do_primitive("bitAnd:", operator.and_)
diff --git a/spyvm/wrapper.py b/spyvm/wrapper.py
--- a/spyvm/wrapper.py
+++ b/spyvm/wrapper.py
@@ -93,7 +93,7 @@
active_priority = active_process.priority()
priority = self.priority()
if priority > active_priority:
- if not self.space.suppress_process_switch[0]:
+ if not self.space.suppress_process_switch.is_set():
active_process.deactivate(s_current_frame)
self.activate()
else:
@@ -104,7 +104,7 @@
def suspend(self, s_current_frame):
if self.is_active_process():
- if not self.space.suppress_process_switch[0]:
+ if not self.space.suppress_process_switch.is_set():
assert self.my_list().is_nil(self.space)
w_process = scheduler(self.space).pop_highest_priority_process()
self.deactivate(s_current_frame, put_to_sleep=False)
diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py
--- a/targetimageloadingsmalltalk.py
+++ b/targetimageloadingsmalltalk.py
@@ -109,7 +109,7 @@
elif arg in ["-P", "--process"]:
headless = False
elif arg in ["-S"]:
- space.no_specialized_storage[0] = True
+ space.no_specialized_storage.set()
elif arg in ["-u"]:
from spyvm.plugins.vmdebugging import stop_ui_process
stop_ui_process()
@@ -156,9 +156,9 @@
# Create context to be executed
if code or selector:
if not have_number:
- w_receiver = interp.space.w_nil
+ w_receiver = space.w_nil
else:
- w_receiver = interp.space.wrap_int(number)
+ w_receiver = space.wrap_int(number)
if code:
selector = compile_code(interp, w_receiver, code)
if selector is None:
@@ -168,9 +168,9 @@
context = s_frame
else:
create_process(interp, s_frame)
- context = active_context(interp.space)
+ context = active_context(space)
else:
- context = active_context(interp.space)
+ context = active_context(space)
w_result = execute_context(interp, context)
print result_string(w_result)
@@ -184,7 +184,6 @@
return w_result.as_repr_string().replace('\r', '\n')
def compile_code(interp, w_receiver, code):
- import time
selector = "DoIt%d" % int(time.time())
space = interp.space
w_receiver_class = w_receiver.getclass(space)
@@ -194,7 +193,7 @@
# registered (primitive 136 not called), so the idle process will never be left once it is entered.
# TODO - Find a way to cleanly initialize the image, without executing the active_context of the image.
# Instead, we want to execute our own context. Then remove this flag (and all references to it)
- interp.space.suppress_process_switch[0] = True
+ space.suppress_process_switch.set()
try:
w_result = interp.perform(
w_receiver_class,
@@ -212,7 +211,7 @@
print_error("Exited while compiling code: %s" % e.msg)
return None
finally:
- interp.space.suppress_process_switch[0] = False
+ space.suppress_process_switch.unset()
w_receiver_class.as_class_get_shadow(space).s_methoddict().sync_method_cache()
return selector
More information about the pypy-commit
mailing list