[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