[pypy-svn] r57183 - in pypy/dist/pypy: interpreter interpreter/callbench interpreter/test module/__builtin__/test module/_stackless/test module/operator module/pypyjit module/thread objspace objspace/std

pedronis at codespeak.net pedronis at codespeak.net
Sun Aug 10 23:55:52 CEST 2008


Author: pedronis
Date: Sun Aug 10 23:55:49 2008
New Revision: 57183

Added:
   pypy/dist/pypy/interpreter/callbench/bltn_instantiate.py
      - copied unchanged from r57182, pypy/branch/garden-call-code/pypy/interpreter/callbench/bltn_instantiate.py
   pypy/dist/pypy/interpreter/callbench/bltna1.py
      - copied unchanged from r57182, pypy/branch/garden-call-code/pypy/interpreter/callbench/bltna1.py
   pypy/dist/pypy/interpreter/callbench/bltna2.py
      - copied unchanged from r57182, pypy/branch/garden-call-code/pypy/interpreter/callbench/bltna2.py
   pypy/dist/pypy/interpreter/callbench/inst_no_init.py
      - copied unchanged from r57182, pypy/branch/garden-call-code/pypy/interpreter/callbench/inst_no_init.py
   pypy/dist/pypy/module/_stackless/test/test_frame_chain_reconstruction.py
      - copied unchanged from r57182, pypy/branch/garden-call-code/pypy/module/_stackless/test/test_frame_chain_reconstruction.py
Modified:
   pypy/dist/pypy/interpreter/argument.py
   pypy/dist/pypy/interpreter/baseobjspace.py
   pypy/dist/pypy/interpreter/callbench/inst.py
   pypy/dist/pypy/interpreter/callbench/sup.py
   pypy/dist/pypy/interpreter/eval.py
   pypy/dist/pypy/interpreter/function.py
   pypy/dist/pypy/interpreter/gateway.py
   pypy/dist/pypy/interpreter/pycode.py
   pypy/dist/pypy/interpreter/test/test_function.py
   pypy/dist/pypy/interpreter/test/test_gateway.py
   pypy/dist/pypy/interpreter/test/test_objspace.py
   pypy/dist/pypy/module/__builtin__/test/test_builtin.py
   pypy/dist/pypy/module/operator/__init__.py
   pypy/dist/pypy/module/operator/app_operator.py
   pypy/dist/pypy/module/operator/interp_operator.py
   pypy/dist/pypy/module/pypyjit/portal.py
   pypy/dist/pypy/module/thread/os_local.py
   pypy/dist/pypy/objspace/descroperation.py
   pypy/dist/pypy/objspace/std/objspace.py
   pypy/dist/pypy/objspace/std/proxyobject.py
   pypy/dist/pypy/objspace/std/typeobject.py
Log:

merging first garden-call-code branch

- avoid the strange interface checking whether the result is None for fastcall_# methods
- killed Arguments.popfirst and ArgumentsPrepended introducing call_obj_args and related methods instead
- kill Function.funccall_obj_valuestack
- prune funccall_star# versions
- move itemgetter and attrgetter back to app-level for simplicity for now

- various new tests



Modified: pypy/dist/pypy/interpreter/argument.py
==============================================================================
--- pypy/dist/pypy/interpreter/argument.py	(original)
+++ pypy/dist/pypy/interpreter/argument.py	Sun Aug 10 23:55:49 2008
@@ -6,32 +6,62 @@
 
 class AbstractArguments:
 
-    def parse(self, fnname, signature, defaults_w=[]):
+    def parse_into_scope(self, w_firstarg,
+                         scope_w, fnname, signature, defaults_w=[]):
         """Parse args and kwargs to initialize a frame
         according to the signature of code object.
+        Store the argumentvalues into scope_w.
+        scope_w must be big enough for signature.
         """
+        argnames, varargname, kwargname = signature
+        has_vararg = varargname is not None
+        has_kwarg = kwargname is not None
         try:
-            return self.match_signature(signature, defaults_w)
+            return self._match_signature(w_firstarg,
+                                         scope_w, argnames, has_vararg,
+                                         has_kwarg, defaults_w, 0)
         except ArgErr, e:
             raise OperationError(self.space.w_TypeError,
                                  self.space.wrap(e.getmsg(fnname)))
 
-    def parse_into_scope(self, scope_w, fnname, signature, defaults_w=[]):
-        """Parse args and kwargs to initialize a frame
-        according to the signature of code object.
-        Store the argumentvalues into scope_w.
-        scope_w must be big enough for signature.
+    def _parse(self, w_firstarg, signature, defaults_w, blindargs=0):
+        """Parse args and kwargs according to the signature of a code object,
+        or raise an ArgErr in case of failure.
         """
         argnames, varargname, kwargname = signature
+        scopelen = len(argnames)
         has_vararg = varargname is not None
         has_kwarg = kwargname is not None
+        if has_vararg:
+            scopelen += 1
+        if has_kwarg:
+            scopelen += 1
+        scope_w = [None] * scopelen
+        self._match_signature(w_firstarg, scope_w, argnames, has_vararg, has_kwarg, defaults_w, blindargs)
+        return scope_w    
+
+    def parse(self, fnname, signature, defaults_w=[], blindargs=0):
+        """Parse args and kwargs to initialize a frame
+        according to the signature of code object.
+        """
         try:
-            return self._match_signature(scope_w, argnames, has_vararg,
-                                         has_kwarg, defaults_w, 0, None)
+            return self._parse(None, signature, defaults_w, blindargs)
         except ArgErr, e:
             raise OperationError(self.space.w_TypeError,
                                  self.space.wrap(e.getmsg(fnname)))
 
+    # xxx have only this one
+    def parse_obj(self, w_firstarg,
+                  fnname, signature, defaults_w=[], blindargs=0):
+        """Parse args and kwargs to initialize a frame
+        according to the signature of code object.
+        """
+        try:
+            return self._parse(w_firstarg, signature, defaults_w, blindargs)
+        except ArgErr, e:
+            raise OperationError(self.space.w_TypeError,
+                                 self.space.wrap(e.getmsg(fnname)))        
+
     def frompacked(space, w_args=None, w_kwds=None):
         """Convenience static method to build an Arguments
            from a wrapped sequence and a wrapped dictionary."""
@@ -68,31 +98,11 @@
         return Arguments(space, args_w, kwds_w, w_star, w_starstar)
     fromshape = staticmethod(fromshape)
 
-    def prepend(self, w_firstarg):
-        "Return a new Arguments with a new argument inserted first."
-        return ArgumentsPrepended(self, w_firstarg)
-
-    def popfirst(self):
-        """For optimization only: might return (w_firstarg, args_with_rest),
-        or might just raise IndexError.
-        """
-        raise IndexError
-
     def match_signature(self, signature, defaults_w):
         """Parse args and kwargs according to the signature of a code object,
         or raise an ArgErr in case of failure.
         """
-        argnames, varargname, kwargname = signature
-        scopelen = len(argnames)
-        has_vararg = varargname is not None
-        has_kwarg = kwargname is not None
-        if  has_vararg:
-            scopelen += 1
-        if has_kwarg:
-            scopelen += 1
-        scope_w = [None] * scopelen
-        self._match_signature(scope_w, argnames, has_vararg, has_kwarg, defaults_w, 0, None)
-        return scope_w
+        return self._parse(None, signature, defaults_w)
 
     def unmatch_signature(self, signature, data_w):
         """kind of inverse of match_signature"""
@@ -156,7 +166,12 @@
         """
         raise NotImplementedError()
 
-    def _match_signature(self, scope_w, argnames, has_vararg=False, has_kwarg=False, defaults_w=[], blindargs=0, extravarargs=None):
+    def prepend(self, w_firstarg):
+        """ Purely abstract
+        """
+        raise NotImplementedError()    
+
+    def _match_signature(self, w_firstarg, scope_w, argnames, has_vararg=False, has_kwarg=False, defaults_w=[], blindargs=0):
         """ Purely abstract
         """
         raise NotImplementedError()
@@ -164,66 +179,9 @@
     def fixedunpack(self, argcount):
         """ Purely abstract
         """
