Commits

Alex Gaynor  committed ef88c5a

Merged nestedscope's frame manipulation code into the proper classes

  • Participants
  • Parent commits 06b2c9f

Comments (0)

Files changed (4)

File pypy/interpreter/baseobjspace.py

         self.builtin_modules = {}
         self.reloading_modules = {}
 
-        # import extra modules for side-effects
-        import pypy.interpreter.nestedscope     # register *_DEREF bytecodes
-
         self.interned_strings = {}
         self.actionflag = ActionFlag()    # changed by the signal module
         self.check_signal_action = None   # changed by the signal module

File pypy/interpreter/nestedscope.py

-from rpython.rlib import jit
 from rpython.tool.uid import uid
 
-from pypy.interpreter import function, pycode, pyframe
-from pypy.interpreter.astcompiler import consts
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.mixedmodule import MixedModule
             return self.get()
         except ValueError:
             raise OperationError(space.w_ValueError, space.wrap("Cell is empty"))
-
-
-super_initialize_frame_scopes = pyframe.PyFrame.initialize_frame_scopes
-super_fast2locals = pyframe.PyFrame.fast2locals
-super_locals2fast = pyframe.PyFrame.locals2fast
-
-
-class __extend__(pyframe.PyFrame):
-    """This class enhances a standard frame with nested scope abilities,
-    i.e. handling of cell/free variables."""
-
-    # Cell Vars:
-    #     my local variables that are exposed to my inner functions
-    # Free Vars:
-    #     variables coming from a parent function in which i'm nested
-    # 'closure' is a list of Cell instances: the received free vars.
-
-    @jit.unroll_safe
-    def initialize_frame_scopes(self, outer_func, code):
-        super_initialize_frame_scopes(self, outer_func, code)
-        ncellvars = len(code.co_cellvars)
-        nfreevars = len(code.co_freevars)
-        if not nfreevars:
-            if not ncellvars:
-                self.cells = []
-                return            # no self.cells needed - fast path
-        elif outer_func is None:
-            space = self.space
-            raise OperationError(space.w_TypeError,
-                                 space.wrap("directly executed code object "
-                                            "may not contain free variables"))
-        if outer_func and outer_func.closure:
-            closure_size = len(outer_func.closure)
-        else:
-            closure_size = 0
-        if closure_size != nfreevars:
-            raise ValueError("code object received a closure with "
-                                 "an unexpected number of free variables")
-        self.cells = [None] * (ncellvars + nfreevars)
-        for i in range(ncellvars):
-            self.cells[i] = Cell()
-        for i in range(nfreevars):
-            self.cells[i + ncellvars] = outer_func.closure[i]
-
-    def _getcells(self):
-        return self.cells
-
-    def _setcellvars(self, cellvars):
-        ncellvars = len(self.pycode.co_cellvars)
-        if len(cellvars) != ncellvars:
-            raise OperationError(self.space.w_TypeError,
-                                 self.space.wrap("bad cellvars"))
-        self.cells[:ncellvars] = cellvars
-
-    @jit.unroll_safe
-    def fast2locals(self):
-        super_fast2locals(self)
-        # cellvars are values exported to inner scopes
-        # freevars are values coming from outer scopes
-        freevarnames = list(self.pycode.co_cellvars)
-        if self.pycode.co_flags & consts.CO_OPTIMIZED:
-            freevarnames.extend(self.pycode.co_freevars)
-        for i in range(len(freevarnames)):
-            name = freevarnames[i]
-            cell = self.cells[i]
-            try:
-                w_value = cell.get()
-            except ValueError:
-                pass
-            else:
-                w_name = self.space.wrap(name)
-                self.space.setitem(self.w_locals, w_name, w_value)
-
-    @jit.unroll_safe
-    def locals2fast(self):
-        super_locals2fast(self)
-        freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
-        for i in range(len(freevarnames)):
-            name = freevarnames[i]
-            cell = self.cells[i]
-            w_name = self.space.wrap(name)
-            try:
-                w_value = self.space.getitem(self.w_locals, w_name)
-            except OperationError, e:
-                if not e.match(self.space, self.space.w_KeyError):
-                    raise
-            else:
-                cell.set(w_value)
-
-    @jit.unroll_safe
-    def init_cells(self):
-        args_to_copy = self.pycode._args_as_cellvars
-        for i in range(len(args_to_copy)):
-            argnum = args_to_copy[i]
-            if argnum >= 0:
-                self.cells[i].set(self.locals_stack_w[argnum])
-
-    def getfreevarname(self, index):
-        freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
-        return freevarnames[index]
-
-    def iscellvar(self, index):
-        # is the variable given by index a cell or a free var?
-        return index < len(self.pycode.co_cellvars)
-
-    ### extra opcodes ###
-
-    def LOAD_CLOSURE(self, varindex, next_instr):
-        # nested scopes: access the cell object
-        cell = self.cells[varindex]
-        w_value = self.space.wrap(cell)
-        self.pushvalue(w_value)
-
-    def LOAD_DEREF(self, varindex, next_instr):
-        # nested scopes: access a variable through its cell object
-        cell = self.cells[varindex]
-        try:
-            w_value = cell.get()
-        except ValueError:
-            varname = self.getfreevarname(varindex)
-            if self.iscellvar(varindex):
-                message = "local variable '%s' referenced before assignment" % varname
-                w_exc_type = self.space.w_UnboundLocalError
-            else:
-                message = ("free variable '%s' referenced before assignment"
-                           " in enclosing scope" % varname)
-                w_exc_type = self.space.w_NameError
-            raise OperationError(w_exc_type, self.space.wrap(message))
-        else:
-            self.pushvalue(w_value)
-
-    def STORE_DEREF(self, varindex, next_instr):
-        # nested scopes: access a variable through its cell object
-        w_newvalue = self.popvalue()
-        cell = self.cells[varindex]
-        cell.set(w_newvalue)
-
-    @jit.unroll_safe
-    def MAKE_CLOSURE(self, numdefaults, next_instr):
-        w_codeobj = self.popvalue()
-        codeobj = self.space.interp_w(pycode.PyCode, w_codeobj)
-        w_freevarstuple = self.popvalue()
-        freevars = [self.space.interp_w(Cell, cell)
-                    for cell in self.space.fixedview(w_freevarstuple)]
-        defaultarguments = self.popvalues(numdefaults)
-        fn = function.Function(self.space, codeobj, self.w_globals,
-                               defaultarguments, freevars)
-        self.pushvalue(self.space.wrap(fn))

