[pypy-svn] r10079 - pypy/dist/pypy/interpreter

ac at codespeak.net ac at codespeak.net
Tue Mar 22 19:47:54 CET 2005


Author: ac
Date: Tue Mar 22 19:47:54 2005
New Revision: 10079

Modified:
   pypy/dist/pypy/interpreter/pyframe.py
   pypy/dist/pypy/interpreter/typedef.py
Log:
Add support for setting f_lineno in frames. This makes the settrace() functionality complete.

Modified: pypy/dist/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyframe.py	(original)
+++ pypy/dist/pypy/interpreter/pyframe.py	Tue Mar 22 19:47:54 2005
@@ -5,6 +5,14 @@
 from pypy.interpreter.miscutils import Stack
 from pypy.interpreter.error import OperationError
 from pypy.interpreter import pytraceback
+import opcode
+
+# Define some opcodes used
+g = globals()
+for op in '''DUP_TOP POP_TOP SETUP_LOOP SETUP_EXCEPT SETUP_FINALLY
+POP_BLOCK END_FINALLY'''.split():
+    g[op] = opcode.opmap[op]
+HAVE_ARGUMENT = opcode.HAVE_ARGUMENT
 
 import __future__
 compiler_flags = 0
@@ -80,6 +88,7 @@
                                 # dispatch() is abstract, see pyopcode.
                                 self.last_instr = self.next_instr
                                 executioncontext.bytecode_trace(self)
+                                self.next_instr = self.last_instr
                                 self.dispatch()
                         # catch asynchronous exceptions and turn them
                         # into OperationErrors
@@ -139,19 +148,123 @@
         else:
             return space.wrap(self.f_lineno)
 
-##     def fset_f_lineno(space, w_self, w_f_lineo):
-##         "Returns the line number of the instruction currently being executed."
-##         f_lineo = space.int_w(w_f_lineo)
-
-##         self = space.interpclass_w(w_self)
-##         if self.self.w_f_trace is None:
-##             raise OperationError(self.space.w_ValueError, space.wrap("f_lineo can only be set by a trace function."))
+    def fset_f_lineno(space, w_self, w_new_lineno):
+        "Returns the line number of the instruction currently being executed."
+        try:
+            new_lineno = space.int_w(w_new_lineno)
+        except OperationError, e:
+            raise OperationError(space.w_ValueError, space.wrap("lineno must be an integer"))
+            
+        self = space.interpclass_w(w_self)
+        if self.w_f_trace is None:
+            raise OperationError(space.w_ValueError, space.wrap("f_lineo can only be set by a trace function."))
+
+        if new_lineno < self.code.co_firstlineno:
+            raise OperationError(space.w_ValueError, space.wrap("line %d comes before the current code." % new_lineno))
+        code = self.code.co_code
+        addr = 0
+        line = self.code.co_firstlineno
+        new_lasti = -1
+        offset = 0
+        lnotab = self.code.co_lnotab
+        for offset in xrange(0, len(lnotab), 2):
+            addr += ord(lnotab[offset])
+            line += ord(lnotab[offset + 1])
+            if line >= new_lineno:
+                new_lasti = addr
+                new_lineno = line
+                break
 
-##         if f_lineo < self.code.co_firstlineno:
-##             raise OperationError(self.space.w_ValueError, space.wrap("line %d comes before the current code." % f_lineo))
+        if new_lasti == -1:
+            raise OperationError(space.w_ValueError, space.wrap("line %d comes after the current code." % new_lineno))
 
-##         self.f_lineno = f_lineo
+        # Don't jump to a line with an except in it.
+        if ord(code[new_lasti]) in (DUP_TOP, POP_TOP):
+            raise OperationError(space.w_ValueError, space.wrap("can't jump to 'except' line as there's no exception"))
+            
 
+        # Don't jump into or out of a finally block.
+        f_lasti_setup_addr = -1
+        new_lasti_setup_addr = -1
+        blockstack = Stack()
+        addr = 0
+        while addr < len(code):
+            op = ord(code[addr])
+            if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY):
+                blockstack.push([addr, False])
+            elif op == POP_BLOCK:
+                setup_op = ord(code[blockstack.top()[0]])
+                if setup_op == SETUP_FINALLY:
+                    blockstack.top()[1] = True
+                else:
+                    blockstack.pop()
+            elif op == END_FINALLY:
+                if not blockstack.empty():
+                    setup_op = ord(code[blockstack.top()[0]])
+                    if setup_op == SETUP_FINALLY:
+                        blockstack.pop()
+
+            if addr == new_lasti or addr == self.last_instr:
+                for setup_addr, in_finally in blockstack:
+                    if in_finally:
+                        if addr == new_lasti:
+                            new_lasti_setup_addr = setup_addr
+                        if addr == self.last_instr:
+                            f_lasti_setup_addr = setup_addr
+                        break
+                    
+            if op >= HAVE_ARGUMENT:
+                addr += 3
+            else:
+                addr += 1
+                
+        assert blockstack.empty()
+
+        if new_lasti_setup_addr != f_lasti_setup_addr:
+            raise OperationError(space.w_ValueError, space.wrap("can't jump into or out of a 'finally' block %d -> %d"%(f_lasti_setup_addr, new_lasti_setup_addr)))
+
+        if new_lasti < self.last_instr:
+            min_addr = new_lasti
+            max_addr = self.last_instr
+        else:
+            min_addr = self.last_instr
+            max_addr = new_lasti
+
+        delta_iblock = min_delta_iblock = 0
+        addr = min_addr
+        while addr < max_addr:
+            op = ord(code[addr])
+
+            if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY):
+                delta_iblock += 1;
+            elif op == POP_BLOCK:
+                delta_iblock -= 1
+                if delta_iblock < min_delta_iblock:
+                    min_delta_iblock = delta_iblock
+
+            if op >= opcode.HAVE_ARGUMENT:
+                addr += 3
+            else:
+                addr += 1
+
+        f_iblock = self.blockstack.depth()
+        min_iblock = f_iblock + min_delta_iblock
+        if new_lasti > self.last_instr:
+            new_iblock = f_iblock + delta_iblock
+        else:
+            new_iblock = f_iblock - delta_iblock
+
+        if new_iblock > min_iblock:
+            raise OperationError(space.w_ValueError, space.wrap("can't jump into the middle of a block"))
+
+        while f_iblock > new_iblock:
+            block = self.blockstack.pop()
+            block.cleanup(self)
+            f_iblock -= 1
+            
+        self.f_lineno = new_lineno
+        self.last_instr = new_lasti
+            
     def get_last_lineno(self):
         "Returns the line number of the instruction currently being executed."
         return pytraceback.offset2lineno(self.code, self.next_instr-1)

Modified: pypy/dist/pypy/interpreter/typedef.py
==============================================================================
--- pypy/dist/pypy/interpreter/typedef.py	(original)
+++ pypy/dist/pypy/interpreter/typedef.py	Tue Mar 22 19:47:54 2005
@@ -324,7 +324,7 @@
 
 PyFrame.typedef = TypeDef('frame',
     f_builtins = GetSetProperty(PyFrame.fget_f_builtins),
-    f_lineno = GetSetProperty(PyFrame.fget_f_lineno),
+    f_lineno = GetSetProperty(PyFrame.fget_f_lineno, PyFrame.fset_f_lineno),
     f_back = GetSetProperty(PyFrame.fget_f_back),
     f_lasti = GetSetProperty(PyFrame.fget_f_lasti),
     f_trace = GetSetProperty(PyFrame.fget_f_trace, PyFrame.fset_f_trace),



More information about the Pypy-commit mailing list