[pypy-commit] pypy py3.6-wordcode: implement the new MAKE_FUNCTION bytecode, that subsumes MAKE_FUNCTION and
cfbolz
pypy.commits at gmail.com
Mon May 21 08:34:54 EDT 2018
Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: py3.6-wordcode
Changeset: r94623:fdaa88d1d204
Date: 2018-05-21 13:34 +0200
http://bitbucket.org/pypy/pypy/changeset/fdaa88d1d204/
Log: implement the new MAKE_FUNCTION bytecode, that subsumes
MAKE_FUNCTION and MAKE_CLOSURE.
diff --git a/lib-python/3/opcode.py b/lib-python/3/opcode.py
--- a/lib-python/3/opcode.py
+++ b/lib-python/3/opcode.py
@@ -216,6 +216,7 @@
def_op('BUILD_SET_UNPACK', 153)
def_op('FORMAT_VALUE', 155) # in CPython 3.6, but available in PyPy from 3.5
+def_op('BUILD_CONST_KEY_MAP', 156)
def_op('BUILD_STRING', 157) # in CPython 3.6, but available in PyPy from 3.5
# pypy modification, experimental bytecode
diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -757,7 +757,7 @@
return -2 - _num_args(arg) - ((arg >> 16) & 0xFFFF)
def _compute_MAKE_FUNCTION(arg):
- return -1 - _num_args(arg) - ((arg >> 16) & 0xFFFF)
+ return -1 - bool(arg & 0x01) - bool(arg & 0x02) - bool(arg & 0x04) - bool(arg & 0x08)
def _compute_BUILD_SLICE(arg):
if arg == 3:
@@ -794,6 +794,9 @@
def _compute_BUILD_STRING(arg):
return 1 - arg
+def _compute_BUILD_CONST_KEY_MAP(arg):
+ return -arg
+
_stack_effect_computers = {}
for name, func in globals().items():
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -320,10 +320,11 @@
self.add_none_to_final_return = False
mod.body.walkabout(self)
- def _make_function(self, code, num_defaults=0, qualname=None):
+ def _make_function(self, code, oparg=0, qualname=None):
"""Emit the opcodes to turn a code object into a function."""
w_qualname = self.space.newtext(qualname or code.co_name)
if code.co_freevars:
+ oparg = oparg | 0x08
# Load cell and free vars to pass on.
for free in code.co_freevars:
free_scope = self.scope.lookup(free)
@@ -334,24 +335,25 @@
index = self.free_vars[free]
self.emit_op_arg(ops.LOAD_CLOSURE, index)
self.emit_op_arg(ops.BUILD_TUPLE, len(code.co_freevars))
- self.load_const(code)
- self.load_const(w_qualname)
- self.emit_op_arg(ops.MAKE_CLOSURE, num_defaults)
- else:
- self.load_const(code)
- self.load_const(w_qualname)
- self.emit_op_arg(ops.MAKE_FUNCTION, num_defaults)
+ self.load_const(code)
+ self.load_const(w_qualname)
+ self.emit_op_arg(ops.MAKE_FUNCTION, oparg)
def _visit_kwonlydefaults(self, args):
defaults = 0
+ keys_w = []
for i, default in enumerate(args.kw_defaults):
if default:
kwonly = args.kwonlyargs[i]
assert isinstance(kwonly, ast.arg)
mangled = self.scope.mangle(kwonly.arg)
- self.load_const(self.space.newtext(mangled))
+ keys_w.append(self.space.newtext(mangled))
default.walkabout(self)
defaults += 1
+ if keys_w:
+ w_tup = self.space.newtuple(keys_w)
+ self.load_const(w_tup)
+ self.emit_op_arg(ops.BUILD_CONST_KEY_MAP, len(keys_w))
return defaults
def _visit_arg_annotation(self, name, ann, names):
@@ -386,7 +388,7 @@
self.error("too many annotations", func)
w_tup = space.newtuple([space.newtext(name) for name in names])
self.load_const(w_tup)
- l += 1
+ self.emit_op_arg(ops.BUILD_CONST_KEY_MAP, l)
return l
@specialize.arg(2)
@@ -395,16 +397,25 @@
# Load decorators first, but apply them after the function is created.
self.visit_sequence(func.decorator_list)
args = func.args
+
assert isinstance(args, ast.arguments)
+
+ oparg = 0
self.visit_sequence(args.defaults)
- kw_default_count = 0
+
+ if args.defaults is not None and len(args.defaults):
+ oparg = oparg | 0x01
+ self.emit_op_arg(ops.BUILD_TUPLE, len(args.defaults))
+
if args.kwonlyargs:
kw_default_count = self._visit_kwonlydefaults(args)
+ if kw_default_count:
+ oparg = oparg | 0x02
+
num_annotations = self._visit_annotations(func, args, func.returns)
- num_defaults = len(args.defaults) if args.defaults is not None else 0
- oparg = num_defaults
- oparg |= kw_default_count << 8
- oparg |= num_annotations << 16
+ if num_annotations:
+ oparg = oparg | 0x04
+
code, qualname = self.sub_scope(function_code_generator, func.name,
func, func.lineno)
self._make_function(code, oparg, qualname=qualname)
@@ -424,15 +435,20 @@
self.update_position(lam.lineno)
args = lam.args
assert isinstance(args, ast.arguments)
+
self.visit_sequence(args.defaults)
- kw_default_count = 0
+
+ oparg = 0
+ if args.defaults is not None and len(args.defaults):
+ oparg = oparg | 0x01
+ self.emit_op_arg(ops.BUILD_TUPLE, len(args.defaults))
+
if args.kwonlyargs:
kw_default_count = self._visit_kwonlydefaults(args)
- default_count = len(args.defaults) if args.defaults is not None else 0
+ if kw_default_count:
+ oparg = oparg | 0x02
code, qualname = self.sub_scope(
LambdaCodeGenerator, "<lambda>", lam, lam.lineno)
- oparg = default_count
- oparg |= kw_default_count << 8
self._make_function(code, oparg, qualname=qualname)
def visit_ClassDef(self, cls):
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -39,7 +39,7 @@
# time you make pyc files incompatible. This value ends up in the frozen
# importlib, via MAGIC_NUMBER in module/_frozen_importlib/__init__.
-pypy_incremental_magic = 144 # bump it by 16
+pypy_incremental_magic = 160 # bump it by 16
assert pypy_incremental_magic % 16 == 0
assert pypy_incremental_magic < 3000 # the magic number of Python 3. There are
# no known magic numbers below this value
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -247,6 +247,8 @@
self.BINARY_TRUE_DIVIDE(oparg, next_instr)
elif opcode == opcodedesc.BINARY_XOR.index:
self.BINARY_XOR(oparg, next_instr)
+ elif opcode == opcodedesc.BUILD_CONST_KEY_MAP.index:
+ self.BUILD_CONST_KEY_MAP(oparg, next_instr)
elif opcode == opcodedesc.BUILD_LIST.index:
self.BUILD_LIST(oparg, next_instr)
elif opcode == opcodedesc.BUILD_LIST_FROM_ARG.index:
@@ -357,8 +359,6 @@
self.LOAD_NAME(oparg, next_instr)
elif opcode == opcodedesc.LOOKUP_METHOD.index:
self.LOOKUP_METHOD(oparg, next_instr)
- elif opcode == opcodedesc.MAKE_CLOSURE.index:
- self.MAKE_CLOSURE(oparg, next_instr)
elif opcode == opcodedesc.MAKE_FUNCTION.index:
self.MAKE_FUNCTION(oparg, next_instr)
elif opcode == opcodedesc.MAP_ADD.index:
@@ -1341,47 +1341,42 @@
self.call_function(oparg, w_varkw, has_vararg=True)
@jit.unroll_safe
- def _make_function(self, oparg, freevars=None):
+ def MAKE_FUNCTION(self, oparg, next_instr):
space = self.space
w_qualname = self.popvalue()
qualname = self.space.unicode_w(w_qualname)
w_codeobj = self.popvalue()
codeobj = self.space.interp_w(PyCode, w_codeobj)
- if freevars is not None:
- # Pop freevars
- self.popvalue()
- posdefaults = oparg & 0xFF
- kwdefaults = (oparg >> 8) & 0xFF
- num_annotations = (oparg >> 16) & 0xFF
- w_ann = None
- if num_annotations:
- names_w = space.fixedview(self.popvalue())
- w_ann = space.newdict(strdict=True)
- for i in range(len(names_w) - 1, -1, -1):
- space.setitem(w_ann, names_w[i], self.popvalue())
- kw_defs_w = None
- if kwdefaults:
- kw_defs_w = []
- for i in range(kwdefaults):
- w_defvalue = self.popvalue()
- w_defname = self.popvalue()
- kw_defs_w.append((w_defname, w_defvalue))
- defaultarguments = self.popvalues(posdefaults)
+ assert 0 <= oparg <= 0x0F
+ if oparg & 0x08:
+ w_freevarstuple = self.popvalue()
+ # XXX this list copy is expensive, it's purely for the annotator
+ freevars = [self.space.interp_w(Cell, cell)
+ for cell in self.space.fixedview(w_freevarstuple)]
+ else:
+ freevars = None
+ if oparg & 0x04:
+ w_ann = self.popvalue()
+ else:
+ w_ann = None
+ if oparg & 0x02:
+ w_kw_defs = self.popvalue()
+ # XXX
+ kw_defs_w = [space.unpackiterable(w_tup)
+ for w_tup in space.fixedview(
+ space.call_method(w_kw_defs, 'items'))]
+ else:
+ kw_defs_w = None
+ if oparg & 0x01:
+ defaultarguments = space.fixedview(self.popvalue())
+ else:
+ defaultarguments = []
+
fn = function.Function(space, codeobj, self.get_w_globals(),
defaultarguments,
kw_defs_w, freevars, w_ann, qualname=qualname)
self.pushvalue(fn)
- def MAKE_FUNCTION(self, oparg, next_instr):
- return self._make_function(oparg)
-
- @jit.unroll_safe
- def MAKE_CLOSURE(self, oparg, next_instr):
- w_freevarstuple = self.peekvalue(2)
- freevars = [self.space.interp_w(Cell, cell)
- for cell in self.space.fixedview(w_freevarstuple)]
- self._make_function(oparg, freevars)
-
def BUILD_SLICE(self, numargs, next_instr):
if numargs == 3:
w_step = self.popvalue()
@@ -1431,7 +1426,18 @@
w_value = self.peekvalue(2 * i)
w_key = self.peekvalue(2 * i + 1)
self.space.setitem(w_dict, w_key, w_value)
- self.popvalues(2 * itemcount)
+ self.dropvalues(2 * itemcount)
+ self.pushvalue(w_dict)
+
+ @jit.unroll_safe
+ def BUILD_CONST_KEY_MAP(self, itemcount, next_instr):
+ keys_w = self.space.fixedview(self.popvalue())
+ w_dict = self.space.newdict()
+ for i in range(itemcount):
+ w_value = self.peekvalue(itemcount - 1 - i)
+ w_key = keys_w[i]
+ self.space.setitem(w_dict, w_key, w_value)
+ self.dropvalues(itemcount)
self.pushvalue(w_dict)
@jit.unroll_safe
@@ -1440,7 +1446,7 @@
for i in range(itemcount-1, -1, -1):
w_item = self.peekvalue(i)
self.space.call_method(w_set, 'add', w_item)
- self.popvalues(itemcount)
+ self.dropvalues(itemcount)
self.pushvalue(w_set)
@jit.unroll_safe
diff --git a/pypy/tool/opcode3.py b/pypy/tool/opcode3.py
--- a/pypy/tool/opcode3.py
+++ b/pypy/tool/opcode3.py
@@ -216,6 +216,7 @@
def_op('BUILD_SET_UNPACK', 153)
def_op('FORMAT_VALUE', 155) # in CPython 3.6, but available in PyPy from 3.5
+def_op("BUILD_CONST_KEY_MAP", 156)
def_op('BUILD_STRING', 157) # in CPython 3.6, but available in PyPy from 3.5
# pypy modification, experimental bytecode
More information about the pypy-commit
mailing list