Commits

Alex Gaynor  committed b494ff6

(alex, with review from arigo and antocuni) Improve function defaults by showing the JIT that the memory they reside in is constant, evne if function.func_defaults isn't

  • Participants
  • Parent commits 143c77a

Comments (0)

Files changed (6)

File pypy/interpreter/function.py

     assert not func.can_change_code
     return func.code
 
+class Defaults(object):
+    _immutable_fields_ = ["items[*]"]
+
+    def __init__(self, items):
+        self.items = items
+
+    def getitems(self):
+        return jit.hint(self, promote=True).items
+
 class Function(Wrappable):
     """A function is a code object captured with some environment:
     an object space, a dictionary of globals, default arguments,
         self.code = code       # Code instance
         self.w_func_globals = w_globals  # the globals dictionary
         self.closure   = closure    # normally, list of Cell instances or None
-        self.defs_w    = defs_w     # list of w_default's
-        make_sure_not_resized(self.defs_w)
+        self.defs = Defaults(defs_w)     # wrapper around list of w_default's
         self.w_func_dict = None # filled out below if needed
         self.w_module = None
 
                 assert isinstance(code, gateway.BuiltinCode4)
                 return code.fastcall_4(self.space, self, args_w[0],
                                        args_w[1], args_w[2], args_w[3])
-        elif (nargs|PyCode.FLATPYCALL) == fast_natural_arity:
+        elif (nargs | PyCode.FLATPYCALL) == fast_natural_arity:
             assert isinstance(code, PyCode)
             if nargs < 5:
                 new_frame = self.space.createframe(code, self.w_func_globals,
                 return code.fastcall_4(self.space, self, frame.peekvalue(3),
                                        frame.peekvalue(2), frame.peekvalue(1),
                                         frame.peekvalue(0))
-        elif (nargs|Code.FLATPYCALL) == fast_natural_arity:
+        elif (nargs | Code.FLATPYCALL) == fast_natural_arity:
             assert isinstance(code, PyCode)
             return self._flat_pycall(code, nargs, frame)
-        elif fast_natural_arity&Code.FLATPYCALL:
-            natural_arity = fast_natural_arity&0xff
-            if natural_arity > nargs >= natural_arity-len(self.defs_w):
+        elif fast_natural_arity & Code.FLATPYCALL:
+            natural_arity = fast_natural_arity & 0xff
+            if natural_arity > nargs >= natural_arity - len(self.defs.getitems()):
                 assert isinstance(code, PyCode)
                 return self._flat_pycall_defaults(code, nargs, frame,
-                                                  natural_arity-nargs)
+                                                  natural_arity - nargs)
         elif fast_natural_arity == Code.PASSTHROUGHARGS1 and nargs >= 1:
             assert isinstance(code, gateway.BuiltinCodePassThroughArguments1)
             w_obj = frame.peekvalue(nargs-1)
             w_arg = frame.peekvalue(nargs-1-i)
             new_frame.fastlocals_w[i] = w_arg
 
-        defs_w = self.defs_w
+        defs_w = self.defs.getitems()
         ndefs = len(defs_w)
-        start = ndefs-defs_to_load
+        start = ndefs - defs_to_load
         i = nargs
         for j in xrange(start, ndefs):
             new_frame.fastlocals_w[i] = defs_w[j]
         return self.w_func_dict
 
     def setdict(self, space, w_dict):
-        if not space.is_true(space.isinstance( w_dict, space.w_dict )):
-            raise OperationError( space.w_TypeError, space.wrap("setting function's dictionary to a non-dict") )
+        if not space.isinstance_w(w_dict, space.w_dict):
+            raise OperationError(space.w_TypeError,
+                space.wrap("setting function's dictionary to a non-dict")
+            )
         self.w_func_dict = w_dict
 
     def descr_function__new__(space, w_subtype, w_code, w_globals,
             w(self.code),
             w_func_globals,
             w_closure,
-            nt(self.defs_w),
+            nt(self.defs.getitems()),
             w_func_dict,
             self.w_module,
         ]
         from pypy.interpreter.pycode import PyCode
         args_w = space.unpackiterable(w_args)
         try:
-            (w_name, w_doc, w_code, w_func_globals, w_closure, w_defs_w,
+            (w_name, w_doc, w_code, w_func_globals, w_closure, w_defs,
              w_func_dict, w_module) = args_w
         except ValueError:
             # wrong args
         if space.is_w(w_func_dict, space.w_None):
             w_func_dict = None
         self.w_func_dict = w_func_dict
-        self.defs_w    = space.fixedview(w_defs_w)
+        self.defs = Defaults(space.fixedview(w_defs))
         self.w_module = w_module
 
     def fget_func_defaults(self, space):
-        values_w = self.defs_w
+        values_w = self.defs.getitems()
+        # the `None in values_w` check here is to ensure that interp-level
+        # functions with a default of NoneNotWrapped do not get their defaults
+        # exposed at applevel
         if not values_w or None in values_w:
             return space.w_None
         return space.newtuple(values_w)
 
     def fset_func_defaults(self, space, w_defaults):
         if space.is_w(w_defaults, space.w_None):
-            self.defs_w = []
+            self.defs = Defaults([])
             return
         if not space.is_true(space.isinstance(w_defaults, space.w_tuple)):
             raise OperationError( space.w_TypeError, space.wrap("func_defaults must be set to a tuple object or None") )
-        self.defs_w = space.fixedview(w_defaults)
+        self.defs = Defaults(space.fixedview(w_defaults))
 
     def fdel_func_defaults(self, space):
-        self.defs_w = []
+        self.defs = Defaults([])
 
     def fget_func_doc(self, space):
         if self.w_doc is None:
     def fget___module__(self, space):
         if self.w_module is None:
             if self.w_func_globals is not None and not space.is_w(self.w_func_globals, space.w_None):
-                self.w_module = space.call_method( self.w_func_globals, "get", space.wrap("__name__") )
+                self.w_module = space.call_method(self.w_func_globals, "get", space.wrap("__name__"))
             else:
                 self.w_module = space.w_None
         return self.w_module
     def __init__(self, func):
         assert isinstance(func, Function)
         Function.__init__(self, func.space, func.code, func.w_func_globals,
-                          func.defs_w, func.closure, func.name)
+                          func.defs.getitems(), func.closure, func.name)
         self.w_doc = func.w_doc
         self.w_func_dict = func.w_func_dict
         self.w_module = func.w_module

File pypy/interpreter/gateway.py

 NoneNotWrapped = object()
 
 from pypy.tool.sourcetools import func_with_new_name
-from pypy.interpreter.error import OperationError 
+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.rlib import rstackovf
 from pypy.rlib.objectmodel import we_are_translated
 
-# internal non-translatable parts: 
+# internal non-translatable parts:
 import py
 
 class SignatureBuilder(object):
         dispatch = self.dispatch
         for el in unwrap_spec:
             dispatch(el, *extra)
-            
+
 class UnwrapSpecEmit(UnwrapSpecRecipe):
 
     def __init__(self):
         self.n = 0
         self.miniglobals = {}
-        
+
     def succ(self):
         n = self.n
         self.n += 1
         name = obj.__name__
         self.miniglobals[name] = obj
         return name
-    
+
 #________________________________________________________________
 
 class UnwrapSpec_Check(UnwrapSpecRecipe):
             "unwrapped %s argument %s of built-in function %r should "
             "not start with 'w_'" % (name, argname, self.func))
         app_sig.append(argname)
-        
+
     def visit__ObjSpace(self, el, app_sig):
         self.orig_arg()
 
             (argname, self.func))
         assert app_sig.varargname is None,(
             "built-in function %r has conflicting rest args specs" % self.func)
-        app_sig.varargname = argname[:-2]    
+        app_sig.varargname = argname[:-2]
 
     def visit_w_args(self, el, app_sig):
         argname = self.orig_arg()
 
     def scopenext(self):
         return "scope_w[%d]" % self.succ()
-    
+
     def visit_function(self, (func, cls)):
         self.run_args.append("%s(%s)" % (self.use(func),
                                          self.scopenext()))
     def visit_self(self, typ):
         self.run_args.append("space.descr_self_interp_w(%s, %s)" %
                              (self.use(typ), self.scopenext()))
-        
+
     def visit__Wrappable(self, typ):
         self.run_args.append("space.interp_w(%s, %s)" % (self.use(typ),
                                                          self.scopenext()))
                 "unexpected: same spec, different run_args")
             return activation_factory_cls
         except KeyError:
-            parts = []          
+            parts = []
             for el in unwrap_spec:
                 if isinstance(el, tuple):
                     parts.append(''.join([getattr(subel, '__name__', subel)
             #print label
 
             d = {}
-            source = """if 1: 
+            source = """if 1:
                 def _run(self, space, scope_w):
                     return self.behavior(%s)
                 \n""" % (', '.join(self.run_args),)
         self.finger += 1
         if self.n > 4:
             raise FastFuncNotSupported