-        raise NotImplementedError()        
-
-class ArgumentsPrepended(AbstractArguments):
-    def __init__(self, args, w_firstarg):
-        self.space = args.space
-        self.args = args
-        self.w_firstarg = w_firstarg
-        
-    def firstarg(self):
-        "Return the first argument for inspection."
-        return self.w_firstarg
-
-    def popfirst(self):
-        return self.w_firstarg, self.args
-
-    def __repr__(self):
-        return 'ArgumentsPrepended(%r, %r)' % (self.args, self.w_firstarg)
-
-    def has_keywords(self):
-        return self.args.has_keywords()
-
-    def unpack(self):
-        arguments_w, kwds_w = self.args.unpack()
-        return ([self.w_firstarg] + arguments_w), kwds_w
-
-    def fixedunpack(self, argcount):
-        if argcount <= 0:
-            raise ValueError, "too many arguments (%d expected)" % argcount # XXX: Incorrect
-        return [self.w_firstarg] + self.args.fixedunpack(argcount - 1)
-        
-    def _rawshape(self, nextra=0):
-        return self.args._rawshape(nextra + 1)
-
-    def _match_signature(self, scope_w, argnames, has_vararg=False, has_kwarg=False, defaults_w=[], blindargs=0, extravarargs=None):
-        """Parse args and kwargs according to the signature of a code object,
-        or raise an ArgErr in case of failure.
-        Return the number of arguments filled in.
-        """
-        if blindargs < len(argnames):
-            scope_w[blindargs] = self.w_firstarg
-        else:
-            if extravarargs is None:
-                extravarargs = [ self.w_firstarg ]
-            else:
-                extravarargs.append(self.w_firstarg)
-        return self.args._match_signature(scope_w, argnames, has_vararg,
-                                          has_kwarg, defaults_w,
-                                          blindargs + 1, extravarargs)
-    
-    def flatten(self):
-        (shape_cnt, shape_keys, shape_star, shape_stst), data_w = self.args.flatten()
-        data_w.insert(0, self.w_firstarg)
-        return (shape_cnt + 1, shape_keys, shape_star, shape_stst), data_w
+        raise NotImplementedError()
 
-    def num_args(self):
-        return self.args.num_args() + 1
 
-    def num_kwds(self):
-        return self.args.num_kwds()
-    
 class ArgumentsFromValuestack(AbstractArguments):
     """
     Collects the arguments of a function call as stored on a PyFrame
@@ -242,14 +200,11 @@
             return None
         return self.frame.peekvalue(self.nargs - 1)
 
-    def popfirst(self):
-        if self.nargs <= 0:
-            raise IndexError
-        frame = self.frame
-        newnargs = self.nargs-1
-        return (frame.peekvalue(newnargs),
-                ArgumentsFromValuestack(self.space, frame, newnargs))
-
+    def prepend(self, w_firstarg):
+        "Return a new Arguments with a new argument inserted first."
+        args_w = self.frame.peekvalues(self.nargs)
+        return Arguments(self.space, [w_firstarg] + args_w)
+        
     def __repr__(self):
         return 'ArgumentsFromValuestack(%r, %r)' % (self.frame, self.nargs)
 
@@ -276,52 +231,65 @@
     def _rawshape(self, nextra=0):
         return nextra + self.nargs, (), False, False
 
-    def _match_signature(self, scope_w, argnames, has_vararg=False, has_kwarg=False, defaults_w=[], blindargs=0, extravarargs=None):
+    def _match_signature(self, w_firstarg, scope_w, argnames, has_vararg=False, has_kwarg=False, defaults_w=[], blindargs=0):
         """Parse args and kwargs according to the signature of a code object,
         or raise an ArgErr in case of failure.
         Return the number of arguments filled in.
         """
         co_argcount = len(argnames)
-        if blindargs + self.nargs + len(defaults_w) < co_argcount:
+        extravarargs = None
+        input_argcount =  0
+
+        if w_firstarg is not None:
+            upfront = 1
+            if co_argcount > 0:
+                scope_w[0] = w_firstarg
+                input_argcount = 1
+            else:
+                extravarargs = [ w_firstarg ]
+        else:
+            upfront = 0
+
+        avail = upfront + self.nargs
+        
+        if avail + len(defaults_w) < co_argcount:
             raise ArgErrCount(blindargs + self.nargs , 0,
                               (co_argcount, has_vararg, has_kwarg),
-                              defaults_w, co_argcount - blindargs -
-                              self.nargs - len(defaults_w))
-        if blindargs + self.nargs > co_argcount and not has_vararg:
+                              defaults_w, co_argcount - avail - len(defaults_w))
+        if avail > co_argcount and not has_vararg:
             raise ArgErrCount(blindargs + self.nargs, 0,
                               (co_argcount, has_vararg, has_kwarg),
                               defaults_w, 0)
 
-        if blindargs + self.nargs >= co_argcount:
-            for i in range(co_argcount - blindargs):
-                scope_w[i + blindargs] = self.frame.peekvalue(self.nargs - 1 - i)
+        if avail >= co_argcount:
+            for i in range(co_argcount - input_argcount):
+                scope_w[i + input_argcount] = self.frame.peekvalue(self.nargs - 1 - i)
             if has_vararg:
-                if blindargs > co_argcount:
+                if upfront > co_argcount:
+                    assert extravarargs is not None                    
                     stararg_w = extravarargs
                     for i in range(self.nargs):
                         stararg_w.append(self.frame.peekvalue(self.nargs - 1 - i))
                 else:
-                    stararg_w = [None] * (self.nargs + blindargs - co_argcount)
-                    for i in range(co_argcount - blindargs, self.nargs):
-                        stararg_w[i - co_argcount + blindargs] = self.frame.peekvalue(self.nargs - 1 - i)
+                    args_left = co_argcount - upfront                
+                    stararg_w = [None] * (avail - co_argcount)
+                    for i in range(args_left, self.nargs):
+                        stararg_w[i - args_left] = self.frame.peekvalue(self.nargs - 1 - i)
                 scope_w[co_argcount] = self.space.newtuple(stararg_w)
-                co_argcount += 1
         else:
             for i in range(self.nargs):
-                scope_w[i + blindargs] = self.frame.peekvalue(self.nargs - 1 - i)
+                scope_w[i + input_argcount] = self.frame.peekvalue(self.nargs - 1 - i)
             ndefaults = len(defaults_w)
-            missing = co_argcount - self.nargs - blindargs
+            missing = co_argcount - avail
             first_default = ndefaults - missing
             for i in range(missing):
-                scope_w[self.nargs + blindargs + i] = defaults_w[first_default + i]
+                scope_w[avail + i] = defaults_w[first_default + i]
             if has_vararg:
                 scope_w[co_argcount] = self.space.newtuple([])
-                co_argcount += 1
 
         if has_kwarg:
-            scope_w[co_argcount] = self.space.newdict()
-            co_argcount += 1
-        return co_argcount
+            scope_w[co_argcount + has_vararg] = self.space.newdict()
+        return co_argcount + has_vararg + has_kwarg
     
     def flatten(self):
         data_w = [None] * self.nargs
@@ -382,12 +350,12 @@
         "Return a ([w1,w2...], {'kw':w3...}) pair."
         self._unpack()
         return self.arguments_w, self.kwds_w
-    
-    def popfirst(self):
-        self._unpack()
-        return self.arguments_w[0], Arguments(self.space, self.arguments_w[1:],
-            kwds_w = self.kwds_w)
 
+    def prepend(self, w_firstarg):
+        "Return a new Arguments with a new argument inserted first."
+        return Arguments(self.space, [w_firstarg] + self.arguments_w,
+                         self.kwds_w, self.w_stararg, self.w_starstararg)
+            
     def _unpack(self):
         "unpack the *arg and **kwd into w_arguments and kwds_w"
         # --- unpack the * argument now ---
@@ -460,9 +428,8 @@
         
     ###  Parsing for function calls  ###
 
-    def _match_signature(self, scope_w, argnames, has_vararg=False,
-                         has_kwarg=False, defaults_w=[], blindargs=0,
-                         extravarargs=None):
+    def _match_signature(self, w_firstarg, scope_w, argnames, has_vararg=False,
+                         has_kwarg=False, defaults_w=[], blindargs=0):
         """Parse args and kwargs according to the signature of a code object,
         or raise an ArgErr in case of failure.
         Return the number of arguments filled in.
@@ -474,10 +441,23 @@
         #   scope_w = resulting list of wrapped values
         #
         co_argcount = len(argnames) # expected formal arguments, without */**