File pypy/interpreter/pyframe.py

 
 from pypy.interpreter import pycode, pytraceback
 from pypy.interpreter.argument import Arguments
+from pypy.interpreter.astcompiler import consts
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.executioncontext import ExecutionContext
+from pypy.interpreter.nestedscope import Cell
 from pypy.tool import stdlib_opcode
 
 # Define some opcodes used
     """Represents a frame for a regular Python function
     that needs to be interpreted.
 
-    See also pyopcode.PyStandardFrame and nestedscope.PyNestedScopeFrame.
-
     Public fields:
      * 'space' is the object space this frame is running in
      * 'code' is the PyCode object this frame runs
      * 'w_globals' is the attached globals dictionary
      * 'builtin' is the attached built-in module
      * 'valuestack_w', 'blockstack', control the interpretation
+
+    Cell Vars:
+        my local variables that are exposed to my inner functions
+    Free Vars:
+        variables coming from a parent function in which i'm nested
+    'closure' is a list of Cell instances: the received free vars.
     """
 
     __metaclass__ = extendabletype
         else:
             return self.space.builtin
 
+    @jit.unroll_safe
     def initialize_frame_scopes(self, outer_func, code):
         # regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
         # class bodies only have CO_NEWLOCALS.
         # CO_OPTIMIZED: no locals dict needed at all
         # NB: this method is overridden in nestedscope.py
         flags = code.co_flags
-        if flags & pycode.CO_OPTIMIZED:
-            return
-        if flags & pycode.CO_NEWLOCALS:
-            self.w_locals = self.space.newdict(module=True)
+        if not (flags & pycode.CO_OPTIMIZED):
+            if flags & pycode.CO_NEWLOCALS:
+                self.w_locals = self.space.newdict(module=True)
+            else:
+                assert self.w_globals is not None
+                self.w_locals = self.w_globals
+
+        ncellvars = len(code.co_cellvars)
+        nfreevars = len(code.co_freevars)
+        if not nfreevars:
+            if not ncellvars:
+                self.cells = []
+                return            # no self.cells needed - fast path
+        elif outer_func is None:
+            space = self.space
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("directly executed code object "
+                                            "may not contain free variables"))
+        if outer_func and outer_func.closure:
+            closure_size = len(outer_func.closure)
         else:
-            assert self.w_globals is not None
-            self.w_locals = self.w_globals
+            closure_size = 0
+        if closure_size != nfreevars:
+            raise ValueError("code object received a closure with "
+                                 "an unexpected number of free variables")
+        self.cells = [None] * (ncellvars + nfreevars)
+        for i in range(ncellvars):
+            self.cells[i] = Cell()
+        for i in range(nfreevars):
+            self.cells[i + ncellvars] = outer_func.closure[i]
 
     def run(self):
         """Start this frame's execution."""
         w = space.wrap
         nt = space.newtuple
 
-        cells = self._getcells()
+        cells = self.cells
         if cells is None:
             w_cells = space.w_None
         else:
                     if not e.match(self.space, self.space.w_KeyError):
                         raise
 
+        # cellvars are values exported to inner scopes
+        # freevars are values coming from outer scopes
+        freevarnames = list(self.pycode.co_cellvars)
+        if self.pycode.co_flags & consts.CO_OPTIMIZED:
+            freevarnames.extend(self.pycode.co_freevars)
+        for i in range(len(freevarnames)):
+            name = freevarnames[i]
+            cell = self.cells[i]
+            try:
+                w_value = cell.get()
+            except ValueError:
+                pass
+            else:
+                w_name = self.space.wrap(name)
+                self.space.setitem(self.w_locals, w_name, w_value)
+
+
     @jit.unroll_safe
     def locals2fast(self):
         # Copy values from self.w_locals to the fastlocals
 
         self.setfastscope(new_fastlocals_w)
 