-        
+
     def nextarg(self):
         arg = "w%d" % self.succ()
         self.args.append(arg)
                     raise FastFuncNotSupported
             d = {}
             unwrap_info.miniglobals['func'] = func
-            source = """if 1: 
+            source = """if 1:
                 def fastfunc_%s_%d(%s):
                     return func(%s)
                 \n""" % (func.__name__, narg,
         # 'w_args' for rest arguments passed as wrapped tuple
         # str,int,float: unwrap argument as such type
         # (function, cls) use function to check/unwrap argument of type cls
-        
+
         # First extract the signature from the (CPython-level) code object
         from pypy.interpreter import pycode
         argnames, varargname, kwargname = pycode.cpython_code_signature(func.func_code)
         else:
             assert descrmismatch is None, (
                 "descrmismatch without a self-type specified")
- 
+
 
         orig_sig = SignatureBuilder(func, argnames, varargname, kwargname)
         app_sig = SignatureBuilder(func)
         space = func.space
         activation = self.activation
         scope_w = args.parse_obj(w_obj, func.name, self.sig,
-                                 func.defs_w, self.minargs)
+                                 func.defs.getitems(), self.minargs)
         try:
             w_result = activation._run(space, scope_w)
         except DescrMismatch:
             if not we_are_translated():
                 raise
             raise e
-        except KeyboardInterrupt: 
+        except KeyboardInterrupt:
             raise OperationError(space.w_KeyboardInterrupt,
-                                 space.w_None) 
-        except MemoryError: 
+                                 space.w_None)
+        except MemoryError:
             raise OperationError(space.w_MemoryError, space.w_None)
         except rstackovf.StackOverflow, e:
             rstackovf.check_stack_overflow()
 class BuiltinCode0(BuiltinCode):
     _immutable_ = True
     fast_natural_arity = 0
-    
+
     def fastcall_0(self, space, w_func):
         try:
             w_result = self.fastfunc_0(space)
 class BuiltinCode1(BuiltinCode):
     _immutable_ = True
     fast_natural_arity = 1
-    
+
     def fastcall_1(self, space, w_func, w1):
         try:
             w_result = self.fastfunc_1(space, w1)
 class BuiltinCode2(BuiltinCode):
     _immutable_ = True
     fast_natural_arity = 2
-    
+
     def fastcall_2(self, space, w_func, w1, w2):
         try:
             w_result = self.fastfunc_2(space, w1, w2)
 class BuiltinCode3(BuiltinCode):
     _immutable_ = True
     fast_natural_arity = 3
-    
+
     def fastcall_3(self, space, func, w1, w2, w3):
         try:
             w_result = self.fastfunc_3(space, w1, w2, w3)
 class BuiltinCode4(BuiltinCode):
     _immutable_ = True
     fast_natural_arity = 4
-    
+
     def fastcall_4(self, space, func, w1, w2, w3, w4):
         try:
             w_result = self.fastfunc_4(space, w1, w2, w3, w4)
     NOT_RPYTHON_ATTRIBUTES = ['_staticdefs']
 
     instancecache = {}
-    
+
     def __new__(cls, f, app_name=None, unwrap_spec = None,
                 descrmismatch=None, as_classmethod=False):
 
         return fn
 
 
-# 
-# the next gateways are to be used only for 
-# temporary/initialization purposes 
-     
-class interp2app_temp(interp2app): 
+#
+# the next gateways are to be used only for
+# temporary/initialization purposes
+
+class interp2app_temp(interp2app):
     "NOT_RPYTHON"
-    def getcache(self, space): 
+    def getcache(self, space):
         return self.__dict__.setdefault(space, GatewayCache(space))
 
 
-# and now for something completely different ... 
+# and now for something completely different ...
 #
 
 class ApplevelClass:
         from pypy.interpreter.module import Module
         return Module(space, space.wrap(name), self.getwdict(space))
 
-    def wget(self, space, name): 
-        w_globals = self.getwdict(space) 
+    def wget(self, space, name):
+        w_globals = self.getwdict(space)
         return space.getitem(w_globals, space.wrap(name))
 
     def interphook(self, name):
         "NOT_RPYTHON"
         def appcaller(space, *args_w):
-            if not isinstance(space, ObjSpace): 
+            if not isinstance(space, ObjSpace):
                 raise TypeError("first argument must be a space instance.")
             # redirect if the space handles this specially
             # XXX can this be factored a bit less flow space dependently?
                                                       args.arguments_w)
             return space.call_args(w_func, args)
         def get_function(space):
-            w_func = self.wget(space, name) 
+            w_func = self.wget(space, name)
             return space.unwrap(w_func)
         appcaller = func_with_new_name(appcaller, name)
         appcaller.get_function = get_function
     myfunc = appdef('''myfunc(x, y):
                            return x+y
                     ''')
-    """ 
-    if not isinstance(source, str): 
+    """
+    if not isinstance(source, str):
         source = py.std.inspect.getsource(source).lstrip()
         while source.startswith('@py.test.mark.'):
             # these decorators are known to return the same function
             # object, we may ignore them
             assert '\n' in source
             source = source[source.find('\n') + 1:].lstrip()
-        assert source.startswith("def "), "can only transform functions" 
+        assert source.startswith("def "), "can only transform functions"
         source = source[4:]
     p = source.find('(')
     assert p >= 0

File pypy/interpreter/pycode.py

         self._init_flags()
         # Precompute what arguments need to be copied into cellvars
         self._args_as_cellvars = []
-        
+
         if self.co_cellvars:
             argcount = self.co_argcount
             assert argcount >= 0     # annotator hint
 
     def signature(self):
         return self._signature
-    
+
     @classmethod
     def _from_code(cls, space, code, hidden_applevel=False, code_hook=None):
         """ Initialize the code object from a real (CPython) one.
                       list(code.co_cellvars),
                       hidden_applevel, cpython_magic)
 
