[pypy-svn] r68846 - in pypy/trunk/pypy: interpreter interpreter/test objspace

cfbolz at codespeak.net cfbolz at codespeak.net
Thu Oct 29 15:58:17 CET 2009


Author: cfbolz
Date: Thu Oct 29 15:58:17 2009
New Revision: 68846

Modified:
   pypy/trunk/pypy/interpreter/function.py
   pypy/trunk/pypy/interpreter/gateway.py
   pypy/trunk/pypy/interpreter/test/test_function.py
   pypy/trunk/pypy/objspace/descroperation.py
Log:
Make it impossible to change the code object of builtin functions. This gets rid
of a getfield and a guard for all builtin function calls.


Modified: pypy/trunk/pypy/interpreter/function.py
==============================================================================
--- pypy/trunk/pypy/interpreter/function.py	(original)
+++ pypy/trunk/pypy/interpreter/function.py	Thu Oct 29 15:58:17 2009
@@ -16,12 +16,20 @@
 
 funccallunrolling = unrolling_iterable(range(4))
 
+ at jit.purefunction
+def _get_immutable_code(func):
+    assert not func.can_change_code
+    return func.code
+
 class Function(Wrappable):
     """A function is a code object captured with some environment:
     an object space, a dictionary of globals, default arguments,
     and an arbitrary 'closure' passed to the code object."""
 
-    def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None):
+    can_change_code = True
+
+    def __init__(self, space, code, w_globals=None, defs_w=[], closure=None,
+                 forcename=None):
         self.space = space
         self.name = forcename or code.co_name
         self.w_doc = None   # lazily read from code.getdocstring()
@@ -48,7 +56,12 @@
         return self.getcode().funcrun_obj(self, w_obj, args)
 
     def getcode(self):
-        return jit.hint(self.code, promote=True)
+        if jit.we_are_jitted():
+            if not self.can_change_code:
+                self = jit.hint(self, promote=True)
+                return _get_immutable_code(self)
+            return jit.hint(self.code, promote=True)
+        return self.code
     
     def funccall(self, *args_w): # speed hack
         from pypy.interpreter import gateway
@@ -368,6 +381,9 @@
 
     def fset_func_code(space, self, w_code):
         from pypy.interpreter.pycode import PyCode
+        if not self.can_change_code:
+            raise OperationError(space.w_TypeError,
+                    space.wrap("Cannot change code attribute of builtin functions"))
         code = space.interp_w(Code, w_code)
         closure_len = 0
         if self.closure:
@@ -568,7 +584,11 @@
                                  "'%s' object is not callable" % typename))
         return space.wrap(ClassMethod(w_function))
 
+class FunctionWithFixedCode(Function):
+    can_change_code = False
+
 class BuiltinFunction(Function):
+    can_change_code = False
 
     def __init__(self, func):
         assert isinstance(func, Function)

Modified: pypy/trunk/pypy/interpreter/gateway.py
==============================================================================
--- pypy/trunk/pypy/interpreter/gateway.py	(original)
+++ pypy/trunk/pypy/interpreter/gateway.py	Thu Oct 29 15:58:17 2009
@@ -16,6 +16,7 @@
 from pypy.interpreter.error import OperationError 
 from pypy.interpreter import eval
 from pypy.interpreter.function import Function, Method, ClassMethod
+from pypy.interpreter.function import FunctionWithFixedCode
 from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable
 from pypy.interpreter.baseobjspace import Wrappable, SpaceCache, DescrMismatch
 from pypy.interpreter.argument import Arguments, Signature
@@ -788,7 +789,7 @@
         space = cache.space
         defs = gateway._getdefaults(space) # needs to be implemented by subclass
         code = gateway._code
-        fn = Function(space, code, None, defs, forcename = gateway.name)
+        fn = FunctionWithFixedCode(space, code, None, defs, forcename = gateway.name)
         if not space.config.translating: # for tests and py.py
             fn._freeze_()
         if gateway.as_classmethod:

Modified: pypy/trunk/pypy/interpreter/test/test_function.py
==============================================================================
--- pypy/trunk/pypy/interpreter/test/test_function.py	(original)
+++ pypy/trunk/pypy/interpreter/test/test_function.py	Thu Oct 29 15:58:17 2009
@@ -84,6 +84,11 @@
             return f() # a closure
         raises(ValueError, "f.func_code = h.func_code")
 
+    def test_write_code_builtin_forbidden(self):
+        def f(*args):
+            return 42
+        raises(TypeError, "dir.func_code = f.func_code")
+        raises(TypeError, "list.append.im_func.func_code = f.func_code")
         
 
 class AppTestFunction: 

Modified: pypy/trunk/pypy/objspace/descroperation.py
==============================================================================
--- pypy/trunk/pypy/objspace/descroperation.py	(original)
+++ pypy/trunk/pypy/objspace/descroperation.py	Thu Oct 29 15:58:17 2009
@@ -90,9 +90,7 @@
     def get_and_call_function(space, w_descr, w_obj, *args_w):
         descr = space.interpclass_w(w_descr)
         # a special case for performance and to avoid infinite recursion
-        if type(descr) is Function:
-            # the fastcall paths are purely for performance, but the resulting
-            # increase of speed is huge
+        if isinstance(descr, Function):
             return descr.funccall(w_obj, *args_w)
         else:
             args = Arguments(space, list(args_w))



More information about the Pypy-commit mailing list