Author: Carl Friedrich Bolz <cfb...@gmx.de>
Branch: globals-quasiimmut
Changeset: r81747:a2af053cbe15
Date: 2016-01-13 21:31 +0100
http://bitbucket.org/pypy/pypy/changeset/a2af053cbe15/

Log:    store the first w_globals that a code object is run in on the code
        object. if a frame runs within that code object (which is almost
        always), it does not need to store it.

diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py
--- a/pypy/interpreter/eval.py
+++ b/pypy/interpreter/eval.py
@@ -9,8 +9,8 @@
 class Code(W_Root):
     """A code is a compiled version of some source code.
     Abstract base class."""
-    _immutable_ = True
     hidden_applevel = False
+    _immutable_fields_ = ['co_name', 'fast_natural_arity', 'hidden_applevel']
 
     # n >= 0 : arity
     # FLATPYCALL = 0x100
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -56,11 +56,13 @@
 
 class PyCode(eval.Code):
     "CPython-style code objects."
-    _immutable_ = True
-    _immutable_fields_ = ["co_consts_w[*]", "co_names_w[*]", "co_varnames[*]",
-                          "co_freevars[*]", "co_cellvars[*]",
-                          "_args_as_cellvars[*]"]
-    
+    _immutable_fields_ = ["_signature", "co_argcount", "co_cellvars[*]",
+                          "co_code", "co_consts_w[*]", "co_filename",
+                          "co_firstlineno", "co_flags", "co_freevars[*]",
+                          "co_lnotab", "co_names_w[*]", "co_nlocals",
+                          "co_stacksize", "co_varnames[*]",
+                          "_args_as_cellvars[*]", "w_globals?"]
+
     def __init__(self, space,  argcount, nlocals, stacksize, flags,
                      code, consts, names, varnames, filename,
                      name, firstlineno, lnotab, freevars, cellvars,
@@ -84,6 +86,10 @@
         self.co_name = name
         self.co_firstlineno = firstlineno
         self.co_lnotab = lnotab
+        # store the first globals object that the code object is run in in
+        # here. if a frame is run in that globals object, it does not need to
+        # store it at all
+        self.w_globals = None
         self.hidden_applevel = hidden_applevel
         self.magic = magic
         self._signature = cpython_code_signature(self)
@@ -91,6 +97,14 @@
         self._init_ready()
         self.new_code_hook()
 
+    def frame_stores_global(self, w_globals):
+        if self.w_globals is None:
+            self.w_globals = w_globals
+            return False
+        if self.w_globals is w_globals:
+            return False
+        return True
+
     def new_code_hook(self):
         code_hook = self.space.fromcache(CodeHookCache)._code_hook
         if code_hook is not None:
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -33,9 +33,11 @@
     f_lineno                 = 0      # current lineno for tracing
     is_being_profiled        = False
     w_locals                 = None
+    w_globals                = None
 
     def __init__(self, pycode):
         self.f_lineno = pycode.co_firstlineno
+        self.w_globals = pycode.w_globals
 
 class PyFrame(W_Root):
     """Represents a frame for a regular Python function
@@ -67,7 +69,6 @@
     escaped                  = False  # see mark_as_escaped()
     debugdata                = None
 
-    w_globals = None
     pycode = None # code object executed by that frame
     locals_cells_stack_w = None # the list of all locals, cells and the 
valuestack
     valuestackdepth = 0 # number of items on valuestack
@@ -90,8 +91,9 @@
         self = hint(self, access_directly=True, fresh_virtualizable=True)
         assert isinstance(code, pycode.PyCode)
         self.space = space
-        self.w_globals = w_globals
         self.pycode = code
+        if code.frame_stores_global(w_globals):
+            self.getorcreatedebug().w_globals = w_globals
         ncellvars = len(code.co_cellvars)
         nfreevars = len(code.co_freevars)
         size = code.co_nlocals + ncellvars + nfreevars + code.co_stacksize
@@ -116,6 +118,15 @@
             self.debugdata = FrameDebugData(self.pycode)
         return self.debugdata
 
+    def get_w_globals(self):
+        debugdata = self.getdebug()
+        if debugdata is not None:
+            return debugdata.w_globals
+        return jit.promote(self.pycode).w_globals
+
+    def set_w_globals(self, w_globals):
+        self.getorcreatedebug().w_globals = w_globals
+
     def get_w_f_trace(self):
         d = self.getdebug()
         if d is None:
@@ -201,8 +212,9 @@
             if flags & pycode.CO_NEWLOCALS:
                 self.getorcreatedebug().w_locals = 
self.space.newdict(module=True)
             else:
-                assert self.w_globals is not None
-                self.getorcreatedebug().w_locals = self.w_globals
+                w_globals = self.get_w_globals()
+                assert w_globals is not None
+                self.getorcreatedebug().w_locals = w_globals
 
         ncellvars = len(code.co_cellvars)
         nfreevars = len(code.co_freevars)
@@ -449,7 +461,7 @@
             w_blockstack,
             w_exc_value, # last_exception
             w_tb,        #
-            self.w_globals,
+            self.get_w_globals(),
             w(self.last_instr),
             w(self.frame_finished_execution),
             w(f_lineno),
@@ -658,6 +670,14 @@
     def fget_getdictscope(self, space):
         return self.getdictscope()
 
+    def fget_w_globals(self, space):
+        # bit silly, but GetSetProperty passes a space
+        return self.get_w_globals()
+
+    def fset_w_globals(self, space, w_obj):
+        # bit silly, but GetSetProperty passes a space
+        return self.set_w_globals(w_obj)
+
     ### line numbers ###
 
     def fget_f_lineno(self, space):
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -837,7 +837,7 @@
         w_bases = self.popvalue()
         w_name = self.popvalue()
         w_metaclass = find_metaclass(self.space, w_bases,
-                                     w_methodsdict, self.w_globals,
+                                     w_methodsdict, self.get_w_globals(),
                                      self.space.wrap(self.get_builtin()))
         w_newclass = self.space.call_function(w_metaclass, w_name,
                                               w_bases, w_methodsdict)
@@ -881,14 +881,14 @@
     def STORE_GLOBAL(self, nameindex, next_instr):
         varname = self.getname_u(nameindex)
         w_newvalue = self.popvalue()
-        self.space.setitem_str(self.w_globals, varname, w_newvalue)
+        self.space.setitem_str(self.get_w_globals(), varname, w_newvalue)
 
     def DELETE_GLOBAL(self, nameindex, next_instr):
         w_varname = self.getname_w(nameindex)
-        self.space.delitem(self.w_globals, w_varname)
+        self.space.delitem(self.get_w_globals(), w_varname)
 
     def LOAD_NAME(self, nameindex, next_instr):
-        if self.getorcreatedebug().w_locals is not self.w_globals:
+        if self.getorcreatedebug().w_locals is not self.get_w_globals():
             varname = self.getname_u(nameindex)
             w_value = self.space.finditem_str(self.getorcreatedebug().w_locals,
                                               varname)
@@ -898,7 +898,7 @@
         self.LOAD_GLOBAL(nameindex, next_instr)    # fall-back
 
     def _load_global(self, varname):
-        w_value = self.space.finditem_str(self.w_globals, varname)
+        w_value = self.space.finditem_str(self.get_w_globals(), varname)
         if w_value is None:
             # not in the globals, now look in the built-ins
             w_value = self.get_builtin().getdictvalue(self.space, varname)
@@ -1029,7 +1029,7 @@
         if w_locals is None:            # CPython does this
             w_locals = space.w_None
         w_modulename = space.wrap(modulename)
-        w_globals = self.w_globals
+        w_globals = self.get_w_globals()
         if w_flag is None:
             w_obj = space.call_function(w_import, w_modulename, w_globals,
                                         w_locals, w_fromlist)
@@ -1237,7 +1237,7 @@
         w_codeobj = self.popvalue()
         codeobj = self.space.interp_w(PyCode, w_codeobj)
         defaultarguments = self.popvalues(numdefaults)
-        fn = function.Function(self.space, codeobj, self.w_globals,
+        fn = function.Function(self.space, codeobj, self.get_w_globals(),
                                defaultarguments)
         self.pushvalue(self.space.wrap(fn))
 
@@ -1249,7 +1249,7 @@
         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,
+        fn = function.Function(self.space, codeobj, self.get_w_globals(),
                                defaultarguments, freevars)
         self.pushvalue(self.space.wrap(fn))
 
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -772,7 +772,7 @@
     f_restricted = GetSetProperty(PyFrame.fget_f_restricted),
     f_code = GetSetProperty(PyFrame.fget_code),
     f_locals = GetSetProperty(PyFrame.fget_getdictscope),
-    f_globals = interp_attrproperty_w('w_globals', cls=PyFrame),
+    f_globals = GetSetProperty(PyFrame.fget_w_globals, PyFrame.fset_w_globals),
 )
 assert not PyFrame.typedef.acceptable_as_base_class  # no __new__
 
diff --git a/pypy/module/__builtin__/compiling.py 
b/pypy/module/__builtin__/compiling.py
--- a/pypy/module/__builtin__/compiling.py
+++ b/pypy/module/__builtin__/compiling.py
@@ -93,7 +93,7 @@
             if space.is_none(w_locals):
                 w_locals = w_globals
         else:
-            w_globals = caller.w_globals
+            w_globals = caller.get_w_globals()
             if space.is_none(w_locals):
                 w_locals = caller.getdictscope()
     elif space.is_none(w_locals):
diff --git a/pypy/module/__builtin__/interp_inspect.py 
b/pypy/module/__builtin__/interp_inspect.py
--- a/pypy/module/__builtin__/interp_inspect.py
+++ b/pypy/module/__builtin__/interp_inspect.py
@@ -2,7 +2,7 @@
 def globals(space):
     "Return the dictionary containing the current scope's global variables."
     ec = space.getexecutioncontext()
-    return ec.gettopframe_nohidden().w_globals
+    return ec.gettopframe_nohidden().get_w_globals()
 
 def locals(space):
     """Return a dictionary containing the current scope's local variables.
diff --git a/pypy/module/_warnings/interp_warnings.py 
b/pypy/module/_warnings/interp_warnings.py
--- a/pypy/module/_warnings/interp_warnings.py
+++ b/pypy/module/_warnings/interp_warnings.py
@@ -75,7 +75,7 @@
         frame = ec.getnextframe_nohidden(frame)
         stacklevel -= 1
     if frame:
-        w_globals = frame.w_globals
+        w_globals = frame.get_w_globals()
         lineno = frame.get_last_lineno()
     else:
         w_globals = space.sys.w_dict
diff --git a/pypy/module/cpyext/eval.py b/pypy/module/cpyext/eval.py
--- a/pypy/module/cpyext/eval.py
+++ b/pypy/module/cpyext/eval.py
@@ -30,7 +30,7 @@
     currently executing."""
     caller = space.getexecutioncontext().gettopframe_nohidden()
     if caller is not None:
-        w_globals = caller.w_globals
+        w_globals = caller.get_w_globals()
         w_builtins = space.getitem(w_globals, space.wrap('__builtins__'))
         if not space.isinstance_w(w_builtins, space.w_dict):
             w_builtins = w_builtins.getdict(space)
@@ -54,7 +54,7 @@
     caller = space.getexecutioncontext().gettopframe_nohidden()
     if caller is None:
         return None
-    return borrow_from(None, caller.w_globals)
+    return borrow_from(None, caller.get_w_globals())
 
 @cpython_api([PyCodeObject, PyObject, PyObject], PyObject)
 def PyEval_EvalCode(space, w_code, w_globals, w_locals):
diff --git a/pypy/module/cpyext/frameobject.py 
b/pypy/module/cpyext/frameobject.py
--- a/pypy/module/cpyext/frameobject.py
+++ b/pypy/module/cpyext/frameobject.py
@@ -34,7 +34,7 @@
     frame = space.interp_w(PyFrame, w_obj)
     py_frame = rffi.cast(PyFrameObject, py_obj)
     py_frame.c_f_code = rffi.cast(PyCodeObject, make_ref(space, frame.pycode))
-    py_frame.c_f_globals = make_ref(space, frame.w_globals)
+    py_frame.c_f_globals = make_ref(space, frame.get_w_globals())
     rffi.setintfield(py_frame, 'c_f_lineno', frame.getorcreatedebug().f_lineno)
 
 @cpython_api([PyObject], lltype.Void, external=False)
diff --git a/pypy/module/cpyext/import_.py b/pypy/module/cpyext/import_.py
--- a/pypy/module/cpyext/import_.py
+++ b/pypy/module/cpyext/import_.py
@@ -20,7 +20,7 @@
     caller = space.getexecutioncontext().gettopframe_nohidden()
     # Get the builtins from current globals
     if caller is not None:
-        w_globals = caller.w_globals
+        w_globals = caller.get_w_globals()
         w_builtin = space.getitem(w_globals, space.wrap('__builtins__'))
     else:
         # No globals -- use standard builtins, and fake globals
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -1139,7 +1139,7 @@
         space = w_self.space
         caller = space.getexecutioncontext().gettopframe_nohidden()
         if caller is not None:
-            w_globals = caller.w_globals
+            w_globals = caller.get_w_globals()
             w_name = space.finditem(w_globals, space.wrap('__name__'))
             if w_name is not None:
                 w_self.dict_w['__module__'] = w_name
diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py
--- a/pypy/tool/pytest/appsupport.py
+++ b/pypy/tool/pytest/appsupport.py
@@ -63,7 +63,7 @@
         for key, w_value in vars.items():
             space.setitem(self.w_locals, space.wrap(key), w_value)
         if isinstance(code, str):
-            return space.eval(code, self.w_globals, self.w_locals)
+            return space.eval(code, self.get_w_globals(), self.w_locals)
         pyc = pycode.PyCode._from_code(space, code)
         return pyc.exec_host_bytecode(self.w_globals, self.w_locals)
     exec_ = eval
@@ -248,7 +248,7 @@
         #if filename.endswith("pyc"):
         #    filename = filename[:-1]
         try:
-            space.exec_(str(source), frame.w_globals, w_locals,
+            space.exec_(str(source), frame.get_w_globals(), w_locals,
                         filename=filename)
         except OperationError, e:
             if e.match(space, w_ExpectedException):
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to