+        freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
+        for i in range(len(freevarnames)):
+            name = freevarnames[i]
+            cell = self.cells[i]
+            w_name = self.space.wrap(name)
+            try:
+                w_value = self.space.getitem(self.w_locals, w_name)
+            except OperationError, e:
+                if not e.match(self.space, self.space.w_KeyError):
+                    raise
+            else:
+                cell.set(w_value)
+
+    @jit.unroll_safe
     def init_cells(self):
-        """Initialize cellvars from self.locals_stack_w.
-        This is overridden in nestedscope.py"""
-        pass
+        """
+        Initialize cellvars from self.locals_stack_w.
+        """
+        args_to_copy = self.pycode._args_as_cellvars
+        for i in range(len(args_to_copy)):
+            argnum = args_to_copy[i]
+            if argnum >= 0:
+                self.cells[i].set(self.locals_stack_w[argnum])
 
     def getclosure(self):
         return None
 
-    def _getcells(self):
-        return None
-
     def _setcellvars(self, cellvars):
-        pass
+        ncellvars = len(self.pycode.co_cellvars)
+        if len(cellvars) != ncellvars:
+            raise OperationError(self.space.w_TypeError,
+                                 self.space.wrap("bad cellvars"))
+        self.cells[:ncellvars] = cellvars
 
     def fget_code(self, space):
         return space.wrap(self.getcode())

File pypy/interpreter/pyopcode.py

 The rest, dealing with variables in optimized ways, is in nestedscope.py.
 """
 
-import sys
-from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter import gateway, function, eval, pyframe, pytraceback
-from pypy.interpreter.pycode import PyCode, BytecodeCorruption
-from rpython.tool.sourcetools import func_with_new_name
+from rpython.rlib import jit, rstackovf
 from rpython.rlib.objectmodel import we_are_translated
-from rpython.rlib import jit, rstackovf
 from rpython.rlib.rarithmetic import r_uint, intmask
 from rpython.rlib.debug import check_nonneg
+from rpython.tool.sourcetools import func_with_new_name
+
+from pypy.interpreter import (
+    gateway, function, eval, pyframe, pytraceback, pycode
+)
+from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.nestedscope import Cell
+from pypy.interpreter.pycode import PyCode, BytecodeCorruption
 from pypy.tool.stdlib_opcode import bytecode_spec
 
 def unaryoperation(operationname):
         assert w_newvalue is not None
         self.locals_stack_w[varindex] = w_newvalue
 
+    def getfreevarname(self, index):
+        freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
+        return freevarnames[index]
+
+    def iscellvar(self, index):
+        # is the variable given by index a cell or a free var?
+        return index < len(self.pycode.co_cellvars)
+
+    def LOAD_DEREF(self, varindex, next_instr):
+        # nested scopes: access a variable through its cell object
+        cell = self.cells[varindex]
+        try:
+            w_value = cell.get()
+        except ValueError:
+            varname = self.getfreevarname(varindex)
+            if self.iscellvar(varindex):
+                message = "local variable '%s' referenced before assignment" % varname
+                w_exc_type = self.space.w_UnboundLocalError
+            else:
+                message = ("free variable '%s' referenced before assignment"
+                           " in enclosing scope" % varname)
+                w_exc_type = self.space.w_NameError
+            raise OperationError(w_exc_type, self.space.wrap(message))
+        else:
+            self.pushvalue(w_value)
+
+    def STORE_DEREF(self, varindex, next_instr):
+        # nested scopes: access a variable through its cell object
+        w_newvalue = self.popvalue()
+        cell = self.cells[varindex]
+        cell.set(w_newvalue)
+
+    def LOAD_CLOSURE(self, varindex, next_instr):
+        # nested scopes: access the cell object
+        cell = self.cells[varindex]
+        w_value = self.space.wrap(cell)
+        self.pushvalue(w_value)
+
     def POP_TOP(self, oparg, next_instr):
         self.popvalue()
 
                                defaultarguments)
         self.pushvalue(self.space.wrap(fn))
 
+    @jit.unroll_safe
+    def MAKE_CLOSURE(self, numdefaults, next_instr):
+        w_codeobj = self.popvalue()
+        codeobj = self.space.interp_w(pycode.PyCode, w_codeobj)
+        w_freevarstuple = self.popvalue()
+        freevars = [self.space.interp_w(Cell, cell)
+                    for cell in self.space.fixedview(w_freevarstuple)]
+        defaultarguments = self.popvalues(numdefaults)
+        fn = function.Function(self.space, codeobj, self.w_globals,
+                               defaultarguments, freevars)
+        self.pushvalue(self.space.wrap(fn))
+
     def BUILD_SLICE(self, numargs, next_instr):
         if numargs == 3:
             w_step = self.popvalue()