-    
+
     def _compute_flatcall(self):
         # Speed hack!
         self.fast_natural_arity = eval.Code.HOPELESS
             return
         if self.co_argcount > 0xff:
             return
-        
+
         self.fast_natural_arity = eval.Code.FLATPYCALL | self.co_argcount
 
     def funcrun(self, func, args):
                                       fresh_virtualizable=True)
         args_matched = args.parse_into_scope(None, fresh_frame.fastlocals_w,
                                              func.name,
-                                             sig, func.defs_w)
+                                             sig, func.defs.getitems())
         fresh_frame.init_cells()
         return frame.run()
 
         sig = self._signature
         # speed hack
         fresh_frame = jit.hint(frame, access_directly=True,
-                                      fresh_virtualizable=True)        
+                                      fresh_virtualizable=True)
         args_matched = args.parse_into_scope(w_obj, fresh_frame.fastlocals_w,
                                              func.name,
-                                             sig, func.defs_w)
+                                             sig, func.defs.getitems())
         fresh_frame.init_cells()
         return frame.run()
 
 
     def fget_co_consts(self, space):
         return space.newtuple(self.co_consts_w)
-    
+
     def fget_co_names(self, space):
         return space.newtuple(self.co_names_w)
 
         return space.newtuple([space.wrap(name) for name in self.co_cellvars])
 
     def fget_co_freevars(self, space):
