[pypy-commit] lang-smalltalk storage: Merged branch storage-refactoring-virtual-pc.

anton_gulenko noreply at buildbot.pypy.org
Wed May 14 14:51:12 CEST 2014


Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage
Changeset: r826:b79f58f23cbc
Date: 2014-05-14 14:33 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/b79f58f23cbc/

Log:	Merged branch storage-refactoring-virtual-pc.

diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -62,7 +62,7 @@
         self.trace_proxy = False
 
     def loop(self, w_active_context):
-        # just a trampoline for the actual loop implemented in loop_bytecodes
+        # 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.remaining_stack_depth == self.max_stack_depth
@@ -72,14 +72,12 @@
                 self.loop_bytecodes(s_new_context)
                 raise Exception("loop_bytecodes left without raising...")
             except StackOverflow, e:
-                s_new_context = e.s_context
+                s_new_context = e.s_new_context
             except Return, nlr:
                 s_new_context = s_sender
                 while s_new_context is not nlr.s_target_context:
                     s_sender = s_new_context.s_sender()
-                    if not s_new_context.is_closure_context() and s_new_context.w_method().primitive() == 198:
-                        s_new_context.activate_unwind_context(self)
-                    s_new_context.mark_returned()
+                    s_new_context._activate_unwind_context(self)
                     s_new_context = s_sender
                 s_new_context.push(nlr.value)
             except ProcessSwitch, p:
@@ -109,9 +107,7 @@
                 self.step(s_context)
             except Return, nlr:
                 if nlr.s_target_context is not s_context:
-                    if not s_context.is_closure_context() and method.primitive() == 198:
-                        s_context.activate_unwind_context(self)
-                    s_context.mark_returned()
+                    s_context._activate_unwind_context(self)
                     raise nlr
                 else:
                     s_context.push(nlr.value)
@@ -221,24 +217,50 @@
     def __init__(self, object):
         self.object = object
 
-class StackOverflow(Exception):
-    _attrs_ = ["s_context"]
-    def __init__(self, s_top_context):
-        self.s_context = s_top_context
-
 class Return(Exception):
     _attrs_ = ["value", "s_target_context"]
-    def __init__(self, object, s_context):
-        self.value = object
-        self.s_target_context = s_context
+    def __init__(self, s_target_context, w_result):
+        self.value = w_result
+        self.s_target_context = s_target_context
 
-class ProcessSwitch(Exception):
+class ContextSwitchException(Exception):
+    """General Exception that causes the interpreter to leave
+    the current context. The current pc is required in order to update
+    the context object that we are leaving."""
     _attrs_ = ["s_new_context"]