+        extravarargs = None
+        input_argcount =  0
+
+        if w_firstarg is not None:
+            upfront = 1
+            if co_argcount > 0:
+                scope_w[0] = w_firstarg
+                input_argcount = 1
+            else:
+                extravarargs = [ w_firstarg ]
+        else:
+            upfront = 0
+        
         if self.w_stararg is not None:
             # There is a case where we don't have to unpack() a w_stararg:
             # if it matches exactly a *arg in the signature.
-            if (len(self.arguments_w) + blindargs == co_argcount and
+            if (len(self.arguments_w) + upfront == co_argcount and
                 has_vararg and
                 self.space.is_w(self.space.type(self.w_stararg),
                                 self.space.w_tuple)):
@@ -489,23 +469,25 @@
             self._unpack()
 
         args_w = self.arguments_w
+        num_args = len(args_w)
+
         kwds_w = self.kwds_w
         num_kwds = 0
         if kwds_w is not None:
             num_kwds = len(kwds_w)
-            
-        # put as many positional input arguments into place as available
-        if blindargs >= co_argcount:
-            input_argcount = co_argcount
-        elif len(args_w) + blindargs > co_argcount:
-            for i in range(co_argcount - blindargs):
-                scope_w[i + blindargs] = args_w[i]
-            input_argcount = co_argcount
-            next_arg = co_argcount - blindargs
-        else:
-            for i in range(len(args_w)):
-                scope_w[i + blindargs] = args_w[i]
-            input_argcount = len(args_w) + blindargs
+
+        avail = num_args + upfront
+
+        if input_argcount < co_argcount:
+            # put as many positional input arguments into place as available
+            if avail > co_argcount:
+                take = co_argcount - input_argcount
+            else:
+                take = num_args
+
+            for i in range(take):
+                scope_w[i + input_argcount] = args_w[i]
+            input_argcount += take
 
         # check that no keyword argument conflicts with these
         # note that for this purpose we ignore the first blindargs,
@@ -542,21 +524,21 @@
         # collect extra positional arguments into the *vararg
         if has_vararg:
             if self.w_stararg is None:   # common case
-                args_left = co_argcount - blindargs
+                args_left = co_argcount - upfront
                 if args_left < 0:  # check required by rpython
                     assert extravarargs is not None
                     starargs_w = extravarargs
-                    if len(args_w):
+                    if num_args:
                         starargs_w.extend(args_w)
-                elif len(args_w) > args_left: 
+                elif num_args > args_left:
                     starargs_w = args_w[args_left:]
                 else:
                     starargs_w = []
                 scope_w[co_argcount] = self.space.newtuple(starargs_w)
             else:      # shortcut for the non-unpack() case above
                 scope_w[co_argcount] = self.w_stararg
-        elif len(args_w) + blindargs > co_argcount:
-            raise ArgErrCount(len(args_w) + blindargs, num_kwds,
+        elif avail > co_argcount:
+            raise ArgErrCount(avail, num_kwds,
                               (co_argcount, has_vararg, has_kwarg),
                               defaults_w, 0)
 
@@ -571,7 +553,7 @@
             raise ArgErrUnknownKwds(remainingkwds_w)
 
         if missing:
-            raise ArgErrCount(len(args_w) + blindargs, num_kwds,
+            raise ArgErrCount(avail, num_kwds,
                               (co_argcount, has_vararg, has_kwarg),
                               defaults_w, missing)
 

Modified: pypy/dist/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/dist/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/dist/pypy/interpreter/baseobjspace.py	Sun Aug 10 23:55:49 2008
@@ -665,20 +665,31 @@
                     return True
         return False
 
+    def call_obj_args(self, w_callable, w_obj, args):
+        if not self.config.objspace.disable_call_speedhacks:
+            # XXX start of hack for performance            
+            from pypy.interpreter.function import Function        
+            if isinstance(w_callable, Function):
+                return w_callable.call_obj_args(w_obj, args)
+            # XXX end of hack for performance
+        return self.call_args(w_callable, args.prepend(w_obj))
+
     def call(self, w_callable, w_args, w_kwds=None):
         args = Arguments.frompacked(self, w_args, w_kwds)
         return self.call_args(w_callable, args)
 
     def call_function(self, w_func, *args_w):
-        if not self.config.objspace.disable_call_speedhacks:
+        nargs = len(args_w) # used for pruning funccall versions
+        if not self.config.objspace.disable_call_speedhacks and nargs < 5:
             # XXX start of hack for performance
             from pypy.interpreter.function import Function, Method
             if isinstance(w_func, Method):
                 w_inst = w_func.w_instance
                 if w_inst is not None:
-                    func = w_func.w_function
-                    if isinstance(func, Function):
-                        return func.funccall(w_inst, *args_w)
+                    if nargs < 4:
+                        func = w_func.w_function
+                        if isinstance(func, Function):
+                            return func.funccall(w_inst, *args_w)
                 elif args_w and self.is_true(
                         self.abstract_isinstance(args_w[0], w_func.w_class)):
                     w_func = w_func.w_function
@@ -698,9 +709,10 @@
             if isinstance(w_func, Method):
                 w_inst = w_func.w_instance
                 if w_inst is not None:
-                    func = w_func.w_function
-                    if isinstance(func, Function):
-                        return func.funccall_obj_valuestack(w_inst, nargs, frame)
+                    w_func = w_func.w_function
+                    # reuse callable stack place for w_inst
+                    frame.settopvalue(w_inst, nargs)
+                    nargs += 1
                 elif nargs > 0 and self.is_true(
                     self.abstract_isinstance(frame.peekvalue(nargs-1),   #    :-(
                                              w_func.w_class)):

Modified: pypy/dist/pypy/interpreter/callbench/inst.py
==============================================================================
--- pypy/dist/pypy/interpreter/callbench/inst.py	(original)
+++ pypy/dist/pypy/interpreter/callbench/inst.py	Sun Aug 10 23:55:49 2008
@@ -5,6 +5,10 @@
         def __init__(self):
             pass
 
+    class B(object):
+        def __init__(self, x, y):
+            pass
+
     start()
     i = 0
     while i < N:
@@ -13,10 +17,10 @@
         A()
         A()
         A()
-        A()
-        A()
-        A()        
-        A()
+        B(1, 2)
+        B(1, 2)
+        B(1, 2)   
+        B(1, 2)
         i+=1
     
 run(w, 1000)

Modified: pypy/dist/pypy/interpreter/callbench/sup.py
==============================================================================
--- pypy/dist/pypy/interpreter/callbench/sup.py	(original)
+++ pypy/dist/pypy/interpreter/callbench/sup.py	Sun Aug 10 23:55:49 2008
@@ -16,10 +16,20 @@
         st[0] = t()
 
     ref(n, start)
-    elapsed_ref = t() - st[0]
+    elapsed_ref1 = t() - st[0]
+    ref(n, start)
+    elapsed_ref2 = t() - st[0]
+    ref(n, start)
+    elapsed_ref3 = t() - st[0]    
+    elapsed_ref = min(elapsed_ref1, elapsed_ref2, elapsed_ref3)
 
     func(n, start)
-    elapsed = t() - st[0]
+    elapsed1 = t() - st[0]
+    func(n, start)
+    elapsed2 = t() - st[0]
+    func(n, start)
+    elapsed3 = t() - st[0]
+    elapsed = min(elapsed1, elapsed2, elapsed3)    
 
     #if elapsed < elapsed_ref*10:
     #    print "not enough meat", elapsed, elapsed_ref

Modified: pypy/dist/pypy/interpreter/eval.py
==============================================================================
--- pypy/dist/pypy/interpreter/eval.py	(original)
+++ pypy/dist/pypy/interpreter/eval.py	Sun Aug 10 23:55:49 2008
@@ -11,6 +11,11 @@
     Abstract base class."""
     hidden_applevel = False
 
+    # n >= 0 : arity
+    # -n: special cases
+    # -99: hopeless    
+    fast_natural_arity = -99
+
     def __init__(self, co_name):
         self.co_name = co_name
 
@@ -55,18 +60,20 @@
         frame.setfastscope(scope_w)
         return frame.run()
 
+    def funcrun_obj(self, func, w_obj, args):
+        return self.funcrun(func, args.prepend(w_obj))
         
     # a performance hack (see gateway.BuiltinCode1/2/3 and pycode.PyCode)
     def fastcall_0(self, space, func):
-        return None
+        raise NotImplementedError
     def fastcall_1(self, space, func, w1):
-        return None
+        raise NotImplementedError        
     def fastcall_2(self, space, func, w1, w2):
-        return None
+        raise NotImplementedError                
     def fastcall_3(self, space, func, w1, w2, w3):
-        return None
+        raise NotImplementedError
     def fastcall_4(self, space, func, w1, w2, w3, w4):
-        return None
+        raise NotImplementedError                                
 
 class Frame(Wrappable):
     """A frame is an environment supporting the execution of a code object.

Modified: pypy/dist/pypy/interpreter/function.py
==============================================================================
--- pypy/dist/pypy/interpreter/function.py	(original)
+++ pypy/dist/pypy/interpreter/function.py	Sun Aug 10 23:55:49 2008
@@ -33,63 +33,70 @@
         return "<Function %s>" % getattr(self, 'name', '?')
 
     def call_args(self, args):
-        return self.code.funcrun(self, args) # delegate activation to code
+        # delegate activation to code        
+        return self.code.funcrun(self, args)
+
+    def call_obj_args(self, w_obj, args):
+        # delegate activation to code
+        return self.code.funcrun_obj(self, w_obj, args)
 
     def getcode(self):
         return self.code
     
     def funccall(self, *args_w): # speed hack
         code = self.getcode() # hook for the jit
-        if len(args_w) == 0:
-            w_res = code.fastcall_0(self.space, self)
-            if w_res is not None:
-                return w_res
-        elif len(args_w) == 1:
-            w_res = code.fastcall_1(self.space, self, args_w[0])
-            if w_res is not None:
-                return w_res
-        elif len(args_w) == 2:
-            w_res = code.fastcall_2(self.space, self, args_w[0], args_w[1])
-            if w_res is not None:
-                return w_res
-        elif len(args_w) == 3:
-            w_res = code.fastcall_3(self.space, self, args_w[0],
-                                    args_w[1], args_w[2])
-            if w_res is not None:
-                return w_res
-        elif len(args_w) == 4:
-            w_res = code.fastcall_4(self.space, self, args_w[0],
-                                    args_w[1], args_w[2], args_w[3])
-            if w_res is not None:
-                return w_res
+        nargs = len(args_w)
+        fast_natural_arity = code.fast_natural_arity
+        if nargs == fast_natural_arity:
+            if nargs == 0:
+                return code.fastcall_0(self.space, self)
+            elif nargs == 1:
+                return code.fastcall_1(self.space, self, args_w[0])
+            elif nargs == 2:
+                return code.fastcall_2(self.space, self, args_w[0], args_w[1])
+            elif nargs == 3:
+                return code.fastcall_3(self.space, self, args_w[0],
+                                       args_w[1], args_w[2])
+            elif nargs == 4:
+                return code.fastcall_4(self.space, self, args_w[0],
+                                       args_w[1], args_w[2], args_w[3])
+        elif nargs >= 1 and fast_natural_arity == -1:
+            from pypy.interpreter import gateway
+            assert isinstance(code, gateway.BuiltinCodePassThroughArguments1)
+            return code.funcrun_obj(self, args_w[0],
+                                    Arguments(self.space,
+                                              list(args_w[1:])))
         return self.call_args(Arguments(self.space, list(args_w)))
 
     def funccall_valuestack(self, nargs, frame): # speed hack
         code = self.getcode() # hook for the jit
-        if nargs == 0:
-            w_res = code.fastcall_0(self.space, self)
-            if w_res is not None:
-                return w_res
-        elif nargs == 1:
-            w_res = code.fastcall_1(self.space, self, frame.peekvalue(0))
-            if w_res is not None:
-                return w_res
-        elif nargs == 2:
-            w_res = code.fastcall_2(self.space, self, frame.peekvalue(1),
-                                    frame.peekvalue(0))
-            if w_res is not None:
-                return w_res
-        elif nargs == 3:
-            w_res = code.fastcall_3(self.space, self, frame.peekvalue(2),
-                                    frame.peekvalue(1), frame.peekvalue(0))
-            if w_res is not None:
-                return w_res
-        elif nargs == 4:
-            w_res = code.fastcall_4(self.space, self, frame.peekvalue(3),
-                                    frame.peekvalue(2), frame.peekvalue(1),
-                                    frame.peekvalue(0))
-            if w_res is not None:
-                return w_res
+        fast_natural_arity = code.fast_natural_arity        
+        if nargs == fast_natural_arity:        
+            if nargs == 0:
+                return code.fastcall_0(self.space, self)
+            elif nargs == 1:
+                return code.fastcall_1(self.space, self, frame.peekvalue(0))
+            elif nargs == 2:
+                return code.fastcall_2(self.space, self, frame.peekvalue(1),
+                                       frame.peekvalue(0))
+            elif nargs == 3:
+                return code.fastcall_3(self.space, self, frame.peekvalue(2),
+                                       frame.peekvalue(1), frame.peekvalue(0))
+            elif nargs == 4:
+                return code.fastcall_4(self.space, self, frame.peekvalue(3),
+                                       frame.peekvalue(2), frame.peekvalue(1),
+                                        frame.peekvalue(0))
+        elif fast_natural_arity == -1 and nargs >= 1:
+            from pypy.interpreter import gateway
+            assert isinstance(code, gateway.BuiltinCodePassThroughArguments1)
+            w_obj = frame.peekvalue(nargs-1)
+            args = frame.make_arguments(nargs-1)
+            try:
+                return code.funcrun_obj(self, w_obj, args)
+            finally:
+                if isinstance(args, ArgumentsFromValuestack):
+                    args.frame = None
+                    
         args = frame.make_arguments(nargs)
         try:
             return self.call_args(args)
@@ -97,34 +104,6 @@
             if isinstance(args, ArgumentsFromValuestack):
                 args.frame = None
 
-    def funccall_obj_valuestack(self, w_obj, nargs, frame): # speed hack
-        code = self.getcode() # hook for the jit
-        if nargs == 0:
-            w_res = code.fastcall_1(self.space, self, w_obj)
-            if w_res is not None:
-                return w_res
-        elif nargs == 1:
-            w_res = code.fastcall_2(self.space, self, w_obj, frame.peekvalue(0))
-            if w_res is not None:
-                return w_res
-        elif nargs == 2:
-            w_res = code.fastcall_3(self.space, self, w_obj, frame.peekvalue(1),
-                                    frame.peekvalue(0))
-            if w_res is not None:
-                return w_res
-        elif nargs == 3:
-            w_res = code.fastcall_4(self.space, self, w_obj, frame.peekvalue(2),
-                                    frame.peekvalue(1), frame.peekvalue(0))
-            if w_res is not None:
-                return w_res
-        stkargs = frame.make_arguments(nargs)
-        args = stkargs.prepend(w_obj)
-        try:
-            return self.call_args(args)
-        finally:
-            if isinstance(stkargs, ArgumentsFromValuestack):
-                stkargs.frame = None
-
     def getdict(self):
         if self.w_func_dict is None:
             self.w_func_dict = self.space.newdict()
@@ -339,29 +318,29 @@
         space = self.space
         if self.w_instance is not None:
             # bound method
-            args = args.prepend(self.w_instance)
-        else:
-            # unbound method
-            w_firstarg = args.firstarg()
-            if w_firstarg is not None and space.is_true(
-                    space.abstract_isinstance(w_firstarg, self.w_class)):
-                pass  # ok
+            return space.call_obj_args(self.w_function, self.w_instance, args)
+
+        # unbound method
+        w_firstarg = args.firstarg()
+        if w_firstarg is not None and space.is_true(
+                space.abstract_isinstance(w_firstarg, self.w_class)):
+            pass  # ok
+        else:
+            myname = self.getname(space,"")
+            clsdescr = self.w_class.getname(space,"")
+            if clsdescr:
+                clsdescr+=" "
+            if w_firstarg is None:
+                instdescr = "nothing"
             else:
-                myname = self.getname(space,"")
-                clsdescr = self.w_class.getname(space,"")
-                if clsdescr:
-                    clsdescr+=" "
-                if w_firstarg is None:
-                    instdescr = "nothing"
-                else:
-                    instname = space.abstract_getclass(w_firstarg).getname(space,"")
-                    if instname:
-                        instname += " "
-                    instdescr = "%sinstance" %instname
-                msg = ("unbound method %s() must be called with %s"
-                       "instance as first argument (got %s instead)")  % (myname, clsdescr, instdescr)
-                raise OperationError(space.w_TypeError,
-                                     space.wrap(msg))
+                instname = space.abstract_getclass(w_firstarg).getname(space,"")
+                if instname:
+                    instname += " "
+                instdescr = "%sinstance" %instname
+            msg = ("unbound method %s() must be called with %s"
+                   "instance as first argument (got %s instead)")  % (myname, clsdescr, instdescr)
+            raise OperationError(space.w_TypeError,
+                                 space.wrap(msg))
         return space.call_args(self.w_function, args)
 
     def descr_method_get(self, w_obj, w_cls=None):

Modified: pypy/dist/pypy/interpreter/gateway.py
==============================================================================
--- pypy/dist/pypy/interpreter/gateway.py	(original)
+++ pypy/dist/pypy/interpreter/gateway.py	Sun Aug 10 23:55:49 2008
@@ -479,9 +479,13 @@
         return space.wrap(self.docstring)
 
     def funcrun(self, func, args):
+        return BuiltinCode.funcrun_obj(self, func, None, args)
+
+    def funcrun_obj(self, func, w_obj, args):
         space = func.space
         activation = self.activation
-        scope_w = args.parse(func.name, self.sig, func.defs_w)
+        scope_w = args.parse_obj(w_obj, func.name, self.sig,
+                                 func.defs_w, self.minargs)
         try:
             w_result = activation._run(space, scope_w)
         except KeyboardInterrupt: 
@@ -495,6 +499,8 @@
             raise OperationError(space.w_RuntimeError, 
                                  space.wrap("internal error: " + str(e)))
         except DescrMismatch, e:
+            if w_obj is not None:
+                args = args.prepend(w_obj)
             return scope_w[0].descr_call_mismatch(space,
                                                   self.descrmismatch_op,
                                                   self.descr_reqcls,
@@ -530,35 +536,33 @@
         return w_result
 
 class BuiltinCodePassThroughArguments1(BuiltinCode):
+    fast_natural_arity = -1
 
-    def funcrun(self, func, args):
+    def funcrun_obj(self, func, w_obj, args):
         space = func.space
         try:
-            w_obj, newargs = args.popfirst()
-        except IndexError:
-            return BuiltinCode.funcrun(self, func, args)
-        else:
-            try:
-                w_result = self.func__args__(space, w_obj, newargs)
-            except KeyboardInterrupt: 
-                raise OperationError(space.w_KeyboardInterrupt, space.w_None) 
-            except MemoryError: 
-                raise OperationError(space.w_MemoryError, space.w_None)
-            except NotImplementedError, e:
-                raise
-            except RuntimeError, e: 
-                raise OperationError(space.w_RuntimeError, 
-                                     space.wrap("internal error: " + str(e))) 
-            except DescrMismatch, e:
-                return args.firstarg().descr_call_mismatch(space,
-                                                      self.descrmismatch_op,
-                                                      self.descr_reqcls,
-                                                      args)
-            if w_result is None:
-                w_result = space.w_None
-            return w_result
+            w_result = self.func__args__(space, w_obj, args)
+        except KeyboardInterrupt: 
+            raise OperationError(space.w_KeyboardInterrupt, space.w_None) 
+        except MemoryError: 
+            raise OperationError(space.w_MemoryError, space.w_None)
+        except NotImplementedError, e:
+            raise
+        except RuntimeError, e: 
+            raise OperationError(space.w_RuntimeError, 
+                                 space.wrap("internal error: " + str(e))) 
+        except DescrMismatch, e:
+            return args.firstarg().descr_call_mismatch(space,
+                                                  self.descrmismatch_op,
+                                                  self.descr_reqcls,
+                                                  args.prepend(w_obj))
+        if w_result is None:
+            w_result = space.w_None
+        return w_result
 
 class BuiltinCode0(BuiltinCode):
+    fast_natural_arity = 0
+    
     def fastcall_0(self, space, w_func):
         self = hint(self, deepfreeze=True)
         try:
@@ -575,6 +579,8 @@
         return w_result
 
 class BuiltinCode1(BuiltinCode):
+    fast_natural_arity = 1
+    
     def fastcall_1(self, space, w_func, w1):
         self = hint(self, deepfreeze=True)
         try:
@@ -598,6 +604,8 @@
         return w_result
 
 class BuiltinCode2(BuiltinCode):
+    fast_natural_arity = 2
+    
     def fastcall_2(self, space, w_func, w1, w2):
         self = hint(self, deepfreeze=True)
         try:
@@ -621,6 +629,8 @@
         return w_result
 
 class BuiltinCode3(BuiltinCode):
+    fast_natural_arity = 3
+    
     def fastcall_3(self, space, func, w1, w2, w3):
         self = hint(self, deepfreeze=True)
         try:
@@ -644,6 +654,8 @@
         return w_result
 
 class BuiltinCode4(BuiltinCode):
+    fast_natural_arity = 4
+    
     def fastcall_4(self, space, func, w1, w2, w3, w4):
         self = hint(self, deepfreeze=True)
         try:

Modified: pypy/dist/pypy/interpreter/pycode.py
==============================================================================
--- pypy/dist/pypy/interpreter/pycode.py	(original)
+++ pypy/dist/pypy/interpreter/pycode.py	Sun Aug 10 23:55:49 2008
@@ -162,7 +162,7 @@
     
     def _compute_fastcall(self):
         # Speed hack!
-        self.do_fastcall = -1
+        self.fast_natural_arity = -99
         if not (0 <= self.co_argcount <= 4):
             return
         if self.co_flags & (CO_VARARGS | CO_VARKEYWORDS):
@@ -170,59 +170,61 @@
         if len(self._args_as_cellvars) > 0:
             return
 
-        self.do_fastcall = self.co_argcount
+        self.fast_natural_arity = self.co_argcount
 
     def fastcall_0(self, space, w_func):
-        if self.do_fastcall == 0:
-            frame = space.createframe(self, w_func.w_func_globals,
+        frame = space.createframe(self, w_func.w_func_globals,
                                       w_func.closure)
-            return frame.run()
-        return None
+        return frame.run()
 
     def fastcall_1(self, space, w_func, w_arg):
-        if self.do_fastcall == 1:
-            frame = space.createframe(self, w_func.w_func_globals,
-                                      w_func.closure)
-            frame.fastlocals_w[0] = w_arg # frame.setfastscope([w_arg])
-            return frame.run()
-        return None
+        frame = space.createframe(self, w_func.w_func_globals,
+                                  w_func.closure)
+        frame.fastlocals_w[0] = w_arg # frame.setfastscope([w_arg])
+        return frame.run()
 
     def fastcall_2(self, space, w_func, w_arg1, w_arg2):
-        if self.do_fastcall == 2:
-            frame = space.createframe(self, w_func.w_func_globals,
-                                      w_func.closure)
-            frame.fastlocals_w[0] = w_arg1 # frame.setfastscope([w_arg])
-            frame.fastlocals_w[1] = w_arg2
-            return frame.run()
-        return None
+        frame = space.createframe(self, w_func.w_func_globals,
+                                  w_func.closure)
+        frame.fastlocals_w[0] = w_arg1 # frame.setfastscope([w_arg])
+        frame.fastlocals_w[1] = w_arg2
+        return frame.run()
 
     def fastcall_3(self, space, w_func, w_arg1, w_arg2, w_arg3):
-        if self.do_fastcall == 3:
-            frame = space.createframe(self, w_func.w_func_globals,
-                                       w_func.closure)
-            frame.fastlocals_w[0] = w_arg1 # frame.setfastscope([w_arg])
-            frame.fastlocals_w[1] = w_arg2 
-            frame.fastlocals_w[2] = w_arg3 
-            return frame.run()
-        return None
+        frame = space.createframe(self, w_func.w_func_globals,
+                                  w_func.closure)
+        frame.fastlocals_w[0] = w_arg1 # frame.setfastscope([w_arg])
+        frame.fastlocals_w[1] = w_arg2 
+        frame.fastlocals_w[2] = w_arg3 
+        return frame.run()
 
     def fastcall_4(self, space, w_func, w_arg1, w_arg2, w_arg3, w_arg4):
-        if self.do_fastcall == 4:
-            frame = space.createframe(self, w_func.w_func_globals,
-                                       w_func.closure)
-            frame.fastlocals_w[0] = w_arg1 # frame.setfastscope([w_arg])
-            frame.fastlocals_w[1] = w_arg2 
-            frame.fastlocals_w[2] = w_arg3 
-            frame.fastlocals_w[3] = w_arg4 
-            return frame.run()
-        return None
+        frame = space.createframe(self, w_func.w_func_globals,
+                                  w_func.closure)
+        frame.fastlocals_w[0] = w_arg1 # frame.setfastscope([w_arg])
+        frame.fastlocals_w[1] = w_arg2 
+        frame.fastlocals_w[2] = w_arg3 
+        frame.fastlocals_w[3] = w_arg4 
+        return frame.run()
 
     def funcrun(self, func, args):
         frame = self.space.createframe(self, func.w_func_globals,
                                   func.closure)
         sig = self._signature
         # speed hack
-        args_matched = args.parse_into_scope(frame.fastlocals_w, func.name,
+        args_matched = args.parse_into_scope(None, frame.fastlocals_w,
+                                             func.name,
+                                             sig, func.defs_w)
+        frame.init_cells()
+        return frame.run()
+
+    def funcrun_obj(self, func, w_obj, args):
+        frame = self.space.createframe(self, func.w_func_globals,
+                                  func.closure)
+        sig = self._signature
+        # speed hack
+        args_matched = args.parse_into_scope(w_obj, frame.fastlocals_w,
+                                             func.name,
                                              sig, func.defs_w)
         frame.init_cells()
         return frame.run()

Modified: pypy/dist/pypy/interpreter/test/test_function.py
==============================================================================
--- pypy/dist/pypy/interpreter/test/test_function.py	(original)
+++ pypy/dist/pypy/interpreter/test/test_function.py	Sun Aug 10 23:55:49 2008
@@ -84,6 +84,10 @@
         assert res[0] == 23
         assert res[1] == (42,)
 
+        res = func(23, *(42,))
+        assert res[0] == 23
+        assert res[1] == (42,)        
+
     def test_simple_kwargs(self):
         def func(arg1, **kwargs):
             return arg1, kwargs
@@ -91,6 +95,10 @@
         assert res[0] == 23
         assert res[1] == {'value': 42}
 
+        res = func(23, **{'value': 42})
+        assert res[0] == 23
+        assert res[1] == {'value': 42}
+
     def test_kwargs_sets_wrong_positional_raises(self):
         def func(arg1):
             pass
@@ -146,6 +154,25 @@
             return arg1, kw
         raises(TypeError, func, 42, **{'arg1': 23})
 
+    def test_kwargs_bound_blind(self):
+        class A(object):
+            def func(self, **kw):
+                return self, kw
+        func = A().func
+
+        # don't want the extra argument passing of raises
+        try:
+            func(self=23)
+            assert False
+        except TypeError:
+            pass
+
+        try:
+            func(**{'self': 23})
+            assert False
+        except TypeError:
+            pass        
+
     def test_kwargs_confusing_name(self):
         def func(self):    # 'self' conflicts with the interp-level
             return self*7  # argument to call_function()
@@ -177,6 +204,55 @@
         assert type(f.__doc__) is unicode
 
 class AppTestMethod: 
+    def test_simple_call(self):
+        class A(object):
+            def func(self, arg2):
+                return self, arg2
+        a = A()
+        res = a.func(42)
+        assert res[0] is a
+        assert res[1] == 42
+
+    def test_simple_varargs(self):
+        class A(object):
+            def func(self, *args):
+                return self, args
+        a = A()
+        res = a.func(42)
+        assert res[0] is a
+        assert res[1] == (42,)
+
+        res = a.func(*(42,))
+        assert res[0] is a
+        assert res[1] == (42,)        
+
+    def test_obscure_varargs(self):
+        class A(object):
+            def func(*args):
+                return args
+        a = A()
+        res = a.func(42)
+        assert res[0] is a
+        assert res[1] == 42
+
+        res = a.func(*(42,))
+        assert res[0] is a
+        assert res[1] == 42        
+
+    def test_simple_kwargs(self):
+        class A(object):
+            def func(self, **kwargs):
+                return self, kwargs
+        a = A()
+            
+        res = a.func(value=42)
+        assert res[0] is a
+        assert res[1] == {'value': 42}
+
+        res = a.func(**{'value': 42})
+        assert res[0] is a
+        assert res[1] == {'value': 42}
+
     def test_get(self):
         def func(self): return self
         class Object(object): pass
@@ -340,3 +416,72 @@
         # --- with an incompatible class
         w_meth5 = meth3.descr_method_get(space.wrap('hello'), space.w_str)
         assert space.is_w(w_meth5, w_meth3)
+
+class TestShortcuts(object): 
+
+    def test_fastcall(self):
+        space = self.space
+        
+        def f(a):
+            return a
+        code = PyCode._from_code(self.space, f.func_code)
+        fn = Function(self.space, code, self.space.newdict())
+
+        assert fn.code.fast_natural_arity == 1
+
+        called = []
+        fastcall_1 = fn.code.fastcall_1
+        def witness_fastcall_1(space, w_func, w_arg):
+            called.append(w_func)
+            return fastcall_1(space, w_func, w_arg)
+
+        fn.code.fastcall_1 = witness_fastcall_1
+
+        w_3 = space.newint(3)
+        w_res = space.call_function(fn, w_3)
+
+        assert w_res is w_3
+        assert called == [fn]
+
+        called = []
+
+        w_res = space.appexec([fn, w_3], """(f, x):
+        return f(x)
+        """)
+
+        assert w_res is w_3
+        assert called == [fn]
+
+    def test_fastcall_method(self):
+        space = self.space
+        
+        def f(self, a):
+            return a
+        code = PyCode._from_code(self.space, f.func_code)
+        fn = Function(self.space, code, self.space.newdict())
+
+        assert fn.code.fast_natural_arity == 2
+
+        called = []
+        fastcall_2 = fn.code.fastcall_2
+        def witness_fastcall_2(space, w_func, w_arg1, w_arg2):
+            called.append(w_func)
+            return fastcall_2(space, w_func, w_arg1, w_arg2)
+
+        fn.code.fastcall_2 = witness_fastcall_2
+
+        w_3 = space.newint(3)
+        w_res = space.appexec([fn, w_3], """(f, x):
+        class A(object):
+           m = f
+        y = A().m(x)
+        b = A().m
+        z = b(x)
+        return y is x and z is x
+        """)
+
+        assert space.is_true(w_res)
+        assert called == [fn, fn]       
+
+        
+        

Modified: pypy/dist/pypy/interpreter/test/test_gateway.py
==============================================================================
--- pypy/dist/pypy/interpreter/test/test_gateway.py	(original)
+++ pypy/dist/pypy/interpreter/test/test_gateway.py	Sun Aug 10 23:55:49 2008
@@ -1,4 +1,4 @@
-
+from pypy.conftest import gettestobjspace
 from pypy.interpreter import gateway
 from pypy.interpreter import argument
 import py
@@ -388,3 +388,250 @@
         w_app_g_run = space.wrap(app_g_run)
         w_bound = space.get(w_app_g_run, w("hello"), space.w_str)
         assert space.eq_w(space.call_function(w_bound), w(42))
+
+    def test_interp2app_fastcall(self):
+        space = self.space
+        w = space.wrap
+        w_3 = w(3)
+
+        def f(space):
+            return w_3
+        app_f = gateway.interp2app_temp(f, unwrap_spec=[gateway.ObjSpace])
+        w_app_f = w(app_f)
+
+        # sanity
+        assert isinstance(w_app_f.code, gateway.BuiltinCode0)
+
+        called = []
+        fastcall_0 = w_app_f.code.fastcall_0
+        def witness_fastcall_0(space, w_func):
+            called.append(w_func)
+            return fastcall_0(space, w_func)
+
+        w_app_f.code.fastcall_0 = witness_fastcall_0
+
+        w_3 = space.newint(3)
+        w_res = space.call_function(w_app_f)
+
+        assert w_res is w_3
+        assert called == [w_app_f]
+
+        called = []
+
+        w_res = space.appexec([w_app_f], """(f):
+        return f()
+        """)
+
+        assert w_res is w_3
+        assert called == [w_app_f]
+
+    def test_interp2app_fastcall_method(self):
+        space = self.space
+        w = space.wrap
+        w_3 = w(3)
+
+        def f(space, w_self, w_x):
+            return w_x
+        app_f = gateway.interp2app_temp(f, unwrap_spec=[gateway.ObjSpace,
+                                                        gateway.W_Root,
+                                                        gateway.W_Root])
+        w_app_f = w(app_f)
+
+        # sanity
+        assert isinstance(w_app_f.code, gateway.BuiltinCode2)
+
+        called = []
+        fastcall_2 = w_app_f.code.fastcall_2
+        def witness_fastcall_2(space, w_func, w_a, w_b):
+            called.append(w_func)
+            return fastcall_2(space, w_func, w_a, w_b)
+
+        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
+        y = A().m(x)
+        b = A().m
+        z = b(x)
+        return y is x and z is x
+        """)
+
+        assert space.is_true(w_res)
+        assert called == [w_app_f, w_app_f]       
+        
+    def test_plain(self):
+        space = self.space
+
+        def g(space, w_a, w_x):
+            return space.newtuple([space.wrap('g'), w_a, w_x])
+
+        w_g = space.wrap(gateway.interp2app_temp(g,
+                         unwrap_spec=[gateway.ObjSpace,
+                                      gateway.W_Root,
+                                      gateway.W_Root]))
+
+        args = argument.Arguments(space, [space.wrap(-1), space.wrap(0)])
+
+        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)])
+        args = args0.prepend(w_self)
+
+        w_res = space.call_args(w_g, args)
+        assert space.is_true(space.eq(w_res, space.wrap(('g', 'self', 0))))
+
+        args3 = argument.Arguments(space, [space.wrap(3)])
+        w_res = space.call_obj_args(w_g, w_self, args3)
+        assert space.is_true(space.eq(w_res, space.wrap(('g', 'self', 3))))
+
+
+class TestPassThroughArguments:
+    
+    def test_pass_trough_arguments0(self):
+        space = self.space
+
+        called = []
+        
+        def f(space, __args__):
+            called.append(__args__)
+            a_w, _ = __args__.unpack()
+            return space.newtuple([space.wrap('f')]+a_w)
+
+        w_f = space.wrap(gateway.interp2app_temp(f,
+                         unwrap_spec=[gateway.ObjSpace,
+                                      gateway.Arguments]))
+
+        args = argument.Arguments(space, [space.wrap(7)])
+
+        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
+
+    def test_pass_trough_arguments1(self):
+        space = self.space
+
+        called = []
+        
+        def g(space, w_self, __args__):
+            called.append(__args__)
+            a_w, _ = __args__.unpack()
+            return space.newtuple([space.wrap('g'), w_self, ]+a_w)
+
+        w_g = space.wrap(gateway.interp2app_temp(g,
+                         unwrap_spec=[gateway.ObjSpace,
+                                      gateway.W_Root,
+                                      gateway.Arguments]))
+
+        old_funcrun = w_g.code.funcrun
+        def funcrun_witness(func, args):
+            called.append('funcrun')
+            return old_funcrun(func, args)
+
+        w_g.code.funcrun = funcrun_witness
+
+        w_self = space.wrap('self')
+
+        args3 = argument.Arguments(space, [space.wrap(3)])
+        w_res = space.call_obj_args(w_g, w_self, args3)
+        assert space.is_true(space.eq(w_res, space.wrap(('g', 'self', 3))))
+        # white-box check for opt
+        assert len(called) == 1
+        assert called[0] is args3
+
+        called = []
+        args0 = argument.Arguments(space, [space.wrap(0)])
+        args = args0.prepend(w_self)
+
+        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 called[0] == 'funcrun'
+        called = []
+
+        # higher level interfaces
+
+        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.AbstractArguments)        
+        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.AbstractArguments)                
+        called = []
+
+        w_res = space.appexec([w_g], """(g):
+        class A(object):
+           m = g # not a builtin function, so works as method
+        d = {'A': A}
+        exec \"\"\"
+# own compiler
+a = A()
+y = a.m(33)
+\"\"\" in d
+        return d['y'] == ('g', d['a'], 33)
+        """)
+        assert space.is_true(w_res)
+        assert len(called) == 1
+        assert isinstance(called[0], argument.AbstractArguments)
+
+class TestPassThroughArguments_CALL_METHOD(TestPassThroughArguments):
+
+    def setup_class(cls):
+        space = gettestobjspace(usemodules=('_stackless',), **{
+            "objspace.opcodes.CALL_METHOD": True
+            })
+        cls.space = space
+
+class AppTestKeywordsToBuiltinSanity(object):
+
+    def test_type(self):
+        class X(object):
+            def __init__(self, **kw):
+                pass
+        clash = type.__call__.func_code.co_varnames[0]
+
+        X(**{clash: 33})
+        type.__call__(X, **{clash: 33})
+
+    def test_object_new(self):
+        class X(object):
+            def __init__(self, **kw):
+                pass
+        clash = object.__new__.func_code.co_varnames[0]
+
+        X(**{clash: 33})
+        object.__new__(X, **{clash: 33})
+
+
+    def test_dict_new(self):
+        clash = dict.__new__.func_code.co_varnames[0]
+
+        dict(**{clash: 33})
+        dict.__new__(dict, **{clash: 33})        
+
+    def test_dict_init(self):
+        d = {}
+        clash = dict.__init__.func_code.co_varnames[0]
+
+        d.__init__(**{clash: 33})
+        dict.__init__(d, **{clash: 33})
+
+    def test_dict_update(self):
+        d = {}
+        clash = dict.update.func_code.co_varnames[0]
+
+        d.update(**{clash: 33})
+        dict.update(d, **{clash: 33})        
+        

Modified: pypy/dist/pypy/interpreter/test/test_objspace.py
==============================================================================
--- pypy/dist/pypy/interpreter/test/test_objspace.py	(original)
+++ pypy/dist/pypy/interpreter/test/test_objspace.py	Sun Aug 10 23:55:49 2008
@@ -180,6 +180,36 @@
         w_obj = space.wrap(-12)
         space.raises_w(space.w_ValueError, space.r_ulonglong_w, w_obj)
 
+    def test_call_obj_args(self):
+        from pypy.interpreter.argument import Arguments
+        
+        space = self.space
+
+        w_f = space.appexec([], """():
+    def f(x, y):
+        return (x, y)
+    return f
+""")
+
+        w_a = space.appexec([], """():
+    class A(object):
+        def __call__(self, x):
+            return x
+    return A()
+""")
+
+        w_9 = space.wrap(9)
+        w_1 = space.wrap(1)
+
+        w_res = space.call_obj_args(w_f, w_9, Arguments(space, [w_1]))
+
+        w_x, w_y = space.unpacktuple(w_res, 2)
+        assert w_x is w_9
+        assert w_y is w_1
+
+        w_res = space.call_obj_args(w_a, w_9, Arguments(space, []))        
+        assert w_res is w_9
+
 
 class TestModuleMinimal: 
     def test_sys_exists(self):

Modified: pypy/dist/pypy/module/__builtin__/test/test_builtin.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/test/test_builtin.py	(original)
+++ pypy/dist/pypy/module/__builtin__/test/test_builtin.py	Sun Aug 10 23:55:49 2008
@@ -503,6 +503,28 @@
         s = """ """
         # XXX write this test!
 
+    def test_shadow_case_bound_method(self):
+        s = """def test(l):
+        n = len(l)
+        old_len = len
+        class A(object):
+            x = 5
+            def length(self, o):
+                return self.x*old_len(o)
+        import __builtin__
+        __builtin__.len = A().length
+        try:
+            m = len(l)
+        finally:
+            __builtin__.len = old_len
+        return n+m
+        """
+        ns = {}
+        exec s in ns
+        res = ns["test"]([2,3,4])
+        assert res == 18
+        
+
 class TestInternal:
 
     def setup_method(self,method):

Modified: pypy/dist/pypy/module/operator/__init__.py
==============================================================================
--- pypy/dist/pypy/module/operator/__init__.py	(original)
+++ pypy/dist/pypy/module/operator/__init__.py	Sun Aug 10 23:55:49 2008
@@ -21,15 +21,16 @@
                  'countOf', 'delslice', 'getslice', 'indexOf',
                  'isMappingType', 'isNumberType', 'isSequenceType',
                  'repeat', 'setslice',
+                 'attrgetter', 'itemgetter'
              ]
 
     for name in app_names:
         appleveldefs[name] = 'app_operator.%s' % name
 
-    interp_names = ['index', 'abs', 'add', 'and_', 'attrgetter',
+    interp_names = ['index', 'abs', 'add', 'and_',
                     'concat', 'contains', 'delitem', 'div', 'eq', 'floordiv',
                     'ge', 'getitem', 'gt', 'inv',
-                    'invert', 'is_', 'is_not', 'isCallable', 'itemgetter',
+                    'invert', 'is_', 'is_not', 'isCallable',
                     'le', 'lshift', 'lt', 'mod', 'mul',
                     'ne', 'neg', 'not_', 'or_',
                     'pos', 'pow', 'rshift', 'setitem', 'sequenceIncludes',

Modified: pypy/dist/pypy/module/operator/app_operator.py
==============================================================================
--- pypy/dist/pypy/module/operator/app_operator.py	(original)
+++ pypy/dist/pypy/module/operator/app_operator.py	Sun Aug 10 23:55:49 2008
@@ -63,3 +63,20 @@
     a[b:c] = d 
 __setslice__ = setslice
 
+class attrgetter(object):
+
+    def __init__(self, name):
+        self.name = name
+
+    def __call__(self, obj):
+        return getattr(obj, self.name)
+    
+class itemgetter(object):
+
+    def __init__(self, index):
+        self.index = index
+
+    def __call__(self, obj):
+        return obj[self.index]
+
+    

Modified: pypy/dist/pypy/module/operator/interp_operator.py
==============================================================================
--- pypy/dist/pypy/module/operator/interp_operator.py	(original)
+++ pypy/dist/pypy/module/operator/interp_operator.py	Sun Aug 10 23:55:49 2008
@@ -157,52 +157,3 @@
 def xor(space, w_a, w_b):
     'xor(a, b) -- Same as a ^ b.'
     return space.xor(w_a, w_b)
-
-# ____________________________________________________________
-# attrgetter and itergetter
-
-from pypy.interpreter import eval, function
-from pypy.interpreter.error import OperationError
-
-class SimpleClosureBuiltinFunction(function.BuiltinFunction):
-
-    def __init__(self, space, code, w_index):
-        assert isinstance(code, SimpleClosureCode)
-        function.Function.__init__(self, space, code)
-        self.w_index = w_index
-
-
-class SimpleClosureCode(eval.Code):
-    sig = (['obj'], None, None)
-
-    def __init__(self, co_name, is_attrgetter):
-        eval.Code.__init__(self, co_name)
-        self.is_attrgetter = is_attrgetter
-
-    def signature(self):
-        return self.sig
-
-    def funcrun(self, func, args):
-        space = func.space
-        [w_obj] = args.parse(func.name, self.sig)
-        return self.fastcall_1(space, func, w_obj)
-
-    def fastcall_1(self, space, func, w_obj):
-        if not isinstance(func, SimpleClosureBuiltinFunction):
-            raise OperationError(space.w_TypeError, space.wrap("bad call"))
-        w_index = func.w_index
-        if self.is_attrgetter:
-            return space.getattr(w_obj, w_index)
-        else:
-            return space.getitem(w_obj, w_index)
-
-attrgetter_code = SimpleClosureCode("attrgetter", is_attrgetter=True)
-itemgetter_code = SimpleClosureCode("itemgetter", is_attrgetter=False)
-
-def attrgetter(space, w_attr):
-    func = SimpleClosureBuiltinFunction(space, attrgetter_code, w_attr)
-    return space.wrap(func)
-
-def itemgetter(space, w_idx):
-    func = SimpleClosureBuiltinFunction(space, itemgetter_code, w_idx)
-    return space.wrap(func)

Modified: pypy/dist/pypy/module/pypyjit/portal.py
==============================================================================
--- pypy/dist/pypy/module/pypyjit/portal.py	(original)
+++ pypy/dist/pypy/module/pypyjit/portal.py	Sun Aug 10 23:55:49 2008
@@ -111,8 +111,6 @@
         #
         self.seepath(pypy.interpreter.pyframe.PyFrame.CALL_FUNCTION,
                      pypy.interpreter.function.Function.funccall_valuestack)
-        self.seepath(pypy.interpreter.pyframe.PyFrame.CALL_FUNCTION,
-                     pypy.interpreter.function.Function.funccall_obj_valuestack)
 
 
 

Modified: pypy/dist/pypy/module/thread/os_local.py
==============================================================================
--- pypy/dist/pypy/module/thread/os_local.py	(original)
+++ pypy/dist/pypy/module/thread/os_local.py	Sun Aug 10 23:55:49 2008
@@ -29,7 +29,7 @@
                 w_self = space.wrap(self)
                 w_type = space.type(w_self)
                 w_init = space.getattr(w_type, space.wrap("__init__"))
-                space.call_args(w_init, self.initargs.prepend(w_self))
+                space.call_obj_args(w_init, w_self, self.initargs)
             except:
                 # failed, forget w_dict and propagate the exception
                 del self.dicts[ident]

Modified: pypy/dist/pypy/objspace/descroperation.py
==============================================================================
--- pypy/dist/pypy/objspace/descroperation.py	(original)
+++ pypy/dist/pypy/objspace/descroperation.py	Sun Aug 10 23:55:49 2008
@@ -75,7 +75,7 @@
         descr = space.interpclass_w(w_descr)
         # a special case for performance and to avoid infinite recursion
         if type(descr) is Function:
-            return descr.call_args(args.prepend(w_obj))
+            return descr.call_obj_args(w_obj, args)
         else:
             w_impl = space.get(w_descr, w_obj)
             return space.call_args(w_impl, args)

Modified: pypy/dist/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/std/objspace.py	(original)
+++ pypy/dist/pypy/objspace/std/objspace.py	Sun Aug 10 23:55:49 2008
@@ -2,8 +2,9 @@
 from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
 from pypy.interpreter.error import OperationError, debug_print
 from pypy.interpreter.typedef import get_unique_interplevel_subclass
-from pypy.interpreter.argument import Arguments
+from pypy.interpreter import argument
 from pypy.interpreter import pyframe
+from pypy.interpreter import function
 from pypy.interpreter.pyopcode import unrolling_compare_dispatch_table, \
      BytecodeCorruption
 from pypy.rlib.objectmodel import instantiate
@@ -147,13 +148,23 @@
                     nargs = oparg & 0xff
                     w_function = w_value
                     try:
-                        w_result = f.space.call_valuestack(w_function, nargs, f)
+                        w_result = f.call_likely_builtin(w_function, nargs)
                         # XXX XXX fix the problem of resume points!
                         #rstack.resume_point("CALL_FUNCTION", f, nargs, returns=w_result)
                     finally:
                         f.dropvalues(nargs)
                     f.pushvalue(w_result)
 
+                def call_likely_builtin(f, w_function, nargs):
+                    if isinstance(w_function, function.Function):
+                        return w_function.funccall_valuestack(nargs, f)
+                    args = f.make_arguments(nargs)
+                    try:
+                        return f.space.call_args(w_function, args)
+                    finally:
+                        if isinstance(args, argument.ArgumentsFromValuestack):
+                            args.frame = None
+
             if self.config.objspace.opcodes.CALL_METHOD:
                 # def LOOKUP_METHOD(...):
                 from pypy.objspace.std.callmethod import LOOKUP_METHOD

Modified: pypy/dist/pypy/objspace/std/proxyobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/proxyobject.py	(original)
+++ pypy/dist/pypy/objspace/std/proxyobject.py	Sun Aug 10 23:55:49 2008
@@ -5,7 +5,7 @@
 from pypy.objspace.std.objspace import *
 from pypy.objspace.std.proxy_helpers import register_type
 from pypy.interpreter.error import OperationError
-from pypy.interpreter import baseobjspace
+from pypy.interpreter import baseobjspace, argument
 
 #class W_Transparent(W_Object):
 #    def __init__(self, w_controller):
@@ -22,8 +22,10 @@
             self.space = space
     
         def descr_call_mismatch(self, space, name, reqcls, args):
-            _, args = args.popfirst()
-            args = args.prepend(space.wrap(name))
+            args_w, kwds_w = args.unpack()
+            args_w = args_w[:]
+            args_w[0] = space.wrap(name)
+            args = argument.Arguments(space, args_w,  kwds_w)
             return space.call_args(self.w_controller, args)
     
         def getclass(self, space):

Modified: pypy/dist/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/typeobject.py	(original)
+++ pypy/dist/pypy/objspace/std/typeobject.py	Sun Aug 10 23:55:49 2008
@@ -499,7 +499,7 @@
             return space.type(w_obj)
     # invoke the __new__ of the type
     w_newfunc = space.getattr(w_type, space.wrap('__new__'))
-    w_newobject = space.call_args(w_newfunc, __args__.prepend(w_type))
+    w_newobject = space.call_obj_args(w_newfunc, w_type, __args__)
     # maybe invoke the __init__ of the type
     if space.is_true(space.isinstance(w_newobject, w_type)):
         w_descr = space.lookup(w_newobject, '__init__')



More information about the Pypy-commit mailing list