-        return space.newtuple([space.wrap(name) for name in self.co_freevars])    
+        return space.newtuple([space.wrap(name) for name in self.co_freevars])
 
     def descr_code__eq__(self, w_other):
         space = self.space
         new_inst = mod.get('code_new')
         w        = space.wrap
         tup      = [
-            w(self.co_argcount), 
-            w(self.co_nlocals), 
-            w(self.co_stacksize), 
+            w(self.co_argcount),
+            w(self.co_nlocals),
+            w(self.co_stacksize),
             w(self.co_flags),
-            w(self.co_code), 
-            space.newtuple(self.co_consts_w), 
-            space.newtuple(self.co_names_w), 
-            space.newtuple([w(v) for v in self.co_varnames]), 
+            w(self.co_code),
+            space.newtuple(self.co_consts_w),
+            space.newtuple(self.co_names_w),
+            space.newtuple([w(v) for v in self.co_varnames]),
             w(self.co_filename),
-            w(self.co_name), 
+            w(self.co_name),
             w(self.co_firstlineno),
-            w(self.co_lnotab), 
+            w(self.co_lnotab),
             space.newtuple([w(v) for v in self.co_freevars]),
             space.newtuple([w(v) for v in self.co_cellvars]),
             w(self.magic),

File pypy/interpreter/test/test_gateway.py

 # -*- coding: utf-8 -*-
 
 from pypy.conftest import gettestobjspace
-from pypy.interpreter import gateway
+from pypy.interpreter import gateway, argument
 from pypy.interpreter.gateway import ObjSpace, W_Root
-from pypy.interpreter import argument
+from pypy.interpreter.function import Defaults
 import py
 import sys
 
 class FakeFunc(object):
-
     def __init__(self, space, name):
         self.space = space
         self.name = name
-        self.defs_w = []
+        self.defs = Defaults([])
 
-class TestBuiltinCode: 
+class TestBuiltinCode:
     def test_signature(self):
         def c(space, w_x, w_y, hello_w):
             pass
         w_result = code.funcrun(FakeFunc(self.space, "c"), args)
         assert self.space.eq_w(w_result, w(1020))
 
-class TestGateway: 
+class TestGateway:
 
     def test_app2interp(self):
         w = self.space.wrap
             return a+b
         g3 = gateway.app2interp_temp(noapp_g3, gateway.applevel_temp)
         assert self.space.eq_w(g3(self.space, w('foo'), w('bar')), w('foobar'))
-        
+
     def test_app2interp2(self):
         """same but using transformed code"""
         w = self.space.wrap
         def g3(space, w_a, w_b):
             return space.add(w_a, w_b)
         app_g3 = gateway.interp2app_temp(g3)
-        w_app_g3 = space.wrap(app_g3) 
+        w_app_g3 = space.wrap(app_g3)
         assert self.space.eq_w(
-            space.call(w_app_g3, 
+            space.call(w_app_g3,
                        space.newtuple([w('foo'), w('bar')]),
                        space.newdict()),
             w('foobar'))
         assert self.space.eq_w(
             space.call_function(w_app_g3, w('foo'), w('bar')),
             w('foobar'))
-        
+
     def test_interp2app_unwrap_spec(self):
         space = self.space
         w = space.wrap
         def g3(space, w_a, w_b):
-            return space.add(w_a, w_b)        
+            return space.add(w_a, w_b)
         app_g3 = gateway.interp2app_temp(g3,
                                          unwrap_spec=[gateway.ObjSpace,
                                                       gateway.W_Root,
                                                       gateway.W_Root])
-        w_app_g3 = space.wrap(app_g3) 
+        w_app_g3 = space.wrap(app_g3)
         assert self.space.eq_w(
-            space.call(w_app_g3, 
+            space.call(w_app_g3,
                        space.newtuple([w('foo'), w('bar')]),
                        space.newdict()),
             w('foobar'))
         app_A = gateway.interp2app(A.f)
         app_B = gateway.interp2app(B.f)
         assert app_A is not app_B
-        
+
     def test_interp2app_unwrap_spec_nonnegint(self):
         space = self.space
         w = space.wrap
         space = self.space
         w = space.wrap
         def g3_args_w(space, args_w):
-            return space.add(args_w[0], args_w[1])        
+            return space.add(args_w[0], args_w[1])
         app_g3_args_w = gateway.interp2app_temp(g3_args_w,
                                          unwrap_spec=[gateway.ObjSpace,
                                                       'args_w'])
-        w_app_g3_args_w = space.wrap(app_g3_args_w) 
+        w_app_g3_args_w = space.wrap(app_g3_args_w)
         assert self.space.eq_w(
-            space.call(w_app_g3_args_w, 
+            space.call(w_app_g3_args_w,
                        space.newtuple([w('foo'), w('bar')]),
                        space.newdict()),
             w('foobar'))
         def g3_ss(space, s0, s1):
             if s1 is None:
                 return space.wrap(42)
-            return space.wrap(s0+s1)       
+            return space.wrap(s0+s1)
         app_g3_ss = gateway.interp2app_temp(g3_ss,
                                          unwrap_spec=[gateway.ObjSpace,
                                                       str, 'str_or_None'])
-        w_app_g3_ss = space.wrap(app_g3_ss) 
+        w_app_g3_ss = space.wrap(app_g3_ss)
         assert self.space.eq_w(
-            space.call(w_app_g3_ss, 
+            space.call(w_app_g3_ss,
                        space.newtuple([w('foo'), w('bar')]),
                        space.newdict()),
             w('foobar'))
         space = self.space
         w = space.wrap
         def g3_if(space, i0, f1):
-            return space.wrap(i0+f1)       
+            return space.wrap(i0+f1)
         app_g3_if = gateway.interp2app_temp(g3_if,
                                          unwrap_spec=[gateway.ObjSpace,
                                                       int,float])
-        w_app_g3_if = space.wrap(app_g3_if) 
+        w_app_g3_if = space.wrap(app_g3_if)
         assert self.space.eq_w(
-            space.call(w_app_g3_if, 
+            space.call(w_app_g3_if,
                        space.newtuple([w(1), w(1.0)]),
                        space.newdict()),
             w(2.0))
         w_app_g3_ll = space.wrap(app_g3_ll)
         w_big = w(gateway.r_longlong(10**10))
         assert space.eq_w(
-            space.call(w_app_g3_ll, 
+            space.call(w_app_g3_ll,
                        space.newtuple([w_big]),
                        space.newdict()),
             w(gateway.r_longlong(3 * 10**10)))
         app_g3_idx = gateway.interp2app_temp(g3_idx,
                                          unwrap_spec=[gateway.ObjSpace,
                                                       'index'])
-        w_app_g3_idx = space.wrap(app_g3_idx) 
+        w_app_g3_idx = space.wrap(app_g3_idx)
         assert space.eq_w(
             space.call_function(w_app_g3_idx, w(123)),
             w(124))
                                                       int])
         w_app_g3_i = space.wrap(app_g3_i)
         assert space.eq_w(space.call_function(w_app_g3_i,w(1)),w(1))
-        assert space.eq_w(space.call_function(w_app_g3_i,w(1L)),w(1))        
+        assert space.eq_w(space.call_function(w_app_g3_i,w(1L)),w(1))
         raises(gateway.OperationError,space.call_function,w_app_g3_i,w(sys.maxint*2))
         raises(gateway.OperationError,space.call_function,w_app_g3_i,w(None))
         raises(gateway.OperationError,space.call_function,w_app_g3_i,w("foo"))
         raises(gateway.OperationError,space.call_function,w_app_g3_s,w(None))
         raises(gateway.OperationError,space.call_function,w_app_g3_s,w(1))
         raises(gateway.OperationError,space.call_function,w_app_g3_s,w(1.0))
-        
+
         app_g3_f = gateway.interp2app_temp(g3_id,
                                          unwrap_spec=[gateway.ObjSpace,
                                                       float])
         w_app_g3_f = space.wrap(app_g3_f)
         assert space.eq_w(space.call_function(w_app_g3_f,w(1.0)),w(1.0))
         assert space.eq_w(space.call_function(w_app_g3_f,w(1)),w(1.0))
-        assert space.eq_w(space.call_function(w_app_g3_f,w(1L)),w(1.0))        
+        assert space.eq_w(space.call_function(w_app_g3_f,w(1L)),w(1.0))
         raises(gateway.OperationError,space.call_function,w_app_g3_f,w(None))
         raises(gateway.OperationError,space.call_function,w_app_g3_f,w("foo"))
 
             called.append(w_func)
             return fastcall_2(space, w_func, w_a, w_b)
 
-        w_app_f.code.fastcall_2 = witness_fastcall_2    
-    
+        w_app_f.code.fastcall_2 = witness_fastcall_2
+
         w_res = space.appexec([w_app_f, w_3], """(f, x):
         class A(object):
            m = f # not a builtin function, so works as method
         """)
 
         assert space.is_true(w_res)
-        assert called == [w_app_f, w_app_f]       
-        
+        assert called == [w_app_f, w_app_f]
+
     def test_plain(self):
         space = self.space
 
 
         w_res = space.call_args(w_g, args)
         assert space.is_true(space.eq(w_res, space.wrap(('g', -1, 0))))
-        
+
         w_self = space.wrap('self')
 
         args0 = argument.Arguments(space, [space.wrap(0)])
 
 
 class TestPassThroughArguments:
-    
+
     def test_pass_trough_arguments0(self):
         space = self.space
 
         called = []
-        
+
         def f(space, __args__):
             called.append(__args__)
             a_w, _ = __args__.unpack()
 
         w_res = space.call_args(w_f, args)
         assert space.is_true(space.eq(w_res, space.wrap(('f', 7))))
-        
+
         # white-box check for opt
         assert called[0] is args
 
         space = self.space
 
         called = []
-        
+
         def g(space, w_self, __args__):
             called.append(__args__)
             a_w, _ = __args__.unpack()
         w_res = space.call_args(w_g, args)
         assert space.is_true(space.eq(w_res, space.wrap(('g', 'self', 0))))
         # no opt in this case
-        assert len(called) == 2      
+        assert len(called) == 2
         assert called[0] == 'funcrun'
         called = []
 
         w_res = space.call_function(w_g, w_self)
         assert space.is_true(space.eq(w_res, space.wrap(('g', 'self'))))
         assert len(called) == 1
-        assert isinstance(called[0], argument.Arguments)        
+        assert isinstance(called[0], argument.Arguments)
         called = []
-        
+
         w_res = space.appexec([w_g], """(g):
         return g('self', 11)
         """)
         assert space.is_true(space.eq(w_res, space.wrap(('g', 'self', 11))))
         assert len(called) == 1
-        assert isinstance(called[0], argument.Arguments)                
+        assert isinstance(called[0], argument.Arguments)
         called = []
 
         w_res = space.appexec([w_g], """(g):
         clash = dict.__new__.func_code.co_varnames[0]
 
         dict(**{clash: 33})
-        dict.__new__(dict, **{clash: 33})        
+        dict.__new__(dict, **{clash: 33})
 
     def test_dict_init(self):
         d = {}
         clash = dict.update.func_code.co_varnames[0]
 
         d.update(**{clash: 33})
-        dict.update(d, **{clash: 33})        
-        
+        dict.update(d, **{clash: 33})
+

File pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py

         where x and y can be either constants or variables. There are cases in
         which the second guard is proven to be always true.
         """
-        
+
         for a, b, res, opt_expected in (('2000', '2000', 20001000, True),
                                         ( '500',  '500', 15001500, True),
                                         ( '300',  '600', 16001700, False),
         test only checks that we get the expected result, not that any
         optimization has been applied.
         """
-        ops = ('<', '>', '<=', '>=', '==', '!=')        
+        ops = ('<', '>', '<=', '>=', '==', '!=')
         for op1 in ops:
             for op2 in ops:
                 for a,b in ((500, 500), (300, 600)):
         test only checks that we get the expected result, not that any
         optimization has been applied.
         """
-        ops = ('<', '>', '<=', '>=', '==', '!=')        
+        ops = ('<', '>', '<=', '>=', '==', '!=')
         for op1 in ops:
             for op2 in ops:
                 for a,b in ((500, 500), (300, 600)):
             --TICK--
             jump(p0, p1, p2, p3, p4, p5, p6, p7, i28, i15, i10, i11, descr=<Loop0>)
         """)
+
+    def test_func_defaults(self):
+        def main(n):
+            i = 1
+            while i < n:
+                i += len(xrange(i)) / i
+            return i
+
+        log = self.run(main, [10000])
+        assert log.result == 10000
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+            i10 = int_lt(i5, i6)
+            guard_true(i10, descr=<Guard3>)
+            # This can be improved if the JIT realized the lookup of i5 produces
+            # a constant and thus can be removed entirely
+            i12 = int_sub(i5, 1)
+            i13 = uint_floordiv(i12, i7)
+            i15 = int_add(i13, 1)
+            i17 = int_lt(i15, 0)
+            guard_false(i17, descr=<Guard4>)
+            i18 = int_floordiv(i15, i5)
+            i19 = int_xor(i15, i5)
+            i20 = int_mod(i15, i5)
+            i21 = int_is_true(i20)
+            i22 = int_add_ovf(i5, i18)
+            guard_no_overflow(descr=<Guard5>)
+            --TICK--
+            jump(p0, p1, p2, p3, p4, i22, i6, i7, p8, p9, descr=<Loop0>)
+        """)

File pypy/objspace/std/fake.py

         frame = func.space.createframe(self, func.w_func_globals,
                                         func.closure)
         sig = self.signature()
-        scope_w = args.parse_obj(None, func.name, sig, func.defs_w)
+        scope_w = args.parse_obj(None, func.name, sig, func.defs.getitems())
         frame.setfastscope(scope_w)
         return frame.run()
-    
+
 
 class CPythonFakeFrame(eval.Frame):