-    def __init__(self, s_context):
-        self.s_new_context = s_context
+    def __init__(self, s_new_context):
+        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."""
 
-def make_call_primitive_bytecode(primitive, selector, argcount):
+class ProcessSwitch(ContextSwitchException):
+    """This causes the interpreter to switch the executed context."""
+
+# This is a decorator for bytecode implementation methods.
+# parameter_bytes=N means N additional bytes are fetched as parameters.
+def bytecode_implementation(parameter_bytes=0):
+    def bytecode_implementation_decorator(actual_implementation_method):
+        from rpython.rlib.unroll import unrolling_zero
+        @jit.unroll_safe
+        def bytecode_implementation_wrapper(self, interp, current_bytecode):
+            parameters = ()
+            i = unrolling_zero
+            while i < parameter_bytes:
+                parameters += (self.fetch_next_bytecode(), )
+                i = i + 1
+            # This is a good place to step through bytecodes.
+            # import pdb; pdb.set_trace()
+            return actual_implementation_method(self, interp, current_bytecode, *parameters)
+        bytecode_implementation_wrapper.func_name = actual_implementation_method.func_name
+        return bytecode_implementation_wrapper
+    return bytecode_implementation_decorator
+
+def make_call_primitive_bytecode(primitive, selector, argcount, store_pc=False):
+    func = primitives.prim_table[primitive]
+    @bytecode_implementation()
     def callPrimitive(self, interp, current_bytecode):
         # WARNING: this is used for bytecodes for which it is safe to
         # directly call the primitive.  In general, it is not safe: for
@@ -247,17 +269,17 @@
         # else that the user put in a class in an 'at:' method.
         # The rule of thumb is that primitives with only int and float
         # in their unwrap_spec are safe.
-        # XXX move next line out of callPrimitive?
-        func = primitives.prim_table[primitive]
         try:
             return func(interp, self, argcount)
         except primitives.PrimitiveFailedError:
             pass
         return self._sendSelfSelectorSpecial(selector, argcount, interp)
+    callPrimitive.func_name = "callPrimitive_%s" % func.func_name
     return callPrimitive
 
 def make_call_primitive_bytecode_classbased(a_class_name, a_primitive, alternative_class_name, alternative_primitive, selector, argcount):
-    def callPrimitive(self, interp, current_bytecode):
+    @bytecode_implementation()
+    def callClassbasedPrimitive(self, interp, current_bytecode):
         rcvr = self.peek(argcount)
         receiver_class = rcvr.getclass(self.space)
         try:
@@ -270,7 +292,25 @@
         except primitives.PrimitiveFailedError:
             pass
         return self._sendSelfSelectorSpecial(selector, argcount, interp)
-    return callPrimitive
+    callClassbasedPrimitive.func_name = "callClassbasedPrimitive_%s" % selector
+    return callClassbasedPrimitive
+
+# Some selectors cannot be overwritten, therefore no need to handle PrimitiveFailed.
+def make_quick_call_primitive_bytecode(primitive_index, argcount):
+    func = primitives.prim_table[primitive_index]
+    @bytecode_implementation()
+    def quick_call_primitive_bytecode(self, interp, current_bytecode):
+        return func(interp, self, argcount)
+    return quick_call_primitive_bytecode
+
+# This is for bytecodes that actually implement a simple message-send.
+# We do not optimize anything for these cases.
+def make_send_selector_bytecode(selector, argcount):
+    @bytecode_implementation()
+    def selector_bytecode(self, interp, current_bytecode):
+        return self._sendSelfSelectorSpecial(selector, argcount, interp)
+    selector_bytecode.func_name = "selector_bytecode_%s" % selector
+    return selector_bytecode
 
 # ___________________________________________________________________________
 # Bytecode Implementations:
@@ -279,19 +319,25 @@
 
 # __extend__ adds new methods to the ContextPartShadow class
 class __extend__(ContextPartShadow):
-    # push bytecodes
+    
+    # ====== Push/Pop bytecodes ======
+    
+    @bytecode_implementation()
     def pushReceiverVariableBytecode(self, interp, current_bytecode):
         index = current_bytecode & 15
         self.push(self.w_receiver().fetch(self.space, index))
 
+    @bytecode_implementation()
     def pushTemporaryVariableBytecode(self, interp, current_bytecode):
         index = current_bytecode & 15
         self.push(self.gettemp(index))
 
+    @bytecode_implementation()
     def pushLiteralConstantBytecode(self, interp, current_bytecode):
         index = current_bytecode & 31
         self.push(self.w_method().getliteral(index))
 
+    @bytecode_implementation()
     def pushLiteralVariableBytecode(self, interp, current_bytecode):
         # this bytecode assumes that literals[index] is an Association
         # which is an object with two named vars, and fetches the second
@@ -301,50 +347,165 @@
         association = wrapper.AssociationWrapper(self.space, w_association)
         self.push(association.value())
 
+    @bytecode_implementation()
     def storeAndPopReceiverVariableBytecode(self, interp, current_bytecode):
         index = current_bytecode & 7
         self.w_receiver().store(self.space, index, self.pop())
 
+    @bytecode_implementation()
     def storeAndPopTemporaryVariableBytecode(self, interp, current_bytecode):
         index = current_bytecode & 7
         self.settemp(index, self.pop())
 
-    # push bytecodes
+    @bytecode_implementation()
     def pushReceiverBytecode(self, interp, current_bytecode):
         self.push(self.w_receiver())
 
+    @bytecode_implementation()
     def pushConstantTrueBytecode(self, interp, current_bytecode):
         self.push(interp.space.w_true)
 
+    @bytecode_implementation()
     def pushConstantFalseBytecode(self, interp, current_bytecode):
         self.push(interp.space.w_false)
 
+    @bytecode_implementation()
     def pushConstantNilBytecode(self, interp, current_bytecode):
         self.push(interp.space.w_nil)
 
+    @bytecode_implementation()
     def pushConstantMinusOneBytecode(self, interp, current_bytecode):
         self.push(interp.space.w_minus_one)
 
+    @bytecode_implementation()
     def pushConstantZeroBytecode(self, interp, current_bytecode):
         self.push(interp.space.w_zero)
 
+    @bytecode_implementation()
     def pushConstantOneBytecode(self, interp, current_bytecode):
         self.push(interp.space.w_one)
 
+    @bytecode_implementation()
     def pushConstantTwoBytecode(self, interp, current_bytecode):
         self.push(interp.space.w_two)
 
+    @bytecode_implementation()
     def pushActiveContextBytecode(self, interp, current_bytecode):
         self.push(self.w_self())
 
+    @bytecode_implementation()
     def duplicateTopBytecode(self, interp, current_bytecode):
         self.push(self.top())
 
-    # send, return bytecodes
-    def sendLiteralSelectorBytecode(self, interp, current_bytecode):
-        w_selector = self.w_method().getliteral(current_bytecode & 15)
-        argcount = ((current_bytecode >> 4) & 3) - 1
-        return self._sendSelfSelector(w_selector, argcount, interp)
+    @bytecode_implementation()
+    def popStackBytecode(self, interp, current_bytecode):
+        self.pop()
+    
+    @bytecode_implementation(parameter_bytes=1)
+    def pushNewArrayBytecode(self, interp, current_bytecode, descriptor):
+        arraySize, popIntoArray = splitter[7, 1](descriptor)
+        newArray = None
+        if popIntoArray == 1:
+           newArray = interp.space.wrap_list(self.pop_and_return_n(arraySize))
+        else:
+           newArray = interp.space.w_Array.as_class_get_shadow(interp.space).new(arraySize)
+        self.push(newArray)
+        
+    # ====== Extended Push/Pop bytecodes ======
+    
+    def _extendedVariableTypeAndIndex(self, descriptor):
+        return ((descriptor >> 6) & 3), (descriptor & 63)
+
+    @bytecode_implementation(parameter_bytes=1)
+    def extendedPushBytecode(self, interp, current_bytecode, descriptor):
+        variableType, variableIndex = self._extendedVariableTypeAndIndex(descriptor)
+        if variableType == 0:
+            self.push(self.w_receiver().fetch(self.space, variableIndex))
+        elif variableType == 1:
+            self.push(self.gettemp(variableIndex))
+        elif variableType == 2:
+            self.push(self.w_method().getliteral(variableIndex))
+        elif variableType == 3:
+            w_association = self.w_method().getliteral(variableIndex)
+            association = wrapper.AssociationWrapper(self.space, w_association)
+            self.push(association.value())
+        else:
+            assert 0
+
+    def _extendedStoreBytecode(self, interp, current_bytecode, descriptor):
+        variableType, variableIndex = self._extendedVariableTypeAndIndex(descriptor)
+        if variableType == 0:
+            self.w_receiver().store(self.space, variableIndex, self.top())
+        elif variableType == 1:
+            self.settemp(variableIndex, self.top())
+        elif variableType == 2:
+            raise IllegalStoreError
+        elif variableType == 3:
+            w_association = self.w_method().getliteral(variableIndex)
+            association = wrapper.AssociationWrapper(self.space, w_association)
+            association.store_value(self.top())
+
+    @bytecode_implementation(parameter_bytes=1)
+    def extendedStoreBytecode(self, interp, current_bytecode, descriptor):
+        return self._extendedStoreBytecode(interp, current_bytecode, descriptor)
+            
+    @bytecode_implementation(parameter_bytes=1)
+    def extendedStoreAndPopBytecode(self, interp, current_bytecode, descriptor):
+        self._extendedStoreBytecode(interp, current_bytecode, descriptor)
+        self.pop()
+    
+    def _extract_index_and_temps(self, index_in_array, index_of_array):
+        w_indirectTemps = self.gettemp(index_of_array)
+        return index_in_array, w_indirectTemps
+    
+    @bytecode_implementation(parameter_bytes=2)
+    def pushRemoteTempLongBytecode(self, interp, current_bytecode, index_in_array, index_of_array):
+        index_in_array, w_indirectTemps = self._extract_index_and_temps(index_in_array, index_of_array)
+        self.push(w_indirectTemps.at0(self.space, index_in_array))
+
+    @bytecode_implementation(parameter_bytes=2)
+    def storeRemoteTempLongBytecode(self, interp, current_bytecode, index_in_array, index_of_array):
+        index_in_array, w_indirectTemps = self._extract_index_and_temps(index_in_array, index_of_array)
+        w_indirectTemps.atput0(self.space, index_in_array, self.top())
+
+    @bytecode_implementation(parameter_bytes=2)
+    def storeAndPopRemoteTempLongBytecode(self, interp, current_bytecode, index_in_array, index_of_array):
+        index_in_array, w_indirectTemps = self._extract_index_and_temps(index_in_array, index_of_array)
+        w_indirectTemps.atput0(self.space, index_in_array, self.pop())
+
+    @bytecode_implementation(parameter_bytes=3)
+    def pushClosureCopyCopiedValuesBytecode(self, interp, current_bytecode, descriptor, j, i):
+        """ Copied from Blogpost: http://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/
+        ContextPart>>pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
+        "Simulate the action of a 'closure copy' bytecode whose result is the
+         new BlockClosure for the following code"
+        | copiedValues |
+        numCopied > 0
+                 ifTrue:
+                          [copiedValues := Array new: numCopied.
+                           numCopied to: 1 by: -1 do:
+                                   [:i|
+                                   copiedValues at: i put: self pop]]
+                 ifFalse:
+                          [copiedValues := nil].
+        self push: (BlockClosure new
+                                   outerContext: self
+                                   startpc: pc
+                                   numArgs: numArgs
+                                   copiedValues: copiedValues).
+        self jump: blockSize
+        """
+        
+        space = self.space
+        numArgs, numCopied = splitter[4, 4](descriptor)
+        blockSize = (j << 8) | i
+        # Create new instance of BlockClosure
+        w_closure = space.newClosure(self.w_self(), self.pc(), numArgs,
+                                            self.pop_and_return_n(numCopied))
+        self.push(w_closure)
+        self._jump(blockSize)
+        
+    # ====== Helpers for send/return bytecodes ======
 
     def _sendSelfSelector(self, w_selector, argcount, interp):
         receiver = self.peek(argcount)
@@ -382,6 +543,11 @@
 
         return interp.stack_frame(s_frame)
 
+    @objectmodel.specialize.arg(1)
+    def _sendSelfSelectorSpecial(self, selector, numargs, interp):
+        w_selector = self.space.get_special_selector(selector)
+        return self._sendSelfSelector(w_selector, numargs, interp)
+    
     def _sendSpecialSelector(self, interp, receiver, special_selector, w_args=[]):
         w_special_selector = self.space.objtable["w_" + special_selector]
         s_class = receiver.class_shadow(self.space)
@@ -435,101 +601,62 @@
             raise e
 
     def _return(self, return_value, interp, s_return_to):
-        # for tests, when returning from the top-level context
-        if s_return_to is None:
-            raise ReturnFromTopLevel(return_value)
-        # unfortunately, the assert below is not true for some tests
+        # unfortunately, this assert is not true for some tests. TODO fix this.
         # assert self._stack_ptr == self.tempsize()
-
+        
+        # ##################################################################
         if interp.trace:
             print '%s<- %s' % (interp.padding(), return_value.as_repr_string())
-        raise Return(return_value, s_return_to)
+        
+        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)
 
-    def activate_unwind_context(self, interp):
-        # the first temp is executed flag for both #ensure: and #ifCurtailed:
-        if self.gettemp(1).is_nil(self.space):
-            self.settemp(1, self.space.w_true) # mark unwound
-            self.push(self.gettemp(0)) # push the first argument
-            try:
-                self.bytecodePrimValue(interp, 0)
-            except Return, nlr:
-                if self is nlr.s_target_context:
-                    return
-                else:
-                    self.mark_returned()
-                    raise nlr
+    # ====== Send/Return bytecodes ======
 
+    @bytecode_implementation()
     def returnReceiverBytecode(self, interp, current_bytecode):
         return self._return(self.w_receiver(), interp, self.s_home().s_sender())
 
+    @bytecode_implementation()
     def returnTrueBytecode(self, interp, current_bytecode):
         return self._return(interp.space.w_true, interp, self.s_home().s_sender())
 
+    @bytecode_implementation()
     def returnFalseBytecode(self, interp, current_bytecode):
         return self._return(interp.space.w_false, interp, self.s_home().s_sender())
 
+    @bytecode_implementation()
     def returnNilBytecode(self, interp, current_bytecode):
         return self._return(interp.space.w_nil, interp, self.s_home().s_sender())
 
+    @bytecode_implementation()
     def returnTopFromMethodBytecode(self, interp, current_bytecode):
         return self._return(self.pop(), interp, self.s_home().s_sender())
 
+    @bytecode_implementation()
     def returnTopFromBlockBytecode(self, interp, current_bytecode):
         return self._return(self.pop(), interp, self.s_sender())
 
-    def unknownBytecode(self, interp, current_bytecode):
-        raise MissingBytecode("unknownBytecode")
+    @bytecode_implementation()
+    def sendLiteralSelectorBytecode(self, interp, current_bytecode):
+        w_selector = self.w_method().getliteral(current_bytecode & 15)
+        argcount = ((current_bytecode >> 4) & 3) - 1
+        return self._sendSelfSelector(w_selector, argcount, interp)
 
-    def extendedVariableTypeAndIndex(self):
-        # AK please explain this method (a helper, I guess)
-        descriptor = self.fetch_next_bytecode()
-        return ((descriptor >> 6) & 3), (descriptor & 63)
-
-    def extendedPushBytecode(self, interp, current_bytecode):
-        variableType, variableIndex = self.extendedVariableTypeAndIndex()
-        if variableType == 0:
-            self.push(self.w_receiver().fetch(self.space, variableIndex))
-        elif variableType == 1:
-            self.push(self.gettemp(variableIndex))
-        elif variableType == 2:
-            self.push(self.w_method().getliteral(variableIndex))
-        elif variableType == 3:
-            w_association = self.w_method().getliteral(variableIndex)
-            association = wrapper.AssociationWrapper(self.space, w_association)
-            self.push(association.value())
-        else:
-            assert 0
-
-    def extendedStoreBytecode(self, interp, current_bytecode):
-        variableType, variableIndex = self.extendedVariableTypeAndIndex()
-        if variableType == 0:
-            self.w_receiver().store(self.space, variableIndex, self.top())
-        elif variableType == 1:
-            self.settemp(variableIndex, self.top())
-        elif variableType == 2:
-            raise IllegalStoreError
-        elif variableType == 3:
-            w_association = self.w_method().getliteral(variableIndex)
-            association = wrapper.AssociationWrapper(self.space, w_association)
-            association.store_value(self.top())
-
-    def extendedStoreAndPopBytecode(self, interp, current_bytecode):
-        self.extendedStoreBytecode(interp, current_bytecode)
-        self.pop()
-
-    def getExtendedSelectorArgcount(self):
-        descriptor = self.fetch_next_bytecode()
+    def _getExtendedSelectorArgcount(self, descriptor):
         return ((self.w_method().getliteral(descriptor & 31)),
                 (descriptor >> 5))
 
-    def singleExtendedSendBytecode(self, interp, current_bytecode):
-        w_selector, argcount = self.getExtendedSelectorArgcount()
+    @bytecode_implementation(parameter_bytes=1)
+    def singleExtendedSendBytecode(self, interp, current_bytecode, descriptor):
+        w_selector, argcount = self._getExtendedSelectorArgcount(descriptor)
         return self._sendSelfSelector(w_selector, argcount, interp)
 
-    def doubleExtendedDoAnythingBytecode(self, interp, current_bytecode):
+    @bytecode_implementation(parameter_bytes=2)
+    def doubleExtendedDoAnythingBytecode(self, interp, current_bytecode, second, third):
         from spyvm import error
-        second = self.fetch_next_bytecode()
-        third = self.fetch_next_bytecode()
         opType = second >> 5
         if opType == 0:
             # selfsend
@@ -565,86 +692,51 @@
             association = wrapper.AssociationWrapper(self.space, w_association)
             association.store_value(self.top())
 
-    def singleExtendedSuperBytecode(self, interp, current_bytecode):
-        w_selector, argcount = self.getExtendedSelectorArgcount()
+    @bytecode_implementation(parameter_bytes=1)
+    def singleExtendedSuperBytecode(self, interp, current_bytecode, descriptor):
+        w_selector, argcount = self._getExtendedSelectorArgcount(descriptor)
         return self._sendSuperSelector(w_selector, argcount, interp)
 
-    def secondExtendedSendBytecode(self, interp, current_bytecode):
-        descriptor = self.fetch_next_bytecode()
+    @bytecode_implementation(parameter_bytes=1)
+    def secondExtendedSendBytecode(self, interp, current_bytecode, descriptor):
         w_selector = self.w_method().getliteral(descriptor & 63)
         argcount = descriptor >> 6
         return self._sendSelfSelector(w_selector, argcount, interp)
 
-    def popStackBytecode(self, interp, current_bytecode):
-        self.pop()
-
-    # closure bytecodes
-    def pushNewArrayBytecode(self, interp, current_bytecode):
-        arraySize, popIntoArray = splitter[7, 1](self.fetch_next_bytecode())
-        newArray = None
-        if popIntoArray == 1:
-           newArray = interp.space.wrap_list(self.pop_and_return_n(arraySize))
-        else:
-           newArray = interp.space.w_Array.as_class_get_shadow(interp.space).new(arraySize)
-        self.push(newArray)
-
+    # ====== 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:
+            self.mark_returned()
+            return
+        # The first temp is executed flag for both #ensure: and #ifCurtailed:
+        if self.gettemp(1).is_nil(self.space):
+            self.settemp(1, self.space.w_true) # mark unwound
+            self.push(self.gettemp(0)) # push the first argument
+            try:
+                self.bytecodePrimValue(interp, 0)
+            except Return, nlr:
+                if self is not nlr.s_target_context:
+                    raise nlr
+            finally:
+                self.mark_returned()
+    
+    @bytecode_implementation()
+    def unknownBytecode(self, interp, current_bytecode):
+        raise MissingBytecode("unknownBytecode")
+        
+    @bytecode_implementation()
     def experimentalBytecode(self, interp, current_bytecode):
         raise MissingBytecode("experimentalBytecode")
 
-    def _extract_index_and_temps(self):
-        index_in_array = self.fetch_next_bytecode()
-        index_of_array = self.fetch_next_bytecode()
-        w_indirectTemps = self.gettemp(index_of_array)
-        return index_in_array, w_indirectTemps
+    # ====== Jump bytecodes ======
 
-    def pushRemoteTempLongBytecode(self, interp, current_bytecode):
-        index_in_array, w_indirectTemps = self._extract_index_and_temps()
-        self.push(w_indirectTemps.at0(self.space, index_in_array))
-
-    def storeRemoteTempLongBytecode(self, interp, current_bytecode):
-        index_in_array, w_indirectTemps = self._extract_index_and_temps()
-        w_indirectTemps.atput0(self.space, index_in_array, self.top())
-
-    def storeAndPopRemoteTempLongBytecode(self, interp, current_bytecode):
-        index_in_array, w_indirectTemps = self._extract_index_and_temps()
-        w_indirectTemps.atput0(self.space, index_in_array, self.pop())
-
-    def pushClosureCopyCopiedValuesBytecode(self, interp, current_bytecode):
-        """ Copied from Blogpost: http://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/
-        ContextPart>>pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
-        "Simulate the action of a 'closure copy' bytecode whose result is the
-         new BlockClosure for the following code"
-        | copiedValues |
-        numCopied > 0
-                 ifTrue:
-                          [copiedValues := Array new: numCopied.
-                           numCopied to: 1 by: -1 do:
-                                   [:i|
-                                   copiedValues at: i put: self pop]]
-                 ifFalse:
-                          [copiedValues := nil].
-        self push: (BlockClosure new
-                                   outerContext: self
-                                   startpc: pc
-                                   numArgs: numArgs
-                                   copiedValues: copiedValues).
-        self jump: blockSize
-        """
-        space = self.space
-        numArgs, numCopied = splitter[4, 4](self.fetch_next_bytecode())
-        j = self.fetch_next_bytecode()
-        i = self.fetch_next_bytecode()
-        blockSize = (j << 8) | i
-        #create new instance of BlockClosure
-        w_closure = space.newClosure(self.w_self(), self.pc(), numArgs,
-                                            self.pop_and_return_n(numCopied))
-        self.push(w_closure)
-        self.jump(blockSize)
-
-    def jump(self, offset):
+    def _jump(self, offset):
         self.store_pc(self.pc() + offset)
 
-    def jumpConditional(self, interp, expecting_true, position):
+    def _jumpConditional(self, interp, expecting_true, position):
         if expecting_true:
             w_expected = interp.space.w_true
             w_alternative = interp.space.w_false
@@ -652,34 +744,42 @@
             w_alternative = interp.space.w_true
             w_expected = interp.space.w_false
         
-        # Don't check the class, just compare with only two instances.
+        # Don't check the class, just compare with only two Boolean instances.
         w_bool = self.pop()
         if w_expected.is_same_object(w_bool):
-            self.jump(position)
+            self._jump(position)
         elif not w_alternative.is_same_object(w_bool):
             self._mustBeBoolean(interp, w_bool)
 
-    def shortJumpPosition(self, current_bytecode):
+    def _shortJumpOffset(self, current_bytecode):
         return (current_bytecode & 7) + 1
 
+    def _longJumpOffset(self, current_bytecode, parameter):
+        return ((current_bytecode & 3) << 8) + parameter
+
+    @bytecode_implementation()
     def shortUnconditionalJumpBytecode(self, interp, current_bytecode):
-        self.jump(self.shortJumpPosition(current_bytecode))
+        self._jump(self._shortJumpOffset(current_bytecode))
 
+    @bytecode_implementation()
     def shortConditionalJumpBytecode(self, interp, current_bytecode):
         # The conditional jump is "jump on false"
-        self.jumpConditional(interp, False, self.shortJumpPosition(current_bytecode))
+        self._jumpConditional(interp, False, self._shortJumpOffset(current_bytecode))
 
-    def longUnconditionalJumpBytecode(self, interp, current_bytecode):
-        self.jump((((current_bytecode & 7) - 4) << 8) + self.fetch_next_bytecode())
+    @bytecode_implementation(parameter_bytes=1)
+    def longUnconditionalJumpBytecode(self, interp, current_bytecode, parameter):
+        offset = (((current_bytecode & 7) - 4) << 8) + parameter
+        self._jump(offset)
 
-    def longJumpPosition(self, current_bytecode):
-        return ((current_bytecode & 3) << 8) + self.fetch_next_bytecode()
+    @bytecode_implementation(parameter_bytes=1)
+    def longJumpIfTrueBytecode(self, interp, current_bytecode, parameter):
+        self._jumpConditional(interp, True, self._longJumpOffset(current_bytecode, parameter))
 
-    def longJumpIfTrueBytecode(self, interp, current_bytecode):
-        self.jumpConditional(interp, True, self.longJumpPosition(current_bytecode))
+    @bytecode_implementation(parameter_bytes=1)
+    def longJumpIfFalseBytecode(self, interp, current_bytecode, parameter):
+        self._jumpConditional(interp, False, self._longJumpOffset(current_bytecode, parameter))
 
-    def longJumpIfFalseBytecode(self, interp, current_bytecode):
-        self.jumpConditional(interp, False, self.longJumpPosition(current_bytecode))
+    # ====== Bytecodes implemented with primitives and message sends ======
 
     bytecodePrimAdd = make_call_primitive_bytecode(primitives.ADD, "+", 1)
     bytecodePrimSubtract = make_call_primitive_bytecode(primitives.SUBTRACT, "-", 1)
@@ -698,61 +798,25 @@
     bytecodePrimBitAnd = make_call_primitive_bytecode(primitives.BIT_AND, "bitAnd:", 1)
     bytecodePrimBitOr = make_call_primitive_bytecode(primitives.BIT_OR, "bitOr:", 1)
 
-    @objectmodel.specialize.arg(1)
-    def _sendSelfSelectorSpecial(self, selector, numargs, interp):
-        w_selector = self.space.get_special_selector(selector)
-        return self._sendSelfSelector(w_selector, numargs, interp)
+    bytecodePrimAt = make_send_selector_bytecode("at:", 1)
+    bytecodePrimAtPut = make_send_selector_bytecode("at:put:", 2)
+    bytecodePrimSize = make_send_selector_bytecode("size", 0)
+    bytecodePrimNext = make_send_selector_bytecode("next", 0)
+    bytecodePrimNextPut = make_send_selector_bytecode("nextPut:", 1)
+    bytecodePrimAtEnd = make_send_selector_bytecode("atEnd", 0)
 
-    def bytecodePrimAt(self, interp, current_bytecode):
-        # n.b.: depending on the type of the receiver, this may invoke
-        # primitives.AT, primitives.STRING_AT, or something else for all
-        # I know.
-        return self._sendSelfSelectorSpecial("at:", 1, interp)
-
-    def bytecodePrimAtPut(self, interp, current_bytecode):
-        # n.b. as above
-        return self._sendSelfSelectorSpecial("at:put:", 2, interp)
-
-    def bytecodePrimSize(self, interp, current_bytecode):
-        return self._sendSelfSelectorSpecial("size", 0, interp)
-
-    def bytecodePrimNext(self, interp, current_bytecode):
-        return self._sendSelfSelectorSpecial("next", 0, interp)
-
-    def bytecodePrimNextPut(self, interp, current_bytecode):
-        return self._sendSelfSelectorSpecial("nextPut:", 1, interp)
-
-    def bytecodePrimAtEnd(self, interp, current_bytecode):
-        return self._sendSelfSelectorSpecial("atEnd", 0, interp)
-
-    def bytecodePrimEquivalent(self, interp, current_bytecode):
-        # short-circuit: classes cannot override the '==' method,
-        # which cannot fail
-        primitives.prim_table[primitives.EQUIVALENT](interp, self, 1)
-
-    def bytecodePrimClass(self, interp, current_bytecode):
-        # short-circuit: classes cannot override the 'class' method,
-        # which cannot fail
-        primitives.prim_table[primitives.CLASS](interp, self, 0)
+    bytecodePrimEquivalent = make_quick_call_primitive_bytecode(primitives.EQUIVALENT, 1)
+    bytecodePrimClass = make_quick_call_primitive_bytecode(primitives.CLASS, 0)
 
     bytecodePrimBlockCopy = make_call_primitive_bytecode(primitives.BLOCK_COPY, "blockCopy:", 1)
     bytecodePrimValue = make_call_primitive_bytecode_classbased("w_BlockContext", primitives.VALUE, "w_BlockClosure", primitives.CLOSURE_VALUE, "value", 0)
     bytecodePrimValueWithArg = make_call_primitive_bytecode_classbased("w_BlockContext", primitives.VALUE, "w_BlockClosure", primitives.CLOSURE_VALUE_, "value:", 1)
 
-    def bytecodePrimDo(self, interp, current_bytecode):
-        return self._sendSelfSelectorSpecial("do:", 1, interp)
-
-    def bytecodePrimNew(self, interp, current_bytecode):
-        return self._sendSelfSelectorSpecial("new", 0, interp)
-
-    def bytecodePrimNewWithArg(self, interp, current_bytecode):
-        return self._sendSelfSelectorSpecial("new:", 1, interp)
-
-    def bytecodePrimPointX(self, interp, current_bytecode):
-        return self._sendSelfSelectorSpecial("x", 0, interp)
-
-    def bytecodePrimPointY(self, interp, current_bytecode):
-        return self._sendSelfSelectorSpecial("y", 0, interp)
+    bytecodePrimDo = make_send_selector_bytecode("do:", 1)
+    bytecodePrimNew = make_send_selector_bytecode("new", 0)
+    bytecodePrimNewWithArg = make_send_selector_bytecode("new:", 1)
+    bytecodePrimPointX = make_send_selector_bytecode("x", 0)
+    bytecodePrimPointY = make_send_selector_bytecode("y", 0)
 
 BYTECODE_RANGES = [
             (  0,  15, "pushReceiverVariableBytecode"),
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
@@ -1008,7 +1008,7 @@
         interp._loop = True
         interp.loop_bytecodes(w_method.create_frame(space, space.wrap_int(0), []))
     except interpreter.StackOverflow, e:
-        assert isinstance(e.s_context, shadow.MethodContextShadow)
+        assert isinstance(e.s_new_context, shadow.MethodContextShadow)
     except interpreter.ReturnFromTopLevel, e:
         assert False
 
@@ -1016,8 +1016,8 @@
     def stack_frame(self, w_frame, may_interrupt=True):
         stack_depth = self.max_stack_depth - self.remaining_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'
+            assert sys._getframe(5 + i * 7).f_code.co_name == 'loop_bytecodes'
+        assert sys._getframe(6 + stack_depth * 7).f_code.co_name == 'loop'
         return interpreter.Interpreter.stack_frame(self, w_frame)
 
 def test_actual_stackdepth():


More information about the pypy-commit mailing list