[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