[pypy-commit] pypy translation-cleanup: Allow const-folding of inner functions
rlamy
noreply at buildbot.pypy.org
Fri Oct 5 19:02:21 CEST 2012
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: translation-cleanup
Changeset: r57798:92f1d72513e1
Date: 2012-10-05 06:29 +0100
http://bitbucket.org/pypy/pypy/changeset/92f1d72513e1/
Log: Allow const-folding of inner functions
* Implement FlowSpaceFrame.MAKE_FUNCTION
* Add tests
* Don't wrap code constants in HostCode
diff --git a/pypy/objspace/flow/bytecode.py b/pypy/objspace/flow/bytecode.py
--- a/pypy/objspace/flow/bytecode.py
+++ b/pypy/objspace/flow/bytecode.py
@@ -19,8 +19,7 @@
def __init__(self, argcount, nlocals, stacksize, flags,
code, consts, names, varnames, filename,
- name, firstlineno, lnotab, freevars, cellvars,
- magic=cpython_magic):
+ name, firstlineno, lnotab, freevars, cellvars):
"""Initialize a new code object"""
self.co_name = name
assert nlocals >= 0
@@ -69,19 +68,12 @@
def _from_code(cls, code):
"""Initialize the code object from a real (CPython) one.
"""
- newconsts = []
- for const in code.co_consts:
- if isinstance(const, CodeType):
- const = cls._from_code(const)
- newconsts.append(const)
- # stick the underlying CPython magic value, if the code object
- # comes from there
return cls(code.co_argcount,
code.co_nlocals,
code.co_stacksize,
code.co_flags,
code.co_code,
- newconsts,
+ list(code.co_consts),
list(code.co_names),
list(code.co_varnames),
code.co_filename,
@@ -89,8 +81,7 @@
code.co_firstlineno,
code.co_lnotab,
list(code.co_freevars),
- list(code.co_cellvars),
- cpython_magic)
+ list(code.co_cellvars))
@property
def formalargcount(self):
diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py
--- a/pypy/objspace/flow/flowcontext.py
+++ b/pypy/objspace/flow/flowcontext.py
@@ -676,6 +676,12 @@
self.pushvalue(self.space.newlist([]))
self.pushvalue(last_val)
+ def MAKE_FUNCTION(self, numdefaults, next_instr):
+ w_codeobj = self.popvalue()
+ defaults = self.popvalues(numdefaults)
+ fn = self.space.newfunction(w_codeobj, self.w_globals, defaults)
+ self.pushvalue(fn)
+
# XXX Unimplemented 2.7 opcodes ----------------
# Set literals, set comprehensions
diff --git a/pypy/objspace/flow/objspace.py b/pypy/objspace/flow/objspace.py
--- a/pypy/objspace/flow/objspace.py
+++ b/pypy/objspace/flow/objspace.py
@@ -98,6 +98,17 @@
else:
return self.w_False
+ def newfunction(self, w_code, w_globals, defaults_w):
+ try:
+ code = self.unwrap(w_code)
+ globals = self.unwrap(w_globals)
+ defaults = tuple([self.unwrap(value) for value in defaults_w])
+ except UnwrapException:
+ raise FlowingError(self.frame, "Dynamically created function must"
+ " have constant default values.")
+ fn = types.FunctionType(code, globals, code.co_name, defaults)
+ return Constant(fn)
+
def wrap(self, obj):
if isinstance(obj, (Variable, Constant)):
raise TypeError("already wrapped: " + repr(obj))
diff --git a/pypy/objspace/flow/test/test_objspace.py b/pypy/objspace/flow/test/test_objspace.py
--- a/pypy/objspace/flow/test/test_objspace.py
+++ b/pypy/objspace/flow/test/test_objspace.py
@@ -1063,6 +1063,32 @@
assert len(graph.startblock.exits) == 1
assert graph.startblock.exits[0].target == graph.returnblock
+ def test_lambda(self):
+ def f():
+ g = lambda m, n: n*m
+ return g
+ graph = self.codetest(f)
+ assert len(graph.startblock.exits) == 1
+ assert graph.startblock.exits[0].target == graph.returnblock
+ g = graph.startblock.exits[0].args[0].value
+ assert g(4, 4) == 16
+
+ def test_lambda_with_defaults(self):
+ def f():
+ g = lambda m, n=5: n*m
+ return g
+ graph = self.codetest(f)
+ assert len(graph.startblock.exits) == 1
+ assert graph.startblock.exits[0].target == graph.returnblock
+ g = graph.startblock.exits[0].args[0].value
+ assert g(4) == 20
+
+ def f2(x):
+ g = lambda m, n=x: n*m
+ return g
+ with py.test.raises(FlowingError):
+ self.codetest(f2)
+
DATA = {'x': 5,
'y': 6}
More information about the pypy-commit
mailing list