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

Reply via email to