[pypy-commit] lang-smalltalk interpreter-flags: Added interrupts-flag to interpreter and entry-point to disable user interrupts.

anton_gulenko noreply at buildbot.pypy.org
Mon Jul 28 10:11:27 CEST 2014


Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: interpreter-flags
Changeset: r990:187ad8278435
Date: 2014-05-13 12:00 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/187ad8278435/

Log:	Added interrupts-flag to interpreter and entry-point to disable user
	interrupts. Added flag to entry-point to configure (or disable) the
	max stack depth before StackOverflow protection kicks in. Fixed
	indentation.

diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -25,7 +25,7 @@
 class Interpreter(object):
     _immutable_fields_ = ["space", "image", "image_name",
                           "max_stack_depth", "interrupt_counter_size",
-                          "startup_time", "evented"]
+                          "startup_time", "evented", "interrupts"]
     
     jit_driver = jit.JitDriver(
         greens=['pc', 'self', 'method'],
@@ -34,9 +34,9 @@
         get_printable_location=get_printable_location
     )
 
-    def __init__(self, space, image=None, image_name="", trace=False,
-                 evented=True,
-                 max_stack_depth=constants.MAX_LOOP_DEPTH):
+    def __init__(self, space, image=None, image_name="",
+                trace=False, evented=True, interrupts=True,
+                max_stack_depth=constants.MAX_LOOP_DEPTH):
         import time
         
         # === Initialize immutable variables
@@ -49,6 +49,7 @@
             self.startup_time = constants.CompileTime
         self.max_stack_depth = max_stack_depth
         self.evented = evented
+        self.interrupts = interrupts
         try:
             self.interrupt_counter_size = int(os.environ["SPY_ICS"])
         except KeyError:
@@ -56,7 +57,7 @@
         
         # === Initialize mutable variables
         self.interrupt_check_counter = self.interrupt_counter_size
-        self.remaining_stack_depth = max_stack_depth
+        self.current_stack_depth = 0
         self.next_wakeup_tick = 0
         self.trace = trace
         self.trace_proxy = False
@@ -65,7 +66,7 @@
         # just a trampoline for the actual loop implemented in loop_bytecodes
         s_new_context = w_active_context.as_context_get_shadow(self.space)
         while True:
-            assert self.remaining_stack_depth == self.max_stack_depth
+            assert self.current_stack_depth == 0
             # Need to save s_sender, loop_bytecodes will nil this on return
             s_sender = s_new_context.s_sender()
             try:
@@ -85,7 +86,7 @@
             except ProcessSwitch, p:
                 if self.trace:
                     print "====== Switched process from: %s" % s_new_context.short_str()
-					print "====== to: %s " % p.s_new_context.short_str()
+                    print "====== to: %s " % p.s_new_context.short_str()
                 s_new_context = p.s_new_context
 
     def loop_bytecodes(self, s_context, may_context_switch=True):
@@ -116,33 +117,36 @@
                 else:
                     s_context.push(nlr.value)
     
-    # This is just a wrapper around loop_bytecodes that handles the remaining_stack_depth mechanism
+    # This is just a wrapper around loop_bytecodes that handles the stack overflow protection mechanism
     def stack_frame(self, s_new_frame, may_context_switch=True):
-        if self.remaining_stack_depth <= 1:
-            raise StackOverflow(s_new_frame)
-
-        self.remaining_stack_depth -= 1
+        if self.max_stack_depth > 0:
+            if self.current_stack_depth >= self.max_stack_depth:
+                raise StackOverflow(s_new_frame)
+        
+        self.current_stack_depth += 1
         try:
             self.loop_bytecodes(s_new_frame, may_context_switch)
         finally:
-            self.remaining_stack_depth += 1
-	
-	def step(self, context):
-		bytecode = context.fetch_next_bytecode()
-		for entry in UNROLLING_BYTECODE_RANGES:
-			if len(entry) == 2:
-				bc, methname = entry
-				if bytecode == bc:
-					return getattr(context, methname)(self, bytecode)
-			else:
-				start, stop, methname = entry
-				if start <= bytecode <= stop:
-					return getattr(context, methname)(self, bytecode)
-		assert 0, "unreachable"
-	
+            self.current_stack_depth -= 1
+    
+    def step(self, context):
+        bytecode = context.fetch_next_bytecode()
+        for entry in UNROLLING_BYTECODE_RANGES:
+            if len(entry) == 2:
+                bc, methname = entry
+                if bytecode == bc:
+                    return getattr(context, methname)(self, bytecode)
+            else:
+                start, stop, methname = entry
+                if start <= bytecode <= stop:
+                    return getattr(context, methname)(self, bytecode)
+        assert 0, "unreachable"
+    
     # ============== Methods for handling user interrupts ==============
     
     def jitted_check_for_interrupt(self, s_frame):
+        if not self.interrupts:
+            return
         # Normally, the tick counter is decremented by 1 for every message send.
         # Since we don't know how many messages are called during this trace, we
         # just decrement by 100th of the trace length (num of bytecodes).
@@ -152,6 +156,8 @@
         self.quick_check_for_interrupt(s_frame, decr_by)
     
     def quick_check_for_interrupt(self, s_frame, dec=1):
+        if not self.interrupts:
+            return
         self.interrupt_check_counter -= dec
         if self.interrupt_check_counter <= 0:
             self.interrupt_check_counter = self.interrupt_counter_size
@@ -214,7 +220,7 @@
         return self.interpret_toplevel(s_frame.w_self())
     
     def padding(self, symbol=' '):
-        return symbol * (self.max_stack_depth - self.remaining_stack_depth)
+        return symbol * self.current_stack_depth
 
 class ReturnFromTopLevel(Exception):
     _attrs_ = ["object"]
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
@@ -1017,7 +1017,7 @@
 
 class StackTestInterpreter(TestInterpreter):
     def stack_frame(self, w_frame, may_interrupt=True):
-        stack_depth = self.max_stack_depth - self.remaining_stack_depth
+        stack_depth = self.current_stack_depth
         for i in range(stack_depth + 1):
             assert sys._getframe(4 + i * 6).f_code.co_name == 'loop_bytecodes'
         assert sys._getframe(5 + stack_depth * 6).f_code.co_name == 'loop'
diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py
--- a/targetimageloadingsmalltalk.py
+++ b/targetimageloadingsmalltalk.py
@@ -6,7 +6,7 @@
 from rpython.rlib import jit, rpath
 
 from spyvm import model, interpreter, squeakimage, objspace, wrapper,\
-    error, shadow, storage_statistics
+    error, shadow, storage_statistics, constants
 from spyvm.tool.analyseimage import create_image
 from spyvm.interpreter_proxy import VirtualMachine
 
@@ -128,13 +128,14 @@
           -r|--run [code string]
           -b|--benchmark [code string]
           -p|--poll_events
+          -ni|--no-interrupts
+          -d|--max-stack-depth [number, default %d, <= 0 disables stack protection]
           --strategy-log
           --strategy-stats
-		  --strategy-stats-dot
+          --strategy-stats-dot
           --strategy-stats-details
           [image path, default: Squeak.image]
-    """ % argv[0]
-
+    """ % (argv[0], constants.MAX_LOOP_DEPTH)
 
 def _arg_missing(argv, idx, arg):
     if len(argv) == idx + 1:
@@ -152,6 +153,8 @@
     stringarg = ""
     code = None
     as_benchmark = False
+    max_stack_depth = constants.MAX_LOOP_DEPTH
+    interrupts = True
     
     while idx < len(argv):
         arg = argv[idx]
@@ -189,6 +192,12 @@
             code = argv[idx + 1]
             as_benchmark = True
             idx += 1
+        elif arg in ["-ni", "--no-interrupts"]:
+            interrupts = False
+        elif arg in ["-d", "--max-stack-depth"]:
+            _arg_missing(argv, idx, arg)
+            max_stack_depth = int(argv[idx + 1])
+            idx += 1
         elif arg == "--strategy-log":
             storage_statistics.activate_statistics(log=True)
         elif arg == "--strategy-stats":
@@ -221,7 +230,9 @@
     space = prebuilt_space
     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=evented)
+    interp = interpreter.Interpreter(space, image, image_name=path,
+                trace=trace, evented=evented,
+                interrupts=interrupts, max_stack_depth=max_stack_depth)
     space.runtime_setup(argv[0])
     result = 0
     if benchmark is not None:


More information about the pypy-commit mailing list