Author: Remi Meier <remi.me...@gmail.com> Branch: stmgc-c8 Changeset: r82418:76de496c32c4 Date: 2016-02-23 10:56 +0100 http://bitbucket.org/pypy/pypy/changeset/76de496c32c4/
Log: Next merge with default diff too long, truncating to 2000 out of 2927 lines diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -39,5 +39,5 @@ # runs. We cannot get their original value either: # http://lists.gnu.org/archive/html/help-make/2010-08/msg00106.html -cffi_imports: +cffi_imports: pypy-c PYTHONPATH=. ./pypy-c pypy/tool/build_cffi_imports.py diff --git a/lib-python/2.7/sysconfig.py b/lib-python/2.7/sysconfig.py --- a/lib-python/2.7/sysconfig.py +++ b/lib-python/2.7/sysconfig.py @@ -524,6 +524,13 @@ import _osx_support _osx_support.customize_config_vars(_CONFIG_VARS) + # PyPy: + import imp + for suffix, mode, type_ in imp.get_suffixes(): + if type_ == imp.C_EXTENSION: + _CONFIG_VARS['SOABI'] = suffix.split('.')[1] + break + if args: vals = [] for name in args: diff --git a/lib_pypy/cPickle.py b/lib_pypy/cPickle.py --- a/lib_pypy/cPickle.py +++ b/lib_pypy/cPickle.py @@ -167,7 +167,11 @@ try: key = ord(self.read(1)) while key != STOP: - self.dispatch[key](self) + try: + meth = self.dispatch[key] + except KeyError: + raise UnpicklingError("invalid load key, %r." % chr(key)) + meth(self) key = ord(self.read(1)) except TypeError: if self.read(1) == '': @@ -559,6 +563,7 @@ def decode_long(data): r"""Decode a long from a two's complement little-endian binary string. + This is overriden on PyPy by a RPython version that has linear complexity. >>> decode_long('') 0L @@ -592,6 +597,11 @@ n -= 1L << (nbytes << 3) return n +try: + from __pypy__ import decode_long +except ImportError: + pass + def load(f): return Unpickler(f).load() diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -103,3 +103,10 @@ Fix the cryptic exception message when attempting to use extended slicing in rpython. Was issue #2211. + +.. branch: ec-keepalive + +Optimize the case where, in a new C-created thread, we keep invoking +short-running Python callbacks. (CFFI on CPython has a hack to achieve +the same result.) This can also be seen as a bug fix: previously, +thread-local objects would be reset between two such calls. diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -9,8 +9,8 @@ class Code(W_Root): """A code is a compiled version of some source code. Abstract base class.""" - _immutable_ = True hidden_applevel = False + _immutable_fields_ = ['co_name', 'fast_natural_arity', 'hidden_applevel'] # n >= 0 : arity # FLATPYCALL = 0x100 diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -56,10 +56,12 @@ class PyCode(eval.Code): "CPython-style code objects." - _immutable_ = True - _immutable_fields_ = ["co_consts_w[*]", "co_names_w[*]", "co_varnames[*]", - "co_freevars[*]", "co_cellvars[*]", - "_args_as_cellvars[*]"] + _immutable_fields_ = ["_signature", "co_argcount", "co_cellvars[*]", + "co_code", "co_consts_w[*]", "co_filename", + "co_firstlineno", "co_flags", "co_freevars[*]", + "co_lnotab", "co_names_w[*]", "co_nlocals", + "co_stacksize", "co_varnames[*]", + "_args_as_cellvars[*]", "w_globals?"] def __init__(self, space, argcount, nlocals, stacksize, flags, code, consts, names, varnames, filename, @@ -84,6 +86,10 @@ self.co_name = name self.co_firstlineno = firstlineno self.co_lnotab = lnotab + # store the first globals object that the code object is run in in + # here. if a frame is run in that globals object, it does not need to + # store it at all + self.w_globals = None self.hidden_applevel = hidden_applevel self.magic = magic self._signature = cpython_code_signature(self) @@ -91,6 +97,14 @@ self._init_ready() self.new_code_hook() + def frame_stores_global(self, w_globals): + if self.w_globals is None: + self.w_globals = w_globals + return False + if self.w_globals is w_globals: + return False + return True + def new_code_hook(self): code_hook = self.space.fromcache(CodeHookCache)._code_hook if code_hook is not None: @@ -139,7 +153,6 @@ from pypy.objspace.std.mapdict import init_mapdict_cache init_mapdict_cache(self) - def _init_ready(self): "This is a hook for the vmprof module, which overrides this method." @@ -381,7 +394,6 @@ code = space.allocate_instance(PyCode, w_subtype) PyCode.__init__(code, space, argcount, nlocals, stacksize, flags, codestring, consts_w[:], names, varnames, filename, name, firstlineno, lnotab, freevars, cellvars, magic=magic) - return space.wrap(code) def descr__reduce__(self, space): diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -36,6 +36,7 @@ def __init__(self, pycode): self.f_lineno = pycode.co_firstlineno + self.w_globals = pycode.w_globals class PyFrame(W_Root): """Represents a frame for a regular Python function @@ -71,7 +72,6 @@ escaped = False # see mark_as_escaped() debugdata = None - w_globals = None pycode = None # code object executed by that frame locals_cells_stack_w = None # the list of all locals, cells and the valuestack valuestackdepth = 0 # number of items on valuestack @@ -94,8 +94,9 @@ self = hint(self, access_directly=True, fresh_virtualizable=True) assert isinstance(code, pycode.PyCode) self.space = space - self.w_globals = w_globals self.pycode = code + if code.frame_stores_global(w_globals): + self.getorcreatedebug().w_globals = w_globals ncellvars = len(code.co_cellvars) nfreevars = len(code.co_freevars) size = code.co_nlocals + ncellvars + nfreevars + code.co_stacksize @@ -120,6 +121,12 @@ self.debugdata = FrameDebugData(self.pycode) return self.debugdata + def get_w_globals(self): + debugdata = self.getdebug() + if debugdata is not None: + return debugdata.w_globals + return jit.promote(self.pycode).w_globals + def get_w_f_trace(self): d = self.getdebug() if d is None: @@ -205,8 +212,9 @@ if flags & pycode.CO_NEWLOCALS: self.getorcreatedebug().w_locals = self.space.newdict(module=True) else: - assert self.w_globals is not None - self.getorcreatedebug().w_locals = self.w_globals + w_globals = self.get_w_globals() + assert w_globals is not None + self.getorcreatedebug().w_locals = w_globals ncellvars = len(code.co_cellvars) nfreevars = len(code.co_freevars) @@ -453,7 +461,7 @@ w_blockstack, w_exc_value, # last_exception w_tb, # - self.w_globals, + self.get_w_globals(), w(self.last_instr), w(self.frame_finished_execution), w(f_lineno), @@ -662,6 +670,11 @@ def fget_getdictscope(self, space): return self.getdictscope() + def fget_w_globals(self, space): + # bit silly, but GetSetProperty passes a space + return self.get_w_globals() + + ### line numbers ### def fget_f_lineno(self, space): diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -843,7 +843,7 @@ w_bases = self.popvalue() w_name = self.popvalue() w_metaclass = find_metaclass(self.space, w_bases, - w_methodsdict, self.w_globals, + w_methodsdict, self.get_w_globals(), self.space.wrap(self.get_builtin())) w_newclass = self.space.call_function(w_metaclass, w_name, w_bases, w_methodsdict) @@ -887,14 +887,14 @@ def STORE_GLOBAL(self, nameindex, next_instr): varname = self.getname_u(nameindex) w_newvalue = self.popvalue() - self.space.setitem_str(self.w_globals, varname, w_newvalue) + self.space.setitem_str(self.get_w_globals(), varname, w_newvalue) def DELETE_GLOBAL(self, nameindex, next_instr): w_varname = self.getname_w(nameindex) - self.space.delitem(self.w_globals, w_varname) + self.space.delitem(self.get_w_globals(), w_varname) def LOAD_NAME(self, nameindex, next_instr): - if self.getorcreatedebug().w_locals is not self.w_globals: + if self.getorcreatedebug().w_locals is not self.get_w_globals(): varname = self.getname_u(nameindex) w_value = self.space.finditem_str(self.getorcreatedebug().w_locals, varname) @@ -904,7 +904,7 @@ self.LOAD_GLOBAL(nameindex, next_instr) # fall-back def _load_global(self, varname): - w_value = self.space.finditem_str(self.w_globals, varname) + w_value = self.space.finditem_str(self.get_w_globals(), varname) if w_value is None: # not in the globals, now look in the built-ins w_value = self.get_builtin().getdictvalue(self.space, varname) @@ -1035,7 +1035,7 @@ if w_locals is None: # CPython does this w_locals = space.w_None w_modulename = space.wrap(modulename) - w_globals = self.w_globals + w_globals = self.get_w_globals() if w_flag is None: w_obj = space.call_function(w_import, w_modulename, w_globals, w_locals, w_fromlist) @@ -1243,7 +1243,7 @@ w_codeobj = self.popvalue() codeobj = self.space.interp_w(PyCode, w_codeobj) defaultarguments = self.popvalues(numdefaults) - fn = function.Function(self.space, codeobj, self.w_globals, + fn = function.Function(self.space, codeobj, self.get_w_globals(), defaultarguments) self.pushvalue(self.space.wrap(fn)) @@ -1255,7 +1255,7 @@ freevars = [self.space.interp_w(Cell, cell) for cell in self.space.fixedview(w_freevarstuple)] defaultarguments = self.popvalues(numdefaults) - fn = function.Function(self.space, codeobj, self.w_globals, + fn = function.Function(self.space, codeobj, self.get_w_globals(), defaultarguments, freevars) self.pushvalue(self.space.wrap(fn)) diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py --- a/pypy/interpreter/test/test_pyframe.py +++ b/pypy/interpreter/test/test_pyframe.py @@ -34,6 +34,7 @@ import sys f = sys._getframe() assert f.f_globals is globals() + raises(TypeError, "f.f_globals = globals()") def test_f_builtins(self): import sys, __builtin__ diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -772,7 +772,7 @@ f_restricted = GetSetProperty(PyFrame.fget_f_restricted), f_code = GetSetProperty(PyFrame.fget_code), f_locals = GetSetProperty(PyFrame.fget_getdictscope), - f_globals = interp_attrproperty_w('w_globals', cls=PyFrame), + f_globals = GetSetProperty(PyFrame.fget_w_globals), ) assert not PyFrame.typedef.acceptable_as_base_class # no __new__ diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py --- a/pypy/module/__builtin__/compiling.py +++ b/pypy/module/__builtin__/compiling.py @@ -93,7 +93,7 @@ if space.is_none(w_locals): w_locals = w_globals else: - w_globals = caller.w_globals + w_globals = caller.get_w_globals() if space.is_none(w_locals): w_locals = caller.getdictscope() elif space.is_none(w_locals): diff --git a/pypy/module/__builtin__/interp_inspect.py b/pypy/module/__builtin__/interp_inspect.py --- a/pypy/module/__builtin__/interp_inspect.py +++ b/pypy/module/__builtin__/interp_inspect.py @@ -2,7 +2,7 @@ def globals(space): "Return the dictionary containing the current scope's global variables." ec = space.getexecutioncontext() - return ec.gettopframe_nohidden().w_globals + return ec.gettopframe_nohidden().get_w_globals() def locals(space): """Return a dictionary containing the current scope's local variables. diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -93,7 +93,7 @@ Return the underlying strategy currently used by a dict, list or set object """ if isinstance(w_obj, W_DictMultiObject): - name = w_obj.strategy.__class__.__name__ + name = w_obj.get_strategy().__class__.__name__ elif isinstance(w_obj, W_ListObject): name = w_obj.strategy.__class__.__name__ elif isinstance(w_obj, W_BaseSetObject): diff --git a/pypy/module/_cffi_backend/cffi1_module.py b/pypy/module/_cffi_backend/cffi1_module.py --- a/pypy/module/_cffi_backend/cffi1_module.py +++ b/pypy/module/_cffi_backend/cffi1_module.py @@ -2,6 +2,7 @@ from pypy.interpreter.error import oefmt from pypy.interpreter.module import Module +from pypy.module import _cffi_backend from pypy.module._cffi_backend import parse_c_type from pypy.module._cffi_backend.ffi_obj import W_FFIObject from pypy.module._cffi_backend.lib_obj import W_LibObject @@ -27,8 +28,10 @@ version = rffi.cast(lltype.Signed, p[0]) if not (VERSION_MIN <= version <= VERSION_MAX): raise oefmt(space.w_ImportError, - "cffi extension module '%s' has unknown version %s", - name, hex(version)) + "cffi extension module '%s' uses an unknown version tag %s. " + "This module might need a more recent version of PyPy. " + "The current PyPy provides CFFI %s.", + name, hex(version), _cffi_backend.VERSION) src_ctx = rffi.cast(parse_c_type.PCTX, p[1]) ffi = W_FFIObject(space, src_ctx) 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 @@ -195,7 +195,7 @@ class SThread(StackletThread): def __init__(self, space, ec): - StackletThread.__init__(self, space.config) + StackletThread.__init__(self) self.space = space self.ec = ec # for unpickling diff --git a/pypy/module/_warnings/interp_warnings.py b/pypy/module/_warnings/interp_warnings.py --- a/pypy/module/_warnings/interp_warnings.py +++ b/pypy/module/_warnings/interp_warnings.py @@ -75,7 +75,7 @@ frame = ec.getnextframe_nohidden(frame) stacklevel -= 1 if frame: - w_globals = frame.w_globals + w_globals = frame.get_w_globals() lineno = frame.get_last_lineno() else: w_globals = space.sys.w_dict diff --git a/pypy/module/cpyext/eval.py b/pypy/module/cpyext/eval.py --- a/pypy/module/cpyext/eval.py +++ b/pypy/module/cpyext/eval.py @@ -30,7 +30,7 @@ currently executing.""" caller = space.getexecutioncontext().gettopframe_nohidden() if caller is not None: - w_globals = caller.w_globals + w_globals = caller.get_w_globals() w_builtins = space.getitem(w_globals, space.wrap('__builtins__')) if not space.isinstance_w(w_builtins, space.w_dict): w_builtins = w_builtins.getdict(space) @@ -54,7 +54,7 @@ caller = space.getexecutioncontext().gettopframe_nohidden() if caller is None: return None - return borrow_from(None, caller.w_globals) + return borrow_from(None, caller.get_w_globals()) @cpython_api([PyCodeObject, PyObject, PyObject], PyObject) def PyEval_EvalCode(space, w_code, w_globals, w_locals): diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py --- a/pypy/module/cpyext/frameobject.py +++ b/pypy/module/cpyext/frameobject.py @@ -34,7 +34,7 @@ frame = space.interp_w(PyFrame, w_obj) py_frame = rffi.cast(PyFrameObject, py_obj) py_frame.c_f_code = rffi.cast(PyCodeObject, make_ref(space, frame.pycode)) - py_frame.c_f_globals = make_ref(space, frame.w_globals) + py_frame.c_f_globals = make_ref(space, frame.get_w_globals()) rffi.setintfield(py_frame, 'c_f_lineno', frame.getorcreatedebug().f_lineno) @cpython_api([PyObject], lltype.Void, external=False) diff --git a/pypy/module/cpyext/import_.py b/pypy/module/cpyext/import_.py --- a/pypy/module/cpyext/import_.py +++ b/pypy/module/cpyext/import_.py @@ -20,7 +20,7 @@ caller = space.getexecutioncontext().gettopframe_nohidden() # Get the builtins from current globals if caller is not None: - w_globals = caller.w_globals + w_globals = caller.get_w_globals() w_builtin = space.getitem(w_globals, space.wrap('__builtins__')) else: # No globals -- use standard builtins, and fake globals diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py --- a/pypy/module/itertools/interp_itertools.py +++ b/pypy/module/itertools/interp_itertools.py @@ -372,7 +372,7 @@ def arg_int_w(self, w_obj, minimum, errormsg): space = self.space try: - result = space.int_w(w_obj) + result = space.int_w(space.int(w_obj)) # CPython allows floats as parameters except OperationError, e: if e.async(space): raise diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py --- a/pypy/module/itertools/test/test_itertools.py +++ b/pypy/module/itertools/test/test_itertools.py @@ -225,6 +225,12 @@ assert it.next() == x raises(StopIteration, it.next) + # CPython implementation allows floats + it = itertools.islice([1, 2, 3, 4, 5], 0.0, 3.0, 2.0) + for x in [1, 3]: + assert it.next() == x + raises(StopIteration, it.next) + it = itertools.islice([1, 2, 3], 0, None) for x in [1, 2, 3]: assert it.next() == x diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -534,7 +534,7 @@ log = self.run(f) loop, = log.loops_by_filename(self.filepath) call_ops = log.opnames(loop.ops_by_id('call')) - assert call_ops == ['force_token'] # it does not follow inlining + assert call_ops == ['guard_not_invalidated', 'force_token'] # it does not follow inlining # add_ops = log.opnames(loop.ops_by_id('add')) assert add_ops == ['int_add'] @@ -542,7 +542,8 @@ ops = log.opnames(loop.allops()) assert ops == [ # this is the actual loop - 'int_lt', 'guard_true', 'force_token', 'int_add', + 'int_lt', 'guard_true', + 'guard_not_invalidated?', 'force_token', 'int_add', # this is the signal checking stuff ] + SIGCHECK + [ 'jump' diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -72,8 +72,6 @@ # LOAD_GLOBAL of OFFSET ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL') assert log.opnames(ops) == ["guard_value", - "guard_value", - "getfield_gc_r", "guard_value", "guard_not_invalidated"] ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL') assert log.opnames(ops) == [] @@ -200,6 +198,7 @@ assert log.result == 1000 loop, = log.loops_by_id('call') assert loop.match_by_id('call', """ + guard_not_invalidated? i14 = force_token() i16 = force_token() """) @@ -222,7 +221,7 @@ loop, = log.loops_by_id('call') ops = log.opnames(loop.ops_by_id('call')) guards = [ops for ops in ops if ops.startswith('guard')] - assert guards == ["guard_no_overflow"] + assert guards == ["guard_not_invalidated", "guard_no_overflow"] def test_kwargs(self): # this is not a very precise test, could be improved @@ -281,6 +280,7 @@ assert log.result == 13000 loop0, = log.loops_by_id('g1') assert loop0.match_by_id('g1', """ + guard_not_invalidated? i20 = force_token() i22 = int_add_ovf(i8, 3) guard_no_overflow(descr=...) @@ -438,9 +438,6 @@ i22 = getfield_gc_pure_i(p12, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>) i24 = int_lt(i22, 5000) guard_true(i24, descr=...) - guard_value(p7, ConstPtr(ptr25), descr=...) - p26 = getfield_gc_r(p7, descr=<FieldP pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy .*>) - guard_value(p26, ConstPtr(ptr27), descr=...) guard_not_invalidated(descr=...) p29 = call_r(ConstClass(_ll_1_threadlocalref_get__Ptr_GcStruct_objectLlT_Signed), #, descr=<Callr . i EF=1 OS=5>) p30 = getfield_gc_r(p29, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>) @@ -472,6 +469,7 @@ i8 = getfield_gc_pure_i(p6, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>) i10 = int_lt(i8, 5000) guard_true(i10, descr=...) + guard_not_invalidated? i11 = force_token() i13 = int_add(i8, 1) --TICK-- diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py --- a/pypy/module/pypyjit/test_pypy_c/test_globals.py +++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py @@ -16,9 +16,5 @@ assert log.result == 500 loop, = log.loops_by_filename(self.filepath) assert loop.match_by_id("loadglobal", """ - p12 = getfield_gc_r(p10, descr=<FieldP .*W_DictMultiObject.inst_strategy .*>) - guard_value(p12, ConstPtr(ptr13), descr=...) guard_not_invalidated(descr=...) - p19 = getfield_gc_r(ConstPtr(p17), descr=<FieldP .*W_DictMultiObject.inst_strategy .*>) - guard_value(p19, ConstPtr(ptr20), descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -124,7 +124,7 @@ setfield_gc(ConstPtr(ptr39), i59, descr=...) i62 = int_lt(i61, 0) guard_false(i62, descr=...) - jump(p0, p1, p3, p6, p7, p12, i59, p18, i31, i59, p100, descr=...) + jump(..., descr=...) """) def test_mutate_class(self): @@ -183,7 +183,7 @@ setfield_gc(p77, ConstPtr(null), descr=...) setfield_gc(p77, ConstPtr(ptr42), descr=...) setfield_gc(ConstPtr(ptr69), p77, descr=...) - jump(p0, p1, p3, p6, p7, p12, i74, p20, p26, i33, p77, p100, descr=...) + jump(..., descr=...) """) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -145,9 +145,9 @@ i15 = int_lt(i10, i11) guard_true(i15, descr=...) i17 = int_add(i10, 1) - i18 = force_token() setfield_gc(p9, i17, descr=<.* .*W_XRangeIterator.inst_current .*>) guard_not_invalidated(descr=...) + i18 = force_token() i84 = int_sub(i14, 1) i21 = int_lt(i10, 0) guard_false(i21, descr=...) @@ -178,9 +178,9 @@ i16 = int_ge(i11, i12) guard_false(i16, descr=...) i20 = int_add(i11, 1) - i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) guard_not_invalidated? + i21 = force_token() i88 = int_sub(i9, 1) i25 = int_ge(i11, i9) guard_false(i25, descr=...) @@ -211,9 +211,9 @@ i17 = int_mul(i11, i14) i18 = int_add(i15, i17) i20 = int_add(i11, 1) - i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) guard_not_invalidated? + i21 = force_token() i95 = int_sub(i9, 1) i23 = int_lt(i18, 0) guard_false(i23, descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_weakref.py b/pypy/module/pypyjit/test_pypy_c/test_weakref.py --- a/pypy/module/pypyjit/test_pypy_c/test_weakref.py +++ b/pypy/module/pypyjit/test_pypy_c/test_weakref.py @@ -23,12 +23,8 @@ i60 = int_lt(i58, i31) guard_true(i60, descr=...) i61 = int_add(i58, 1) - p62 = getfield_gc_r(ConstPtr(ptr37), descr=<FieldP pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy \d+>) setfield_gc(p18, i61, descr=<FieldS pypy.module.__builtin__.functional.W_XRangeIterator.inst_current 8>) - guard_value(p62, ConstPtr(ptr39), descr=...) guard_not_invalidated(descr=...) - p64 = getfield_gc_r(ConstPtr(ptr40), descr=<FieldP pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy \d+>) - guard_value(p64, ConstPtr(ptr42), descr=...) p65 = getfield_gc_r(p14, descr=<FieldP pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst_map \d+>) guard_value(p65, ConstPtr(ptr45), descr=...) p66 = getfield_gc_r(p14, descr=<FieldP pypy.objspace.std.mapdict.W_ObjectObjectSize5.inst__value0 \d+>) diff --git a/pypy/module/test_lib_pypy/test_cPickle.py b/pypy/module/test_lib_pypy/test_cPickle.py --- a/pypy/module/test_lib_pypy/test_cPickle.py +++ b/pypy/module/test_lib_pypy/test_cPickle.py @@ -5,3 +5,7 @@ def test_stack_underflow(): py.test.raises(cPickle.UnpicklingError, cPickle.loads, "a string") + +def test_bad_key(): + e = py.test.raises(cPickle.UnpicklingError, cPickle.loads, "v") + assert str(e.value) == "invalid load key, 'v'." diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py --- a/pypy/objspace/std/celldict.py +++ b/pypy/objspace/std/celldict.py @@ -153,7 +153,7 @@ d_new = strategy.unerase(strategy.get_empty_storage()) for key, cell in d.iteritems(): d_new[_wrapkey(space, key)] = unwrap_cell(self.space, cell) - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = strategy.erase(d_new) def getiterkeys(self, w_dict): diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -42,6 +42,14 @@ class W_DictMultiObject(W_Root): + """ Abstract base class that does not store a strategy. """ + def get_strategy(self): + raise NotImplementedError("abstract method") + + def set_strategy(self, strategy): + raise NotImplementedError("abstract method") + + @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, strdict=False, @@ -52,6 +60,10 @@ # every module needs its own strategy, because the strategy stores # the version tag strategy = ModuleDictStrategy(space) + storage = strategy.get_empty_storage() + w_obj = space.allocate_instance(W_ModuleDictObject, space.w_dict) + W_ModuleDictObject.__init__(w_obj, space, strategy, storage) + return w_obj elif space.config.objspace.std.withmapdict and instance: from pypy.objspace.std.mapdict import MapDictStrategy strategy = space.fromcache(MapDictStrategy) @@ -68,18 +80,17 @@ w_type = space.w_dict storage = strategy.get_empty_storage() - w_obj = space.allocate_instance(W_DictMultiObject, w_type) - W_DictMultiObject.__init__(w_obj, space, strategy, storage) + w_obj = space.allocate_instance(W_DictObject, w_type) + W_DictObject.__init__(w_obj, space, strategy, storage) return w_obj - def __init__(self, space, strategy, storage): + def __init__(self, space, storage): self.space = space - self.strategy = strategy self.dstorage = storage def __repr__(self): """representation for debugging purposes""" - return "%s(%s)" % (self.__class__.__name__, self.strategy) + return "%s(%s)" % (self.__class__.__name__, self.get_strategy()) def unwrap(w_dict, space): result = {} @@ -101,7 +112,7 @@ self.setitem(w_k, w_v) def setitem_str(self, key, w_value): - self.strategy.setitem_str(self, key, w_value) + self.get_strategy().setitem_str(self, key, w_value) @staticmethod def descr_new(space, w_dicttype, __args__): @@ -261,8 +272,9 @@ def nondescr_reversed_dict(self, space): """Not exposed directly to app-level, but via __pypy__.reversed_dict(). """ - if self.strategy.has_iterreversed: - it = self.strategy.iterreversed(self) + strategy = self.get_strategy() + if strategy.has_iterreversed: + it = strategy.iterreversed(self) return W_DictMultiIterKeysObject(space, it) else: # fall-back @@ -337,6 +349,37 @@ init_or_update(space, self, __args__, 'dict.update') +class W_DictObject(W_DictMultiObject): + """ a regular dict object """ + def __init__(self, space, strategy, storage): + W_DictMultiObject.__init__(self, space, storage) + self.dstrategy = strategy + + def get_strategy(self): + return self.dstrategy + + def set_strategy(self, strategy): + self.dstrategy = strategy + + +class W_ModuleDictObject(W_DictMultiObject): + """ a dict object for a module, that is not expected to change. It stores + the strategy as a quasi-immutable field. """ + _immutable_fields_ = ['mstrategy?'] + + def __init__(self, space, strategy, storage): + W_DictMultiObject.__init__(self, space, storage) + self.mstrategy = strategy + + def get_strategy(self): + return self.mstrategy + + def set_strategy(self, strategy): + self.mstrategy = strategy + + + + def _add_indirections(): dict_methods = "getitem getitem_str setitem setdefault \ popitem delitem clear \ @@ -347,7 +390,7 @@ def make_method(method): def f(self, *args): - return getattr(self.strategy, method)(self, *args) + return getattr(self.get_strategy(), method)(self, *args) f.func_name = method return f @@ -490,7 +533,7 @@ def clear(self, w_dict): strategy = self.space.fromcache(EmptyDictStrategy) storage = strategy.get_empty_storage() - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = storage def listview_bytes(self, w_dict): @@ -556,32 +599,32 @@ def switch_to_bytes_strategy(self, w_dict): strategy = self.space.fromcache(BytesDictStrategy) storage = strategy.get_empty_storage() - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = storage def switch_to_unicode_strategy(self, w_dict): strategy = self.space.fromcache(UnicodeDictStrategy) storage = strategy.get_empty_storage() - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = storage def switch_to_int_strategy(self, w_dict): strategy = self.space.fromcache(IntDictStrategy) storage = strategy.get_empty_storage() - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = storage def switch_to_identity_strategy(self, w_dict): from pypy.objspace.std.identitydict import IdentityDictStrategy strategy = self.space.fromcache(IdentityDictStrategy) storage = strategy.get_empty_storage() - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = storage def switch_to_object_strategy(self, w_dict): strategy = self.space.fromcache(ObjectDictStrategy) storage = strategy.get_empty_storage() - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = storage def getitem(self, w_dict, w_key): @@ -662,7 +705,7 @@ if self.pos < self.len: result = getattr(self, 'next_' + TP + '_entry')() self.pos += 1 - if self.strategy is self.dictimplementation.strategy: + if self.strategy is self.dictimplementation.get_strategy(): return result # common case else: # waaa, obscure case: the strategy changed, but not the @@ -804,7 +847,7 @@ else: return # w_dict is completely empty, nothing to do count = w_dict.length() - 1 - w_updatedict.strategy.prepare_update(w_updatedict, count) + w_updatedict.get_strategy().prepare_update(w_updatedict, count) # If the strategy is still different, continue the slow way if not same_strategy(self, w_updatedict): for key, value, keyhash in iteritemsh: @@ -825,7 +868,7 @@ def same_strategy(self, w_otherdict): return (setitem_untyped is not None and - w_otherdict.strategy is self) + w_otherdict.get_strategy() is self) dictimpl.iterkeys = iterkeys dictimpl.itervalues = itervalues @@ -934,7 +977,7 @@ d_new = strategy.unerase(strategy.get_empty_storage()) for key, value in d.iteritems(): d_new[self.wrap(key)] = value - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = strategy.erase(d_new) # --------------- iterator interface ----------------- @@ -1178,7 +1221,7 @@ def update1_dict_dict(space, w_dict, w_data): - w_data.strategy.rev_update1_dict_dict(w_data, w_dict) + w_data.get_strategy().rev_update1_dict_dict(w_data, w_dict) def update1_pairs(space, w_dict, data_w): diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py --- a/pypy/objspace/std/kwargsdict.py +++ b/pypy/objspace/std/kwargsdict.py @@ -18,7 +18,7 @@ def switch_to_bytes_strategy(self, w_dict): strategy = self.space.fromcache(KwargsDictStrategy) storage = strategy.get_empty_storage() - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = storage @@ -142,7 +142,7 @@ d_new = strategy.unerase(strategy.get_empty_storage()) for i in range(len(keys)): d_new[self.wrap(keys[i])] = values_w[i] - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = strategy.erase(d_new) def switch_to_bytes_strategy(self, w_dict): @@ -152,7 +152,7 @@ d_new = strategy.unerase(storage) for i in range(len(keys)): d_new[keys[i]] = values_w[i] - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = storage def view_as_kwargs(self, w_dict): diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -6,7 +6,8 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.dictmultiobject import ( W_DictMultiObject, DictStrategy, ObjectDictStrategy, BaseKeyIterator, - BaseValueIterator, BaseItemIterator, _never_equal_to_string + BaseValueIterator, BaseItemIterator, _never_equal_to_string, + W_DictObject, ) from pypy.objspace.std.typeobject import MutableCell from rpython.rlib.objectmodel import we_are_translated @@ -416,7 +417,7 @@ strategy = space.fromcache(MapDictStrategy) storage = strategy.erase(self) - w_dict = W_DictMultiObject(space, strategy, storage) + w_dict = W_DictObject(space, strategy, storage) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag return w_dict @@ -431,8 +432,8 @@ # new dict. If the old dict was using the MapDictStrategy, we # have to force it now: otherwise it would remain an empty # shell that continues to delegate to 'self'. - if type(w_olddict.strategy) is MapDictStrategy: - w_olddict.strategy.switch_to_object_strategy(w_olddict) + if type(w_olddict.get_strategy()) is MapDictStrategy: + w_olddict.get_strategy().switch_to_object_strategy(w_olddict) flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) assert flag @@ -650,7 +651,7 @@ w_obj = self.unerase(w_dict.dstorage) strategy = self.space.fromcache(ObjectDictStrategy) dict_w = strategy.unerase(strategy.get_empty_storage()) - w_dict.strategy = strategy + w_dict.set_strategy(strategy) w_dict.dstorage = strategy.erase(dict_w) assert w_obj.getdict(self.space) is w_dict or w_obj._get_mapdict_map().terminator.w_cls is None materialize_r_dict(self.space, w_obj, dict_w) @@ -759,7 +760,7 @@ def next_key_entry(self): implementation = self.dictimplementation - assert isinstance(implementation.strategy, MapDictStrategy) + assert isinstance(implementation.get_strategy(), MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None if self.curr_map: @@ -781,7 +782,7 @@ def next_value_entry(self): implementation = self.dictimplementation - assert isinstance(implementation.strategy, MapDictStrategy) + assert isinstance(implementation.get_strategy(), MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None if self.curr_map: @@ -802,7 +803,7 @@ def next_item_entry(self): implementation = self.dictimplementation - assert isinstance(implementation.strategy, MapDictStrategy) + assert isinstance(implementation.get_strategy(), MapDictStrategy) if self.orig_map is not self.w_obj._get_mapdict_map(): return None, None if self.curr_map: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -18,7 +18,7 @@ from pypy.objspace.std.bytearrayobject import W_BytearrayObject from pypy.objspace.std.bytesobject import W_AbstractBytesObject, W_BytesObject, wrapstr from pypy.objspace.std.complexobject import W_ComplexObject -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictMultiObject, W_DictObject from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.intobject import W_IntObject, setup_prebuilt, wrapint from pypy.objspace.std.iterobject import W_AbstractSeqIterObject, W_SeqIterObject @@ -439,7 +439,7 @@ # and isinstance() for others. See test_listobject.test_uses_custom... if type(w_obj) is W_ListObject: return w_obj.getitems_bytes() - if type(w_obj) is W_DictMultiObject: + if type(w_obj) is W_DictObject: return w_obj.listview_bytes() if type(w_obj) is W_SetObject or type(w_obj) is W_FrozensetObject: return w_obj.listview_bytes() @@ -454,7 +454,7 @@ # and isinstance() for others. See test_listobject.test_uses_custom... if type(w_obj) is W_ListObject: return w_obj.getitems_unicode() - if type(w_obj) is W_DictMultiObject: + if type(w_obj) is W_DictObject: return w_obj.listview_unicode() if type(w_obj) is W_SetObject or type(w_obj) is W_FrozensetObject: return w_obj.listview_unicode() @@ -467,7 +467,7 @@ def listview_int(self, w_obj): if type(w_obj) is W_ListObject: return w_obj.getitems_int() - if type(w_obj) is W_DictMultiObject: + if type(w_obj) is W_DictObject: return w_obj.listview_int() if type(w_obj) is W_SetObject or type(w_obj) is W_FrozensetObject: return w_obj.listview_int() @@ -485,7 +485,7 @@ return None def view_as_kwargs(self, w_dict): - if type(w_dict) is W_DictMultiObject: + if type(w_dict) is W_DictObject: return w_dict.view_as_kwargs() return (None, None) diff --git a/pypy/objspace/std/test/test_celldict.py b/pypy/objspace/std/test/test_celldict.py --- a/pypy/objspace/std/test/test_celldict.py +++ b/pypy/objspace/std/test/test_celldict.py @@ -1,7 +1,7 @@ import py from pypy.objspace.std.celldict import ModuleDictStrategy -from pypy.objspace.std.dictmultiobject import W_DictMultiObject +from pypy.objspace.std.dictmultiobject import W_DictObject, W_ModuleDictObject from pypy.objspace.std.test.test_dictmultiobject import ( BaseTestRDictImplementation, BaseTestDevolvedDictImplementation, FakeSpace, FakeString) @@ -14,7 +14,7 @@ def test_basic_property_cells(self): strategy = ModuleDictStrategy(space) storage = strategy.get_empty_storage() - d = W_DictMultiObject(space, strategy, storage) + d = W_ModuleDictObject(space, strategy, storage) v1 = strategy.version key = "a" @@ -23,30 +23,30 @@ v2 = strategy.version assert v1 is not v2 assert d.getitem(w_key) == 1 - assert d.strategy.getdictvalue_no_unwrapping(d, key) == 1 + assert d.get_strategy().getdictvalue_no_unwrapping(d, key) == 1 d.setitem(w_key, 2) v3 = strategy.version assert v2 is not v3 assert d.getitem(w_key) == 2 - assert d.strategy.getdictvalue_no_unwrapping(d, key).w_value == 2 + assert d.get_strategy().getdictvalue_no_unwrapping(d, key).w_value == 2 d.setitem(w_key, 3) v4 = strategy.version assert v3 is v4 assert d.getitem(w_key) == 3 - assert d.strategy.getdictvalue_no_unwrapping(d, key).w_value == 3 + assert d.get_strategy().getdictvalue_no_unwrapping(d, key).w_value == 3 d.delitem(w_key) v5 = strategy.version assert v5 is not v4 assert d.getitem(w_key) is None - assert d.strategy.getdictvalue_no_unwrapping(d, key) is None + assert d.get_strategy().getdictvalue_no_unwrapping(d, key) is None def test_same_key_set_twice(self): strategy = ModuleDictStrategy(space) storage = strategy.get_empty_storage() - d = W_DictMultiObject(space, strategy, storage) + d = W_ModuleDictObject(space, strategy, storage) v1 = strategy.version x = object() @@ -134,7 +134,7 @@ py.test.skip("__repr__ doesn't work on appdirect") strategy = ModuleDictStrategy(cls.space) storage = strategy.get_empty_storage() - cls.w_d = W_DictMultiObject(cls.space, strategy, storage) + cls.w_d = W_ModuleDictObject(cls.space, strategy, storage) def test_popitem(self): import __pypy__ diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -2,14 +2,14 @@ import py from pypy.objspace.std.dictmultiobject import (W_DictMultiObject, - BytesDictStrategy, ObjectDictStrategy) + W_DictObject, BytesDictStrategy, ObjectDictStrategy) class TestW_DictObject(object): def test_empty(self): d = self.space.newdict() assert not self.space.is_true(d) - assert type(d.strategy) is not ObjectDictStrategy + assert type(d.get_strategy()) is not ObjectDictStrategy def test_nonempty(self): space = self.space @@ -1050,7 +1050,7 @@ return l def newlist_bytes(self, l): return l - DictObjectCls = W_DictMultiObject + DictObjectCls = W_DictObject def type(self, w_obj): if isinstance(w_obj, FakeString): return str @@ -1076,7 +1076,7 @@ return tuple(l) def newdict(self, module=False, instance=False): - return W_DictMultiObject.allocate_and_init_instance( + return W_DictObject.allocate_and_init_instance( self, module=module, instance=instance) def view_as_kwargs(self, w_d): @@ -1105,7 +1105,7 @@ w_float = float StringObjectCls = FakeString UnicodeObjectCls = FakeUnicode - w_dict = W_DictMultiObject + w_dict = W_DictObject iter = iter fixedview = list listview = list @@ -1149,8 +1149,8 @@ def get_impl(self): strategy = self.StrategyClass(self.fakespace) storage = strategy.get_empty_storage() - w_dict = self.fakespace.allocate_instance(W_DictMultiObject, None) - W_DictMultiObject.__init__(w_dict, self.fakespace, strategy, storage) + w_dict = self.fakespace.allocate_instance(W_DictObject, None) + W_DictObject.__init__(w_dict, self.fakespace, strategy, storage) return w_dict def fill_impl(self): @@ -1159,7 +1159,7 @@ def check_not_devolved(self): #XXX check if strategy changed!? - assert type(self.impl.strategy) is self.StrategyClass + assert type(self.impl.get_strategy()) is self.StrategyClass #assert self.impl.r_dict_content is None def test_popitem(self): @@ -1246,7 +1246,7 @@ for x in xrange(100): impl.setitem(self.fakespace.str_w(str(x)), x) impl.setitem(x, x) - assert type(impl.strategy) is ObjectDictStrategy + assert type(impl.get_strategy()) is ObjectDictStrategy def test_setdefault_fast(self): on_pypy = "__pypy__" in sys.builtin_module_names @@ -1308,7 +1308,7 @@ class BaseTestDevolvedDictImplementation(BaseTestRDictImplementation): def fill_impl(self): BaseTestRDictImplementation.fill_impl(self) - self.impl.strategy.switch_to_object_strategy(self.impl) + self.impl.get_strategy().switch_to_object_strategy(self.impl) def check_not_devolved(self): pass @@ -1320,5 +1320,5 @@ def test_module_uses_strdict(): fakespace = FakeSpace() d = fakespace.newdict(module=True) - assert type(d.strategy) is BytesDictStrategy + assert type(d.get_strategy()) is BytesDictStrategy diff --git a/pypy/objspace/std/test/test_kwargsdict.py b/pypy/objspace/std/test/test_kwargsdict.py --- a/pypy/objspace/std/test/test_kwargsdict.py +++ b/pypy/objspace/std/test/test_kwargsdict.py @@ -1,5 +1,5 @@ import py -from pypy.objspace.std.test.test_dictmultiobject import FakeSpace, W_DictMultiObject +from pypy.objspace.std.test.test_dictmultiobject import FakeSpace, W_DictObject from pypy.objspace.std.kwargsdict import * space = FakeSpace() @@ -9,7 +9,7 @@ keys = ["a", "b", "c"] values = [1, 2, 3] storage = strategy.erase((keys, values)) - d = W_DictMultiObject(space, strategy, storage) + d = W_DictObject(space, strategy, storage) assert d.getitem_str("a") == 1 assert d.getitem_str("b") == 2 assert d.getitem_str("c") == 3 @@ -23,7 +23,7 @@ keys = ["a", "b", "c"] values = [1, 2, 3] storage = strategy.erase((keys, values)) - d = W_DictMultiObject(space, strategy, storage) + d = W_DictObject(space, strategy, storage) assert d.getitem_str("a") == 1 assert d.getitem_str("b") == 2 assert d.getitem_str("c") == 3 @@ -52,7 +52,7 @@ keys = ["a", "b", "c"] values = [1, 2, 3] storage = strategy.erase((keys, values)) - d = W_DictMultiObject(space, strategy, storage) + d = W_DictObject(space, strategy, storage) assert d.getitem_str("a") == 1 assert d.getitem_str("b") == 2 assert d.getitem_str("c") == 3 @@ -69,11 +69,11 @@ def test_limit_size(): storage = strategy.get_empty_storage() - d = W_DictMultiObject(space, strategy, storage) + d = W_DictObject(space, strategy, storage) for i in range(100): assert d.setitem_str("d%s" % i, 4) is None - assert d.strategy is not strategy - assert "BytesDictStrategy" == d.strategy.__class__.__name__ + assert d.get_strategy() is not strategy + assert "BytesDictStrategy" == d.get_strategy().__class__.__name__ def test_keys_doesnt_wrap(): space = FakeSpace() @@ -82,7 +82,7 @@ keys = ["a", "b", "c"] values = [1, 2, 3] storage = strategy.erase((keys, values)) - d = W_DictMultiObject(space, strategy, storage) + d = W_DictObject(space, strategy, storage) w_l = d.w_keys() # does not crash def test_view_as_kwargs(): @@ -91,26 +91,27 @@ keys = ["a", "b", "c"] values = [1, 2, 3] storage = strategy.erase((keys, values)) - d = W_DictMultiObject(space, strategy, storage) + d = W_DictObject(space, strategy, storage) assert (space.view_as_kwargs(d) == keys, values) strategy = EmptyDictStrategy(space) storage = strategy.get_empty_storage() - d = W_DictMultiObject(space, strategy, storage) + d = W_DictObject(space, strategy, storage) assert (space.view_as_kwargs(d) == [], []) def test_from_empty_to_kwargs(): strategy = EmptyKwargsDictStrategy(space) storage = strategy.get_empty_storage() - d = W_DictMultiObject(space, strategy, storage) + d = W_DictObject(space, strategy, storage) d.setitem_str("a", 3) - assert isinstance(d.strategy, KwargsDictStrategy) + assert isinstance(d.get_strategy(), KwargsDictStrategy) from pypy.objspace.std.test.test_dictmultiobject import BaseTestRDictImplementation, BaseTestDevolvedDictImplementation def get_impl(self): storage = strategy.erase(([], [])) - return W_DictMultiObject(space, strategy, storage) + return W_DictObject(space, strategy, storage) + class TestKwargsDictImplementation(BaseTestRDictImplementation): StrategyClass = KwargsDictStrategy get_impl = get_impl diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -1,4 +1,4 @@ -from pypy.objspace.std.test.test_dictmultiobject import FakeSpace, W_DictMultiObject +from pypy.objspace.std.test.test_dictmultiobject import FakeSpace, W_DictObject from pypy.objspace.std.mapdict import * class Config: @@ -309,7 +309,7 @@ obj.setdictvalue(space, "c", 7) assert obj.storage == [50, 60, 70, 5, 6, 7] - class FakeDict(W_DictMultiObject): + class FakeDict(W_DictObject): def __init__(self, d): self.dstorage = d @@ -368,7 +368,7 @@ def devolve_dict(space, obj): w_d = obj.getdict(space) - w_d.strategy.switch_to_object_strategy(w_d) + w_d.get_strategy().switch_to_object_strategy(w_d) def test_get_setdictvalue_after_devolve(): cls = Class() @@ -1131,7 +1131,7 @@ def test_newdict_instance(): w_dict = space.newdict(instance=True) - assert type(w_dict.strategy) is MapDictStrategy + assert type(w_dict.get_strategy()) is MapDictStrategy class TestMapDictImplementationUsingnewdict(BaseTestRDictImplementation): StrategyClass = MapDictStrategy diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -483,12 +483,12 @@ def getdict(w_self, space): # returning a dict-proxy! from pypy.objspace.std.dictproxyobject import DictProxyStrategy - from pypy.objspace.std.dictmultiobject import W_DictMultiObject + from pypy.objspace.std.dictmultiobject import W_DictObject if w_self.lazyloaders: w_self._cleanup_() # force un-lazification strategy = space.fromcache(DictProxyStrategy) storage = strategy.erase(w_self) - return W_DictMultiObject(space, strategy, storage) + return W_DictObject(space, strategy, storage) def is_heaptype(w_self): return w_self.flag_heaptype @@ -1144,7 +1144,7 @@ space = w_self.space caller = space.getexecutioncontext().gettopframe_nohidden() if caller is not None: - w_globals = caller.w_globals + w_globals = caller.get_w_globals() w_name = space.finditem(w_globals, space.wrap('__name__')) if w_name is not None: w_self.dict_w['__module__'] = w_name diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -63,7 +63,7 @@ for key, w_value in vars.items(): space.setitem(self.w_locals, space.wrap(key), w_value) if isinstance(code, str): - return space.eval(code, self.w_globals, self.w_locals) + return space.eval(code, self.get_w_globals(), self.w_locals) pyc = pycode.PyCode._from_code(space, code) return pyc.exec_host_bytecode(self.w_globals, self.w_locals) exec_ = eval @@ -248,7 +248,7 @@ #if filename.endswith("pyc"): # filename = filename[:-1] try: - space.exec_(str(source), frame.w_globals, w_locals, + space.exec_(str(source), frame.get_w_globals(), w_locals, filename=filename) except OperationError, e: if e.match(space, w_ExpectedException): diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py --- a/rpython/jit/backend/llgraph/runner.py +++ b/rpython/jit/backend/llgraph/runner.py @@ -730,7 +730,8 @@ def bh_gc_load_indexed_f(self, struct, index, scale, base_ofs, bytes): if bytes != 8: raise Exception("gc_load_indexed_f is only for 'double'!") - return llop.gc_load_indexed(rffi.DOUBLE, struct, index, scale, base_ofs) + return llop.gc_load_indexed(longlong.FLOATSTORAGE, + struct, index, scale, base_ofs) def bh_increment_debug_counter(self, addr): p = rffi.cast(rffi.CArrayPtr(lltype.Signed), addr) diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py --- a/rpython/jit/codewriter/effectinfo.py +++ b/rpython/jit/codewriter/effectinfo.py @@ -338,15 +338,11 @@ return op.opname == 'jit_force_quasi_immutable' class RandomEffectsAnalyzer(BoolGraphAnalyzer): - def analyze_external_call(self, op, seen=None): - try: - funcobj = op.args[0].value._obj - if funcobj.random_effects_on_gcobjs: - return True - except (AttributeError, lltype.DelayedPointer): - return True # better safe than sorry + def analyze_external_call(self, funcobj, seen=None): + if funcobj.random_effects_on_gcobjs: + return True return super(RandomEffectsAnalyzer, self).analyze_external_call( - op, seen) + funcobj, seen) def analyze_simple_operation(self, op, graphinfo): return False diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py --- a/rpython/jit/metainterp/executor.py +++ b/rpython/jit/metainterp/executor.py @@ -443,9 +443,7 @@ rop.GC_LOAD_I, rop.GC_LOAD_R, rop.GC_LOAD_F, - rop.GC_LOAD_INDEXED_I, rop.GC_LOAD_INDEXED_R, - rop.GC_LOAD_INDEXED_F, rop.GC_STORE, rop.GC_STORE_INDEXED, ): # list of opcodes never executed by pyjitpl diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py --- a/rpython/jit/metainterp/optimizeopt/heap.py +++ b/rpython/jit/metainterp/optimizeopt/heap.py @@ -14,14 +14,17 @@ AbstractResOp, GuardResOp from rpython.rlib.objectmodel import we_are_translated from rpython.jit.metainterp.optimizeopt import info - + class BogusImmutableField(JitException): pass -class CachedField(object): +class AbstractCachedEntry(object): + """ abstract base class abstracting over the difference between caching + struct fields and array items. """ + def __init__(self): # Cache information for a field descr, or for an (array descr, index) # pair. It can be in one of two states: @@ -29,8 +32,8 @@ # 1. 'cached_infos' is a list listing all the infos that are # caching this descr # - # 2. we just did one setfield, which is delayed (and thus - # not synchronized). 'lazy_setfield' is the delayed + # 2. we just did one set(field/arrayitem), which is delayed (and thus + # not synchronized). '_lazy_set' is the delayed # ResOperation. In this state, 'cached_infos' contains # out-of-date information. More precisely, the field # value pending in the ResOperation is *not* visible in @@ -38,43 +41,39 @@ # self.cached_infos = [] self.cached_structs = [] - self._lazy_setfield = None - self._lazy_setfield_registered = False + self._lazy_set = None - def register_dirty_field(self, structop, info): + def register_info(self, structop, info): + # invariant: every struct or array ptr info, that is not virtual and + # that has a non-None entry at + # info._fields[descr.get_index()] + # must be in cache_infos self.cached_structs.append(structop) self.cached_infos.append(info) - def invalidate(self, descr): - for opinfo in self.cached_infos: - assert isinstance(opinfo, info.AbstractStructPtrInfo) - opinfo._fields[descr.get_index()] = None - self.cached_infos = [] - self.cached_structs = [] - def produce_potential_short_preamble_ops(self, optimizer, shortboxes, descr, index=-1): - assert self._lazy_setfield is None + assert self._lazy_set is None for i, info in enumerate(self.cached_infos): structbox = optimizer.get_box_replacement(self.cached_structs[i]) info.produce_short_preamble_ops(structbox, descr, index, optimizer, shortboxes) def possible_aliasing(self, optheap, opinfo): - # If lazy_setfield is set and contains a setfield on a different + # If lazy_set is set and contains a setfield on a different # structvalue, then we are annoyed, because it may point to either # the same or a different structure at runtime. # XXX constants? - return (self._lazy_setfield is not None + return (self._lazy_set is not None and (not optheap.getptrinfo( - self._lazy_setfield.getarg(0)).same_info(opinfo))) + self._lazy_set.getarg(0)).same_info(opinfo))) def do_setfield(self, optheap, op): # Update the state with the SETFIELD_GC/SETARRAYITEM_GC operation 'op'. structinfo = optheap.ensure_ptr_info_arg0(op) - arg1 = optheap.get_box_replacement(self._getvalue(op)) + arg1 = optheap.get_box_replacement(self._get_rhs_from_set_op(op)) if self.possible_aliasing(optheap, structinfo): - self.force_lazy_setfield(optheap, op.getdescr()) + self.force_lazy_set(optheap, op.getdescr()) assert not self.possible_aliasing(optheap, structinfo) cached_field = self._getfield(structinfo, op.getdescr(), optheap, False) if cached_field is not None: @@ -87,58 +86,43 @@ # cached_fieldvalue = self._cached_fields.get(structvalue, None) if not cached_field or not cached_field.same_box(arg1): - # common case: store the 'op' as lazy_setfield, and register - # myself in the optheap's _lazy_setfields_and_arrayitems list - self._lazy_setfield = op - #if not self._lazy_setfield_registered: - # self._lazy_setfield_registered = True + # common case: store the 'op' as lazy_set + self._lazy_set = op else: # this is the case where the pending setfield ends up # storing precisely the value that is already there, # as proved by 'cached_fields'. In this case, we don't - # need any _lazy_setfield: the heap value is already right. - # Note that this may reset to None a non-None lazy_setfield, + # need any _lazy_set: the heap value is already right. + # Note that this may reset to None a non-None lazy_set, # cancelling its previous effects with no side effect. - + # Now, we have to force the item in the short preamble self._getfield(structinfo, op.getdescr(), optheap) - self._lazy_setfield = None + self._lazy_set = None def getfield_from_cache(self, optheap, opinfo, descr): # Returns the up-to-date field's value, or None if not cached. if self.possible_aliasing(optheap, opinfo): - self.force_lazy_setfield(optheap, descr) - if self._lazy_setfield is not None: - op = self._lazy_setfield - return optheap.get_box_replacement(self._getvalue(op)) + self.force_lazy_set(optheap, descr) + if self._lazy_set is not None: + op = self._lazy_set + return optheap.get_box_replacement(self._get_rhs_from_set_op(op)) else: res = self._getfield(opinfo, descr, optheap) if res is not None: return res.get_box_replacement() return None - def _getvalue(self, op): - return op.getarg(1) - - def _getfield(self, opinfo, descr, optheap, true_force=True): - res = opinfo.getfield(descr, optheap) - if isinstance(res, PreambleOp): - if not true_force: - return res.op - res = optheap.optimizer.force_op_from_preamble(res) - opinfo.setfield(descr, None, res, optheap) - return res - - def force_lazy_setfield(self, optheap, descr, can_cache=True): - op = self._lazy_setfield + def force_lazy_set(self, optheap, descr, can_cache=True): + op = self._lazy_set if op is not None: - # This is the way _lazy_setfield is usually reset to None. + # This is the way _lazy_set is usually reset to None. # Now we clear _cached_fields, because actually doing the # setfield might impact any of the stored result (because of # possible aliasing). self.invalidate(descr) - self._lazy_setfield = None + self._lazy_set = None if optheap.postponed_op: for a in op.getarglist(): if a is optheap.postponed_op: @@ -151,25 +135,74 @@ # back in the cache: the value of this particular structure's # field. opinfo = optheap.ensure_ptr_info_arg0(op) - self._setfield(op, opinfo, optheap) + self.put_field_back_to_info(op, opinfo, optheap) elif not can_cache: self.invalidate(descr) - def _setfield(self, op, opinfo, optheap): + + # abstract methods + + def _get_rhs_from_set_op(self, op): + """ given a set(field or arrayitem) op, return the rhs argument """ + raise NotImplementedError("abstract method") + + def put_field_back_to_info(self, op, opinfo, optheap): + """ this method is called just after a lazy setfield was ommitted. it + puts the information of the lazy setfield back into the proper cache in + the info. """ + raise NotImplementedError("abstract method") + + def _getfield(self, opinfo, descr, optheap, true_force=True): + raise NotImplementedError("abstract method") + + def invalidate(self, descr): + """ clear all the cached knowledge in the infos in self.cached_infos. + """ + raise NotImplementedError("abstract method") + + +class CachedField(AbstractCachedEntry): + def _get_rhs_from_set_op(self, op): + return op.getarg(1) + + def put_field_back_to_info(self, op, opinfo, optheap): arg = optheap.get_box_replacement(op.getarg(1)) struct = optheap.get_box_replacement(op.getarg(0)) - opinfo.setfield(op.getdescr(), struct, arg, optheap, self) + opinfo.setfield(op.getdescr(), struct, arg, optheap=optheap, cf=self) -class ArrayCachedField(CachedField): + def _getfield(self, opinfo, descr, optheap, true_force=True): + res = opinfo.getfield(descr, optheap) + if not we_are_translated() and res: + if isinstance(opinfo, info.AbstractStructPtrInfo): + assert opinfo in self.cached_infos + if isinstance(res, PreambleOp): + if not true_force: + return res.op + res = optheap.optimizer.force_op_from_preamble(res) + opinfo.setfield(descr, None, res, optheap=optheap) + return res + + def invalidate(self, descr): + for opinfo in self.cached_infos: + assert isinstance(opinfo, info.AbstractStructPtrInfo) + opinfo._fields[descr.get_index()] = None + self.cached_infos = [] + self.cached_structs = [] + + +class ArrayCachedItem(AbstractCachedEntry): def __init__(self, index): self.index = index - CachedField.__init__(self) + AbstractCachedEntry.__init__(self) - def _getvalue(self, op): + def _get_rhs_from_set_op(self, op): return op.getarg(2) def _getfield(self, opinfo, descr, optheap, true_force=True): res = opinfo.getitem(descr, self.index, optheap) + if not we_are_translated() and res: + if isinstance(opinfo, info.ArrayPtrInfo): + assert opinfo in self.cached_infos if (isinstance(res, PreambleOp) and optheap.optimizer.cpu.supports_guard_gc_type): if not true_force: @@ -179,10 +212,10 @@ opinfo.setitem(descr, index, None, res, optheap=optheap) return res - def _setfield(self, op, opinfo, optheap): + def put_field_back_to_info(self, op, opinfo, optheap): arg = optheap.get_box_replacement(op.getarg(2)) struct = optheap.get_box_replacement(op.getarg(0)) - opinfo.setitem(op.getdescr(), self.index, struct, arg, self, optheap) + opinfo.setitem(op.getdescr(), self.index, struct, arg, optheap=optheap, cf=self) def invalidate(self, descr): for opinfo in self.cached_infos: @@ -201,15 +234,11 @@ self.postponed_op = None - # XXXX the rest is old - # cached array items: {array descr: {index: CachedField}} - #self.cached_arrayitems = {} # cached dict items: {dict descr: {(optval, index): box-or-const}} self.cached_dict_reads = {} # cache of corresponding {array descrs: dict 'entries' field descr} self.corresponding_array_descrs = {} # - self._lazy_setfields_and_arrayitems = [] self._remove_guard_not_invalidated = False self._seen_guard_not_invalidated = False @@ -221,7 +250,7 @@ def flush(self): self.cached_dict_reads.clear() self.corresponding_array_descrs.clear() - self.force_all_lazy_setfields_and_arrayitems() + self.force_all_lazy_sets() self.emit_postponed_op() def emit_postponed_op(self): @@ -234,7 +263,7 @@ descrkeys = self.cached_fields.keys() if not we_are_translated(): # XXX Pure operation of boxes that are cached in several places will - # only be removed from the peeled loop when red from the first + # only be removed from the peeled loop when read from the first # place discovered here. This is far from ideal, as it makes # the effectiveness of our optimization a bit random. It should # howevere always generate correct results. For tests we dont @@ -249,22 +278,15 @@ d.produce_potential_short_preamble_ops(self.optimizer, sb, descr, index) - def register_dirty_field(self, descr, op, info): - self.field_cache(descr).register_dirty_field(op, info) - - def register_dirty_array_field(self, arraydescr, op, index, info): - self.arrayitem_cache(arraydescr, index).register_dirty_field(op, info) - def clean_caches(self): - del self._lazy_setfields_and_arrayitems[:] items = self.cached_fields.items() if not we_are_translated(): items.sort(key=str, reverse=True) for descr, cf in items: - if not descr.is_immutable(): + if not descr.is_always_pure(): cf.invalidate(descr) for descr, submap in self.cached_arrayitems.iteritems(): - if not descr.is_immutable(): + if not descr.is_always_pure(): for index, cf in submap.iteritems(): cf.invalidate(None) #self.cached_arrayitems.clear() @@ -285,10 +307,10 @@ try: cf = submap[index] except KeyError: - cf = submap[index] = ArrayCachedField(index) + cf = submap[index] = ArrayCachedItem(index) return cf - def emit_operation(self, op): + def emit_operation(self, op): self.emitting_operation(op) self.emit_postponed_op() if (op.is_comparison() or op.is_call_may_force() @@ -304,7 +326,7 @@ return if op.is_guard(): self.optimizer.pendingfields = ( - self.force_lazy_setfields_and_arrayitems_for_guard()) + self.force_lazy_sets_for_guard()) return opnum = op.getopnum() if (opnum == rop.SETFIELD_GC or # handled specially @@ -332,7 +354,7 @@ if not effectinfo.has_random_effects(): self.force_from_effectinfo(effectinfo) return - self.force_all_lazy_setfields_and_arrayitems() + self.force_all_lazy_sets() self.clean_caches() def optimize_CALL_I(self, op): @@ -410,17 +432,17 @@ # XXX we can get the wrong complexity here, if the lists # XXX stored on effectinfo are large for fielddescr in effectinfo.readonly_descrs_fields: - self.force_lazy_setfield(fielddescr) + self.force_lazy_set(fielddescr) for arraydescr in effectinfo.readonly_descrs_arrays: self.force_lazy_setarrayitem(arraydescr) for fielddescr in effectinfo.write_descrs_fields: - if fielddescr.is_immutable(): + if fielddescr.is_always_pure(): continue try: del self.cached_dict_reads[fielddescr] except KeyError: pass - self.force_lazy_setfield(fielddescr, can_cache=False) + self.force_lazy_set(fielddescr, can_cache=False) for arraydescr in effectinfo.write_descrs_arrays: self.force_lazy_setarrayitem(arraydescr, can_cache=False) if arraydescr in self.corresponding_array_descrs: @@ -431,16 +453,16 @@ pass # someone did it already if effectinfo.check_forces_virtual_or_virtualizable(): vrefinfo = self.optimizer.metainterp_sd.virtualref_info - self.force_lazy_setfield(vrefinfo.descr_forced) + self.force_lazy_set(vrefinfo.descr_forced) # ^^^ we only need to force this field; the other fields # of virtualref_info and virtualizable_info are not gcptrs. - def force_lazy_setfield(self, descr, can_cache=True): + def force_lazy_set(self, descr, can_cache=True): try: cf = self.cached_fields[descr] except KeyError: return - cf.force_lazy_setfield(self, descr, can_cache) + cf.force_lazy_set(self, descr, can_cache) def force_lazy_setarrayitem(self, arraydescr, indexb=None, can_cache=True): try: @@ -449,35 +471,35 @@ return for idx, cf in submap.iteritems(): if indexb is None or indexb.contains(idx): - cf.force_lazy_setfield(self, None, can_cache) + cf.force_lazy_set(self, None, can_cache) - def force_all_lazy_setfields_and_arrayitems(self): + def force_all_lazy_sets(self): items = self.cached_fields.items() if not we_are_translated(): items.sort(key=str, reverse=True) for descr, cf in items: - cf.force_lazy_setfield(self, descr) + cf.force_lazy_set(self, descr) for submap in self.cached_arrayitems.itervalues(): for index, cf in submap.iteritems(): - cf.force_lazy_setfield(self, None) + cf.force_lazy_set(self, None) - def force_lazy_setfields_and_arrayitems_for_guard(self): + def force_lazy_sets_for_guard(self): pendingfields = [] items = self.cached_fields.items() if not we_are_translated(): items.sort(key=str, reverse=True) for descr, cf in items: - op = cf._lazy_setfield + op = cf._lazy_set if op is None: continue val = op.getarg(1) if self.optimizer.is_virtual(val): pendingfields.append(op) continue - cf.force_lazy_setfield(self, descr) + cf.force_lazy_set(self, descr) for descr, submap in self.cached_arrayitems.iteritems(): for index, cf in submap.iteritems(): - op = cf._lazy_setfield + op = cf._lazy_set if op is None: continue # the only really interesting case that we need to handle in the @@ -489,7 +511,7 @@ if self.optimizer.is_virtual(op.getarg(2)): pendingfields.append(op) else: - cf.force_lazy_setfield(self, descr) + cf.force_lazy_set(self, descr) return pendingfields def optimize_GETFIELD_GC_I(self, op): @@ -503,7 +525,7 @@ self.make_nonnull(op.getarg(0)) self.emit_operation(op) # then remember the result of reading the field - structinfo.setfield(op.getdescr(), op.getarg(0), op, self, cf) + structinfo.setfield(op.getdescr(), op.getarg(0), op, optheap=self, cf=cf) optimize_GETFIELD_GC_R = optimize_GETFIELD_GC_I optimize_GETFIELD_GC_F = optimize_GETFIELD_GC_I @@ -554,12 +576,12 @@ # default case: produce the operation self.make_nonnull(op.getarg(0)) self.emit_operation(op) - # the remember the result of reading the array item + # then remember the result of reading the array item if cf is not None: arrayinfo.setitem(op.getdescr(), indexb.getint(), self.get_box_replacement(op.getarg(0)), - self.get_box_replacement(op), cf, - self) + self.get_box_replacement(op), optheap=self, + cf=cf) optimize_GETARRAYITEM_GC_R = optimize_GETARRAYITEM_GC_I optimize_GETARRAYITEM_GC_F = optimize_GETARRAYITEM_GC_I diff --git a/rpython/jit/metainterp/optimizeopt/info.py b/rpython/jit/metainterp/optimizeopt/info.py --- a/rpython/jit/metainterp/optimizeopt/info.py +++ b/rpython/jit/metainterp/optimizeopt/info.py @@ -196,28 +196,28 @@ def all_items(self): return self._fields - def setfield(self, descr, struct, op, optheap=None, cf=None): - self.init_fields(descr.get_parent_descr(), descr.get_index()) + def setfield(self, fielddescr, struct, op, optheap=None, cf=None): + self.init_fields(fielddescr.get_parent_descr(), fielddescr.get_index()) assert isinstance(op, AbstractValue) - self._fields[descr.get_index()] = op + self._fields[fielddescr.get_index()] = op if cf is not None: assert not self.is_virtual() assert struct is not None - cf.register_dirty_field(struct, self) + cf.register_info(struct, self) - def getfield(self, descr, optheap=None): - self.init_fields(descr.get_parent_descr(), descr.get_index()) - return self._fields[descr.get_index()] + def getfield(self, fielddescr, optheap=None): + self.init_fields(fielddescr.get_parent_descr(), fielddescr.get_index()) + return self._fields[fielddescr.get_index()] def _force_elements(self, op, optforce, descr): if self._fields is None: return - for i, flddescr in enumerate(descr.get_all_fielddescrs()): + for i, fielddescr in enumerate(descr.get_all_fielddescrs()): fld = self._fields[i] if fld is not None: subbox = optforce.force_box(fld) setfieldop = ResOperation(rop.SETFIELD_GC, [op, subbox], - descr=flddescr) + descr=fielddescr) self._fields[i] = None optforce.emit_operation(setfieldop) @@ -249,16 +249,16 @@ if fieldinfo and fieldinfo.is_virtual(): fieldinfo.visitor_walk_recursive(op, visitor, optimizer) - def produce_short_preamble_ops(self, structbox, descr, index, optimizer, + def produce_short_preamble_ops(self, structbox, fielddescr, index, optimizer, shortboxes): if self._fields is None: return - if descr.get_index() >= len(self._fields): + if fielddescr.get_index() >= len(self._fields): # we don't know about this item return - op = optimizer.get_box_replacement(self._fields[descr.get_index()]) - opnum = OpHelpers.getfield_for_descr(descr) - getfield_op = ResOperation(opnum, [structbox], descr=descr) + op = optimizer.get_box_replacement(self._fields[fielddescr.get_index()]) + opnum = OpHelpers.getfield_for_descr(fielddescr) + getfield_op = ResOperation(opnum, [structbox], descr=fielddescr) shortboxes.add_heap_op(op, getfield_op) def _is_immutable_and_filled_with_constants(self, optimizer, memo=None): @@ -294,12 +294,12 @@ return True def _force_elements_immutable(self, descr, constptr, optforce): - for i, flddescr in enumerate(descr.get_all_fielddescrs()): + for i, fielddescr in enumerate(descr.get_all_fielddescrs()): fld = self._fields[i] subbox = optforce.force_box(fld) assert isinstance(subbox, Const) execute(optforce.optimizer.cpu, None, rop.SETFIELD_GC, - flddescr, constptr, subbox) + fielddescr, constptr, subbox) class InstancePtrInfo(AbstractStructPtrInfo): _attrs_ = ('_known_class',) @@ -505,6 +505,7 @@ info._items = self._items[:] def _force_elements(self, op, optforce, descr): + # XXX descr = op.getdescr() const = optforce.new_const_item(self.descr) for i in range(self.length): @@ -523,15 +524,16 @@ optforce.emit_operation(setop) optforce.pure_from_args(rop.ARRAYLEN_GC, [op], ConstInt(len(self._items))) - def setitem(self, descr, index, struct, op, cf=None, optheap=None): + def setitem(self, descr, index, struct, op, optheap=None, cf=None): if self._items is None: self._items = [None] * (index + 1) if index >= len(self._items): + assert not self.is_virtual() self._items = self._items + [None] * (index - len(self._items) + 1) self._items[index] = op if cf is not None: assert not self.is_virtual() - cf.register_dirty_field(struct, self) + cf.register_info(struct, self) def getitem(self, descr, index, optheap=None): if self._items is None or index >= len(self._items): @@ -626,13 +628,13 @@ i = 0 fielddescrs = op.getdescr().get_all_fielddescrs() for index in range(self.length): - for flddescr in fielddescrs: + for fielddescr in fielddescrs: fld = self._items[i] if fld is not None: subbox = optforce.force_box(fld) setfieldop = ResOperation(rop.SETINTERIORFIELD_GC, [op, ConstInt(index), subbox], - descr=flddescr) + descr=fielddescr) optforce.emit_operation(setfieldop) # heapcache does not work for interiorfields # if it does, we would need a fix here @@ -645,7 +647,7 @@ fielddescrs = self.descr.get_all_fielddescrs() i = 0 for index in range(self.getlength()): - for flddescr in fielddescrs: + for fielddescr in fielddescrs: itemop = self._items[i] if (itemop is not None and not isinstance(itemop, Const)): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit