Author: Carl Friedrich Bolz <[email protected]>
Branch:
Changeset: r77306:a069d938fb12
Date: 2015-05-13 08:09 +0200
http://bitbucket.org/pypy/pypy/changeset/a069d938fb12/
Log: merge cells-local-stack
unify the PyFrame.cells and Pyframe.locals_stack_w lists, making
frame objects 1 or 3 words smaller.
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -105,7 +105,7 @@
self)
for i in funccallunrolling:
if i < nargs:
- new_frame.locals_stack_w[i] = args_w[i]
+ new_frame.locals_cells_stack_w[i] = args_w[i]
return new_frame.run()
elif nargs >= 1 and fast_natural_arity == Code.PASSTHROUGHARGS1:
assert isinstance(code, gateway.BuiltinCodePassThroughArguments1)
@@ -171,7 +171,7 @@
self)
for i in xrange(nargs):
w_arg = frame.peekvalue(nargs-1-i)
- new_frame.locals_stack_w[i] = w_arg
+ new_frame.locals_cells_stack_w[i] = w_arg
return new_frame.run()
@@ -182,13 +182,13 @@
self)
for i in xrange(nargs):
w_arg = frame.peekvalue(nargs-1-i)
- new_frame.locals_stack_w[i] = w_arg
+ new_frame.locals_cells_stack_w[i] = w_arg
ndefs = len(self.defs_w)
start = ndefs - defs_to_load
i = nargs
for j in xrange(start, ndefs):
- new_frame.locals_stack_w[i] = self.defs_w[j]
+ new_frame.locals_cells_stack_w[i] = self.defs_w[j]
i += 1
return new_frame.run()
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -209,7 +209,7 @@
# speed hack
fresh_frame = jit.hint(frame, access_directly=True,
fresh_virtualizable=True)
- args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name,
+ args.parse_into_scope(None, fresh_frame.locals_cells_stack_w,
func.name,
sig, func.defs_w)
fresh_frame.init_cells()
return frame.run()
@@ -221,7 +221,7 @@
# speed hack
fresh_frame = jit.hint(frame, access_directly=True,
fresh_virtualizable=True)
- args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name,
+ args.parse_into_scope(w_obj, fresh_frame.locals_cells_stack_w,
func.name,
sig, func.defs_w)
fresh_frame.init_cells()
return frame.run()
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -69,10 +69,9 @@
w_globals = None
pycode = None # code object executed by that frame
- locals_stack_w = None # the list of all locals and valuestack
+ locals_cells_stack_w = None # the list of all locals, cells and the
valuestack
valuestackdepth = 0 # number of items on valuestack
lastblock = None
- cells = None # cells
# other fields:
@@ -93,9 +92,14 @@
self.space = space
self.w_globals = w_globals
self.pycode = code
- self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize)
- self.valuestackdepth = code.co_nlocals
- make_sure_not_resized(self.locals_stack_w)
+ ncellvars = len(code.co_cellvars)
+ nfreevars = len(code.co_freevars)
+ size = code.co_nlocals + ncellvars + nfreevars + code.co_stacksize
+ # the layout of this list is as follows:
+ # | local vars | cells | stack |
+ self.locals_cells_stack_w = [None] * size
+ self.valuestackdepth = code.co_nlocals + ncellvars + nfreevars
+ make_sure_not_resized(self.locals_cells_stack_w)
check_nonneg(self.valuestackdepth)
#
if space.config.objspace.honor__builtins__:
@@ -136,6 +140,11 @@
self.__class__.__module__, self.__class__.__name__,
self.pycode, self.get_last_lineno())
+ def _getcell(self, varindex):
+ cell = self.locals_cells_stack_w[varindex + self.pycode.co_nlocals]
+ assert isinstance(cell, Cell)
+ return cell
+
def mark_as_escaped(self):
"""
Must be called on frames that are exposed to applevel, e.g. by
@@ -181,8 +190,6 @@
else:
return self.space.builtin
- _NO_CELLS = []
-
@jit.unroll_safe
def initialize_frame_scopes(self, outer_func, code):
# regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
@@ -201,8 +208,7 @@
nfreevars = len(code.co_freevars)
if not nfreevars:
if not ncellvars:
- self.cells = self._NO_CELLS
- return # no self.cells needed - fast path
+ return # no cells needed - fast path
elif outer_func is None:
space = self.space
raise OperationError(space.w_TypeError,
@@ -215,11 +221,13 @@
if closure_size != nfreevars:
raise ValueError("code object received a closure with "
"an unexpected number of free variables")
- self.cells = [None] * (ncellvars + nfreevars)
+ index = code.co_nlocals
for i in range(ncellvars):
- self.cells[i] = Cell()
+ self.locals_cells_stack_w[index] = Cell()
+ index += 1
for i in range(nfreevars):
- self.cells[i + ncellvars] = outer_func.closure[i]
+ self.locals_cells_stack_w[index] = outer_func.closure[i]
+ index += 1
def run(self):
"""Start this frame's execution."""
@@ -283,14 +291,24 @@
# stack manipulation helpers
def pushvalue(self, w_object):
depth = self.valuestackdepth
- self.locals_stack_w[depth] = w_object
+ self.locals_cells_stack_w[depth] = w_object
self.valuestackdepth = depth + 1
+ def _check_stack_index(self, index):
+ # will be completely removed by the optimizer if only used in an assert
+ # and if asserts are disabled
+ code = self.pycode
+ ncellvars = len(code.co_cellvars)
+ nfreevars = len(code.co_freevars)
+ stackstart = code.co_nlocals + ncellvars + nfreevars
+ return index >= stackstart
+
def popvalue(self):
depth = self.valuestackdepth - 1
- assert depth >= self.pycode.co_nlocals, "pop from empty value stack"
- w_object = self.locals_stack_w[depth]
- self.locals_stack_w[depth] = None
+ assert self._check_stack_index(depth)
+ assert depth >= 0
+ w_object = self.locals_cells_stack_w[depth]
+ self.locals_cells_stack_w[depth] = None
self.valuestackdepth = depth
return w_object
@@ -316,25 +334,26 @@
def peekvalues(self, n):
values_w = [None] * n
base = self.valuestackdepth - n
- assert base >= self.pycode.co_nlocals
+ assert self._check_stack_index(base)
+ assert base >= 0
while True:
n -= 1
if n < 0:
break
- values_w[n] = self.locals_stack_w[base+n]
+ values_w[n] = self.locals_cells_stack_w[base+n]
return values_w
@jit.unroll_safe
def dropvalues(self, n):
n = hint(n, promote=True)
finaldepth = self.valuestackdepth - n
- assert finaldepth >= self.pycode.co_nlocals, (
- "stack underflow in dropvalues()")
+ assert self._check_stack_index(finaldepth)
+ assert finaldepth >= 0
while True:
n -= 1
if n < 0:
break
- self.locals_stack_w[finaldepth+n] = None
+ self.locals_cells_stack_w[finaldepth+n] = None
self.valuestackdepth = finaldepth
@jit.unroll_safe
@@ -361,34 +380,27 @@
# Contrast this with CPython where it's PEEK(-1).
index_from_top = hint(index_from_top, promote=True)
index = self.valuestackdepth + ~index_from_top
- assert index >= self.pycode.co_nlocals, (
- "peek past the bottom of the stack")
- return self.locals_stack_w[index]
+ assert self._check_stack_index(index)
+ assert index >= 0
+ return self.locals_cells_stack_w[index]
def settopvalue(self, w_object, index_from_top=0):
index_from_top = hint(index_from_top, promote=True)
index = self.valuestackdepth + ~index_from_top
- assert index >= self.pycode.co_nlocals, (
- "settop past the bottom of the stack")
- self.locals_stack_w[index] = w_object
+ assert self._check_stack_index(index)
+ assert index >= 0
+ self.locals_cells_stack_w[index] = w_object
@jit.unroll_safe
def dropvaluesuntil(self, finaldepth):
depth = self.valuestackdepth - 1
finaldepth = hint(finaldepth, promote=True)
+ assert finaldepth >= 0
while depth >= finaldepth:
- self.locals_stack_w[depth] = None
+ self.locals_cells_stack_w[depth] = None
depth -= 1
self.valuestackdepth = finaldepth
- def save_locals_stack(self):
- return self.locals_stack_w[:self.valuestackdepth]
-
- def restore_locals_stack(self, items_w):
- self.locals_stack_w[:len(items_w)] = items_w
- self.init_cells()
- self.dropvaluesuntil(len(items_w))
-
def make_arguments(self, nargs):
return Arguments(self.space, self.peekvalues(nargs))
@@ -411,24 +423,16 @@
w = space.wrap
nt = space.newtuple
- cells = self.cells
- if cells is None:
- w_cells = space.w_None
- else:
- w_cells = space.newlist([space.wrap(cell) for cell in cells])
-
if self.get_w_f_trace() is None:
f_lineno = self.get_last_lineno()
else:
f_lineno = self.getorcreatedebug().f_lineno
nlocals = self.pycode.co_nlocals
- values_w = self.locals_stack_w[nlocals:self.valuestackdepth]
- w_valuestack = maker.slp_into_tuple_with_nulls(space, values_w)
+ values_w = self.locals_cells_stack_w
+ w_locals_cells_stack = maker.slp_into_tuple_with_nulls(space, values_w)
w_blockstack = nt([block._get_state_(space) for block in
self.get_blocklist()])
- w_fastlocals = maker.slp_into_tuple_with_nulls(
- space, self.locals_stack_w[:nlocals])
if self.last_exception is None:
w_exc_value = space.w_None
w_tb = space.w_None
@@ -441,7 +445,7 @@
w(self.f_backref()),
w(self.get_builtin()),
w(self.pycode),
- w_valuestack,
+ w_locals_cells_stack,
w_blockstack,
w_exc_value, # last_exception
w_tb, #
@@ -449,7 +453,6 @@
w(self.last_instr),
w(self.frame_finished_execution),
w(f_lineno),
- w_fastlocals,
space.w_None, #XXX placeholder for f_locals
#f_restricted requires no additional data!
@@ -458,7 +461,7 @@
w(d.instr_lb),
w(d.instr_ub),
w(d.instr_prev_plus_one),
- w_cells,
+ w(self.valuestackdepth),
]
return nt(tup_state)
@@ -467,24 +470,20 @@
from pypy.module._pickle_support import maker # helper fns
from pypy.interpreter.pycode import PyCode
from pypy.interpreter.module import Module
- args_w = space.unpackiterable(w_args, 18)
- w_f_back, w_builtin, w_pycode, w_valuestack, w_blockstack,
w_exc_value, w_tb,\
- w_globals, w_last_instr, w_finished, w_f_lineno, w_fastlocals,
w_f_locals, \
- w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev_plus_one, w_cells
= args_w
+ args_w = space.unpackiterable(w_args, 17)
+ w_f_back, w_builtin, w_pycode, w_locals_cells_stack, w_blockstack,
w_exc_value, w_tb,\
+ w_globals, w_last_instr, w_finished, w_f_lineno, w_f_locals, \
+ w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev_plus_one,
w_stackdepth = args_w
new_frame = self
pycode = space.interp_w(PyCode, w_pycode)
- if space.is_w(w_cells, space.w_None):
- closure = None
- cellvars = []
- else:
- from pypy.interpreter.nestedscope import Cell
- cells_w = space.unpackiterable(w_cells)
- cells = [space.interp_w(Cell, w_cell) for w_cell in cells_w]
- ncellvars = len(pycode.co_cellvars)
- cellvars = cells[:ncellvars]
- closure = cells[ncellvars:]
+ values_w = maker.slp_from_tuple_with_nulls(space, w_locals_cells_stack)
+ nfreevars = len(pycode.co_freevars)
+ closure = None
+ if nfreevars:
+ base = pycode.co_nlocals + len(pycode.co_cellvars)
+ closure = values_w[base: base + nfreevars]
# do not use the instance's __init__ but the base's, because we set
# everything like cells from here
@@ -502,9 +501,12 @@
assert space.interp_w(Module, w_builtin) is space.builtin
new_frame.set_blocklist([unpickle_block(space, w_blk)
for w_blk in
space.unpackiterable(w_blockstack)])
- values_w = maker.slp_from_tuple_with_nulls(space, w_valuestack)
- for w_value in values_w:
- new_frame.pushvalue(w_value)
+ self.locals_cells_stack_w = values_w[:]
+ valuestackdepth = space.int_w(w_stackdepth)
+ if not self._check_stack_index(valuestackdepth):
+ raise OperationError(space.w_ValueError, space.wrap("invalid
stackdepth"))
+ assert valuestackdepth >= 0
+ self.valuestackdepth = valuestackdepth
if space.is_w(w_exc_value, space.w_None):
new_frame.last_exception = None
else:
@@ -517,8 +519,6 @@
new_frame.frame_finished_execution = space.is_true(w_finished)
d = new_frame.getorcreatedebug()
d.f_lineno = space.int_w(w_f_lineno)
- fastlocals_w = maker.slp_from_tuple_with_nulls(space, w_fastlocals)
- new_frame.locals_stack_w[:len(fastlocals_w)] = fastlocals_w
if space.is_w(w_f_trace, space.w_None):
d.w_f_trace = None
@@ -529,8 +529,6 @@
d.instr_ub = space.int_w(w_instr_ub)
d.instr_prev_plus_one = space.int_w(w_instr_prev_plus_one)
- self._setcellvars(cellvars)
-
def hide(self):
return self.pycode.hidden_applevel
@@ -544,10 +542,10 @@
scope_len = len(scope_w)
if scope_len > self.pycode.co_nlocals:
raise ValueError, "new fastscope is longer than the allocated area"
- # don't assign directly to 'locals_stack_w[:scope_len]' to be
+ # don't assign directly to 'locals_cells_stack_w[:scope_len]' to be
# virtualizable-friendly
for i in range(scope_len):
- self.locals_stack_w[i] = scope_w[i]
+ self.locals_cells_stack_w[i] = scope_w[i]
self.init_cells()
def getdictscope(self):
@@ -573,7 +571,7 @@
varnames = self.getcode().getvarnames()
for i in range(min(len(varnames), self.getcode().co_nlocals)):
name = varnames[i]
- w_value = self.locals_stack_w[i]
+ w_value = self.locals_cells_stack_w[i]
if w_value is not None:
self.space.setitem_str(d.w_locals, name, w_value)
else:
@@ -592,7 +590,7 @@
freevarnames = freevarnames + self.pycode.co_freevars
for i in range(len(freevarnames)):
name = freevarnames[i]
- cell = self.cells[i]
+ cell = self._getcell(i)
try:
w_value = cell.get()
except ValueError:
@@ -631,7 +629,7 @@
# into the locals dict used by the class.
for i in range(len(freevarnames)):
name = freevarnames[i]
- cell = self.cells[i]
+ cell = self._getcell(i)
w_value = self.space.finditem_str(w_locals, name)
if w_value is not None:
cell.set(w_value)
@@ -639,24 +637,21 @@
@jit.unroll_safe
def init_cells(self):
"""
- Initialize cellvars from self.locals_stack_w.
+ Initialize cellvars from self.locals_cells_stack_w.
"""
args_to_copy = self.pycode._args_as_cellvars
+ index = self.pycode.co_nlocals
for i in range(len(args_to_copy)):
argnum = args_to_copy[i]
if argnum >= 0:
- self.cells[i].set(self.locals_stack_w[argnum])
+ cell = self.locals_cells_stack_w[index]
+ assert isinstance(cell, Cell)
+ cell.set(self.locals_cells_stack_w[argnum])
+ index += 1
def getclosure(self):
return None
- def _setcellvars(self, cellvars):
- ncellvars = len(self.pycode.co_cellvars)
- if len(cellvars) != ncellvars:
- raise OperationError(self.space.w_TypeError,
- self.space.wrap("bad cellvars"))
- self.cells[:ncellvars] = cellvars
-
def fget_code(self, space):
return space.wrap(self.getcode())
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -485,7 +485,7 @@
def LOAD_FAST(self, varindex, next_instr):
# access a local variable directly
- w_value = self.locals_stack_w[varindex]
+ w_value = self.locals_cells_stack_w[varindex]
if w_value is None:
self._load_fast_failed(varindex)
self.pushvalue(w_value)
@@ -505,7 +505,7 @@
def STORE_FAST(self, varindex, next_instr):
w_newvalue = self.popvalue()
assert w_newvalue is not None
- self.locals_stack_w[varindex] = w_newvalue
+ self.locals_cells_stack_w[varindex] = w_newvalue
def getfreevarname(self, index):
freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
@@ -517,7 +517,7 @@
def LOAD_DEREF(self, varindex, next_instr):
# nested scopes: access a variable through its cell object
- cell = self.cells[varindex]
+ cell = self._getcell(varindex)
try:
w_value = cell.get()
except ValueError:
@@ -536,12 +536,12 @@
def STORE_DEREF(self, varindex, next_instr):
# nested scopes: access a variable through its cell object
w_newvalue = self.popvalue()
- cell = self.cells[varindex]
+ cell = self._getcell(varindex)
cell.set(w_newvalue)
def LOAD_CLOSURE(self, varindex, next_instr):
# nested scopes: access the cell object
- cell = self.cells[varindex]
+ cell = self._getcell(varindex)
w_value = self.space.wrap(cell)
self.pushvalue(w_value)
@@ -911,12 +911,12 @@
LOAD_GLOBAL._always_inline_ = True
def DELETE_FAST(self, varindex, next_instr):
- if self.locals_stack_w[varindex] is None:
+ if self.locals_cells_stack_w[varindex] is None:
varname = self.getlocalvarname(varindex)
raise oefmt(self.space.w_UnboundLocalError,
"local variable '%s' referenced before assignment",
varname)
- self.locals_stack_w[varindex] = None
+ self.locals_cells_stack_w[varindex] = None
def BUILD_TUPLE(self, itemcount, next_instr):
items = self.popvalues(itemcount)
diff --git a/pypy/module/_continuation/interp_continuation.py
b/pypy/module/_continuation/interp_continuation.py
--- a/pypy/module/_continuation/interp_continuation.py
+++ b/pypy/module/_continuation/interp_continuation.py
@@ -35,10 +35,10 @@
w_args, w_kwds = __args__.topacked()
bottomframe = space.createframe(get_entrypoint_pycode(space),
get_w_module_dict(space), None)
- bottomframe.locals_stack_w[0] = space.wrap(self)
- bottomframe.locals_stack_w[1] = w_callable
- bottomframe.locals_stack_w[2] = w_args
- bottomframe.locals_stack_w[3] = w_kwds
+ bottomframe.locals_cells_stack_w[0] = space.wrap(self)
+ bottomframe.locals_cells_stack_w[1] = w_callable
+ bottomframe.locals_cells_stack_w[2] = w_args
+ bottomframe.locals_cells_stack_w[3] = w_kwds
bottomframe.last_exception = get_cleared_operation_error(space)
self.bottomframe = bottomframe
#
diff --git a/pypy/module/pypyjit/interp_jit.py
b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -19,8 +19,8 @@
PyFrame._virtualizable_ = ['last_instr', 'pycode',
- 'valuestackdepth', 'locals_stack_w[*]',
- 'cells[*]',
+ 'valuestackdepth',
+ 'locals_cells_stack_w[*]',
'debugdata',
'last_exception',
'lastblock',
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit