Author: Armin Rigo <ar...@tunes.org> Branch: cpyext-gc-support-2 Changeset: r81979:1fc97a564c99 Date: 2016-01-27 19:12 +0100 http://bitbucket.org/pypy/pypy/changeset/1fc97a564c99/
Log: hg merge default diff too long, truncating to 2000 out of 4461 lines diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -85,7 +85,8 @@ module_dependencies = { '_multiprocessing': [('objspace.usemodules.time', True), ('objspace.usemodules.thread', True)], - 'cpyext': [('objspace.usemodules.array', True)], + 'cpyext': [('objspace.usemodules.array', True), + ('objspace.usemodules.micronumpy', True)], 'cppyy': [('objspace.usemodules.cpyext', True)], } module_suggests = { diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -54,7 +54,8 @@ It is quite common nowadays that xyz is available on PyPI_ and installable with ``pip install xyz``. The simplest solution is to `use virtualenv (as documented here)`_. Then enter (activate) the virtualenv -and type: ``pip install xyz``. +and type: ``pip install xyz``. If you don't know or don't want virtualenv, +you can also install ``pip`` globally by saying ``pypy -m ensurepip``. If you get errors from the C compiler, the module is a CPython C Extension module using unsupported features. `See below.`_ 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 @@ -123,3 +123,13 @@ .. branch: fix-cpython-ssl-tests-2.7 Fix SSL tests by importing cpython's patch + +.. branch: remove-getfield-pure + +Remove pure variants of ``getfield_gc_*`` operations from the JIT. Relevant +optimizations instead consult the field descriptor to determine the purity of +the operation. Additionally, pure ``getfield`` operations are now handled +entirely by `rpython/jit/metainterp/optimizeopt/heap.py` rather than +`rpython/jit/metainterp/optimizeopt/pure.py`, which can result in better codegen +for traces containing a large number of pure getfield operations. + diff --git a/pypy/module/cpyext/Doc_stubgen_enable.patch b/pypy/module/cpyext/Doc_stubgen_enable.patch deleted file mode 100644 --- a/pypy/module/cpyext/Doc_stubgen_enable.patch +++ /dev/null @@ -1,27 +0,0 @@ -Index: Doc/tools/sphinx/ext/refcounting.py -=================================================================== ---- Doc/tools/sphinx/ext/refcounting.py (Revision 79453) -+++ Doc/tools/sphinx/ext/refcounting.py (Arbeitskopie) -@@ -91,6 +91,7 @@ - if app.config.refcount_file: - refcounts = Refcounts.fromfile( - path.join(app.srcdir, app.config.refcount_file)) -+ app._refcounts = refcounts - app.connect('doctree-read', refcounts.add_refcount_annotations) - - -Index: Doc/conf.py -=================================================================== ---- Doc/conf.py (Revision 79421) -+++ Doc/conf.py (Arbeitskopie) -@@ -13,8 +13,8 @@ - # General configuration - # --------------------- - --extensions = ['sphinx.ext.refcounting', 'sphinx.ext.coverage', -- 'sphinx.ext.doctest', 'pyspecific'] -+extensions = ['pypy.module.cpyext.stubgen', 'sphinx.ext.refcounting', 'sphinx.ext.coverage', -+ 'sphinx.ext.doctest', 'pyspecific', ] - templates_path = ['tools/sphinxext'] - - # General substitutions. diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -441,8 +441,8 @@ TYPES = {} GLOBALS = { # this needs to include all prebuilt pto, otherwise segfaults occur '_Py_NoneStruct#': ('PyObject*', 'space.w_None'), - '_Py_TrueStruct#': ('PyObject*', 'space.w_True'), - '_Py_ZeroStruct#': ('PyObject*', 'space.w_False'), + '_Py_TrueStruct#': ('PyIntObject*', 'space.w_True'), + '_Py_ZeroStruct#': ('PyIntObject*', 'space.w_False'), '_Py_NotImplementedStruct#': ('PyObject*', 'space.w_NotImplemented'), '_Py_EllipsisObject#': ('PyObject*', 'space.w_Ellipsis'), 'PyDateTimeAPI': ('PyDateTime_CAPI*', 'None'), @@ -505,7 +505,9 @@ def get_structtype_for_ctype(ctype): from pypy.module.cpyext.typeobjectdefs import PyTypeObjectPtr from pypy.module.cpyext.cdatetime import PyDateTime_CAPI + from pypy.module.cpyext.intobject import PyIntObject return {"PyObject*": PyObject, "PyTypeObject*": PyTypeObjectPtr, + "PyIntObject*": PyIntObject, "PyDateTime_CAPI*": lltype.Ptr(PyDateTime_CAPI)}[ctype] # Note: as a special case, "PyObject" is the pointer type in RPython, @@ -846,6 +848,7 @@ space.fromcache(State).install_dll(eci) # populate static data + builder = StaticObjectBuilder(space) for name, (typ, expr) in GLOBALS.iteritems(): from pypy.module import cpyext # for the eval() below w_obj = eval(expr) @@ -870,7 +873,7 @@ assert False, "Unknown static pointer: %s %s" % (typ, name) ptr.value = ctypes.cast(ll2ctypes.lltype2ctypes(value), ctypes.c_void_p).value - elif typ in ('PyObject*', 'PyTypeObject*'): + elif typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*'): if name.startswith('PyPyExc_') or name.startswith('cpyexttestExc_'): # we already have the pointer in_dll = ll2ctypes.get_ctypes_type(PyObject).in_dll(bridge, name) @@ -879,17 +882,10 @@ # we have a structure, get its address in_dll = ll2ctypes.get_ctypes_type(PyObject.TO).in_dll(bridge, name) py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes.pointer(in_dll)) - from pypy.module.cpyext.pyobject import ( - track_reference, get_typedescr) - w_type = space.type(w_obj) - typedescr = get_typedescr(w_type.instancetypedef) - py_obj.c_ob_refcnt = 1 - py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr, - make_ref(space, w_type)) - typedescr.attach(space, py_obj, w_obj) - track_reference(space, py_obj, w_obj) + builder.prepare(py_obj, w_obj) else: assert False, "Unknown static object: %s %s" % (typ, name) + builder.attach_all() pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI') @@ -906,6 +902,36 @@ setup_init_functions(eci, translating=False) return modulename.new(ext='') + +class StaticObjectBuilder: + def __init__(self, space): + self.space = space + self.to_attach = [] + + def prepare(self, py_obj, w_obj): + from pypy.module.cpyext.pyobject import track_reference + py_obj.c_ob_refcnt = 1 + track_reference(self.space, py_obj, w_obj) + self.to_attach.append((py_obj, w_obj)) + + def attach_all(self): + from pypy.module.cpyext.pyobject import get_typedescr, make_ref + from pypy.module.cpyext.typeobject import finish_type_1, finish_type_2 + space = self.space + space._cpyext_type_init = [] + for py_obj, w_obj in self.to_attach: + w_type = space.type(w_obj) + typedescr = get_typedescr(w_type.instancetypedef) + py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr, + make_ref(space, w_type)) + typedescr.attach(space, py_obj, w_obj) + cpyext_type_init = space._cpyext_type_init + del space._cpyext_type_init + for pto, w_type in cpyext_type_init: + finish_type_1(space, pto) + finish_type_2(space, pto, w_type) + + def mangle_name(prefix, name): if name.startswith('Py'): return prefix + name[2:] @@ -1100,14 +1126,33 @@ run_bootstrap_functions(space) setup_va_functions(eci) + from pypy.module import cpyext # for eval() below + + # Set up the types. Needs a special case, because of the + # immediate cycle involving 'c_ob_type', and because we don't + # want these types to be Py_TPFLAGS_HEAPTYPE. + static_types = {} + for name, (typ, expr) in GLOBALS.items(): + if typ == 'PyTypeObject*': + pto = lltype.malloc(PyTypeObject, immortal=True, + zero=True, flavor='raw') + pto.c_ob_refcnt = 1 + pto.c_tp_basicsize = -1 + static_types[name] = pto + builder = StaticObjectBuilder(space) + for name, pto in static_types.items(): + pto.c_ob_type = static_types['PyType_Type#'] + w_type = eval(GLOBALS[name][1]) + builder.prepare(rffi.cast(PyObject, pto), w_type) + builder.attach_all() + # populate static data for name, (typ, expr) in GLOBALS.iteritems(): name = name.replace("#", "") if name.startswith('PyExc_'): name = '_' + name - from pypy.module import cpyext w_obj = eval(expr) - if typ in ('PyObject*', 'PyTypeObject*'): + if typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*'): struct_ptr = make_ref(space, w_obj) elif typ == 'PyDateTime_CAPI*': continue diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py --- a/pypy/module/cpyext/dictobject.py +++ b/pypy/module/cpyext/dictobject.py @@ -59,7 +59,7 @@ return None return borrow_from(w_dict, w_res) -@cpython_api([PyObject, rffi.CCHARP], rffi.INT_real, error=-1) +@cpython_api([PyObject, CONST_STRING], rffi.INT_real, error=-1) def PyDict_DelItemString(space, w_dict, key_ptr): """Remove the entry in dictionary p which has a key specified by the string key. Return 0 on success or -1 on failure.""" 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 @@ -128,7 +128,7 @@ filename = "<string>" return run_string(space, source, filename, start, w_globals, w_locals) -@cpython_api([rffi.CCHARP, rffi.INT_real, PyObject, PyObject, +@cpython_api([CONST_STRING, rffi.INT_real, PyObject, PyObject, PyCompilerFlagsPtr], PyObject) def PyRun_StringFlags(space, source, start, w_globals, w_locals, flagsptr): """Execute Python source code from str in the context specified by the @@ -189,7 +189,7 @@ pi[0] = space.getindex_w(w_obj, None) return 1 -@cpython_api([rffi.CCHARP, rffi.CCHARP, rffi.INT_real, PyCompilerFlagsPtr], +@cpython_api([CONST_STRING, CONST_STRING, rffi.INT_real, PyCompilerFlagsPtr], PyObject) def Py_CompileStringFlags(space, source, filename, start, flagsptr): """Parse and compile the Python source code in str, returning the diff --git a/pypy/module/cpyext/patches/Doc_stubgen_enable.patch b/pypy/module/cpyext/patches/Doc_stubgen_enable.patch new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/patches/Doc_stubgen_enable.patch @@ -0,0 +1,27 @@ +Index: Doc/tools/sphinx/ext/refcounting.py +=================================================================== +--- Doc/tools/sphinx/ext/refcounting.py (Revision 79453) ++++ Doc/tools/sphinx/ext/refcounting.py (Arbeitskopie) +@@ -91,6 +91,7 @@ + if app.config.refcount_file: + refcounts = Refcounts.fromfile( + path.join(app.srcdir, app.config.refcount_file)) ++ app._refcounts = refcounts + app.connect('doctree-read', refcounts.add_refcount_annotations) + + +Index: Doc/conf.py +=================================================================== +--- Doc/conf.py (Revision 79421) ++++ Doc/conf.py (Arbeitskopie) +@@ -13,8 +13,8 @@ + # General configuration + # --------------------- + +-extensions = ['sphinx.ext.refcounting', 'sphinx.ext.coverage', +- 'sphinx.ext.doctest', 'pyspecific'] ++extensions = ['pypy.module.cpyext.stubgen', 'sphinx.ext.refcounting', 'sphinx.ext.coverage', ++ 'sphinx.ext.doctest', 'pyspecific', ] + templates_path = ['tools/sphinxext'] + + # General substitutions. diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py --- a/pypy/module/cpyext/pystrtod.py +++ b/pypy/module/cpyext/pystrtod.py @@ -1,6 +1,6 @@ import errno from pypy.interpreter.error import OperationError -from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.api import cpython_api, CONST_STRING from pypy.module.cpyext.pyobject import PyObject from rpython.rlib import rdtoa from rpython.rlib import rfloat @@ -22,7 +22,7 @@ rfloat.DIST_NAN: Py_DTST_NAN } -@cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) +@cpython_api([CONST_STRING, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0) @jit.dont_look_inside # direct use of _get_errno() def PyOS_string_to_double(space, s, endptr, w_overflow_exception): """Convert a string s to a double, raising a Python diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py --- a/pypy/module/cpyext/test/test_typeobject.py +++ b/pypy/module/cpyext/test/test_typeobject.py @@ -374,6 +374,11 @@ module = self.import_extension('foo', [ ("test_type", "METH_O", ''' + /* "args->ob_type" is a strange way to get at 'type', + which should have a different tp_getattro/tp_setattro + than its tp_base, which is 'object'. + */ + if (!args->ob_type->tp_setattro) { PyErr_SetString(PyExc_ValueError, "missing tp_setattro"); @@ -382,8 +387,12 @@ if (args->ob_type->tp_setattro == args->ob_type->tp_base->tp_setattro) { - PyErr_SetString(PyExc_ValueError, "recursive tp_setattro"); - return NULL; + /* Note that unlike CPython, in PyPy 'type.tp_setattro' + is the same function as 'object.tp_setattro'. This + test used to check that it was not, but that was an + artifact of the bootstrap logic only---in the final + C sources I checked and they are indeed the same. + So we ignore this problem here. */ } if (!args->ob_type->tp_getattro) { diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -146,7 +146,7 @@ assert len(slot_names) == 2 struct = getattr(pto, slot_names[0]) if not struct: - assert not space.config.translating + #assert not space.config.translating assert not pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE if slot_names[0] == 'c_tp_as_number': STRUCT_TYPE = PyNumberMethods @@ -310,36 +310,6 @@ realize=type_realize, dealloc=type_dealloc) - # There is the obvious cycle of 'type(type) == type', but there are - # also several other ones, like 'tuple.tp_bases' being itself a - # tuple instance. We solve the first one by creating the type - # "type" manually here. For the other cycles, we fix them by delaying - # creation of the types here, and hoping nothing breaks by seeing - # uninitialized-yet types (only for a few basic types like 'type', - # 'tuple', 'object', 'str'). - space._cpyext_delay_type_creation = [] - - py_type = _type_alloc(space, lltype.nullptr(PyTypeObject)) - py_type.c_ob_type = rffi.cast(PyTypeObjectPtr, py_type) - track_reference(space, py_type, space.w_type) - type_attach(space, py_type, space.w_type) - - as_pyobj(space, space.w_str) - as_pyobj(space, space.w_tuple) - as_pyobj(space, space.w_object) - - delayed_types = [] - while space._cpyext_delay_type_creation: - (py_obj, w_type) = space._cpyext_delay_type_creation.pop() - _type_really_attach(space, py_obj, w_type) - delayed_types.append((py_obj, w_type)) - del space._cpyext_delay_type_creation - for py_obj, w_type in delayed_types: - pto = rffi.cast(PyTypeObjectPtr, py_obj) - finish_type_1(space, pto) - finish_type_2(space, pto, w_type) - finish_type_3(space, pto, w_type) - @cpython_api([PyObject], lltype.Void, external=False) def subtype_dealloc(space, obj): @@ -440,16 +410,13 @@ def type_alloc(space, w_metatype): - metatype = make_ref(space, w_metatype) - metatype = rffi.cast(PyTypeObjectPtr, metatype) - assert metatype + metatype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_metatype)) # Don't increase refcount for non-heaptypes - flags = rffi.cast(lltype.Signed, metatype.c_tp_flags) - if not flags & Py_TPFLAGS_HEAPTYPE: - Py_DecRef(space, w_metatype) - return _type_alloc(space, metatype) + if metatype: + flags = rffi.cast(lltype.Signed, metatype.c_tp_flags) + if not flags & Py_TPFLAGS_HEAPTYPE: + Py_DecRef(space, w_metatype) -def _type_alloc(space, metatype): heaptype = lltype.malloc(PyHeapTypeObject.TO, flavor='raw', zero=True) pto = heaptype.c_ht_type @@ -460,7 +427,6 @@ pto.c_tp_as_sequence = heaptype.c_as_sequence pto.c_tp_as_mapping = heaptype.c_as_mapping pto.c_tp_as_buffer = heaptype.c_as_buffer - pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 @@ -470,13 +436,6 @@ """ Fills a newly allocated PyTypeObject from an existing type. """ - if hasattr(space, '_cpyext_delay_type_creation'): - space._cpyext_delay_type_creation.append((py_obj, w_type)) - else: - _type_really_attach(space, py_obj, w_type) - return rffi.cast(PyTypeObjectPtr, py_obj) - -def _type_really_attach(space, py_obj, w_type): from pypy.module.cpyext.object import PyObject_Del assert isinstance(w_type, W_TypeObject) @@ -497,15 +456,24 @@ PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) + if pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE: + w_typename = space.getattr(w_type, space.wrap('__name__')) + heaptype = rffi.cast(PyHeapTypeObject, pto) + heaptype.c_ht_name = make_ref(space, w_typename) + from pypy.module.cpyext.stringobject import PyString_AsString + pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name) + else: + pto.c_tp_name = rffi.str2charp(w_type.name) # uninitialized fields: # c_tp_print, c_tp_getattr, c_tp_setattr # XXX implement # c_tp_compare and the following fields (see http://docs.python.org/c-api/typeobj.html ) w_base = best_base(space, w_type.bases_w) - py_base = make_ref(space, w_base) - pto.c_tp_base = rffi.cast(PyTypeObjectPtr, py_base) + pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base)) - if not hasattr(space, '_cpyext_delay_type_creation'): + if hasattr(space, '_cpyext_type_init'): + space._cpyext_type_init.append((pto, w_type)) + else: finish_type_1(space, pto) finish_type_2(space, pto, w_type) @@ -519,21 +487,8 @@ if space.is_w(w_type, space.w_object): pto.c_tp_new = rffi.cast(newfunc, 1) update_all_slots(space, w_type, pto) - - if not hasattr(space, '_cpyext_delay_type_creation'): - finish_type_3(space, pto, w_type) - pto.c_tp_flags |= Py_TPFLAGS_READY - -def finish_type_3(space, pto, w_type): - if pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE: - w_typename = space.getattr(w_type, space.wrap('__name__')) - heaptype = rffi.cast(PyHeapTypeObject, pto) - heaptype.c_ht_name = make_ref(space, w_typename) - from pypy.module.cpyext.stringobject import PyString_AsString - pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name) - else: - pto.c_tp_name = rffi.str2charp(w_type.name) + return pto def py_type_ready(space, pto): if pto.c_tp_flags & Py_TPFLAGS_READY: 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 @@ -83,9 +83,9 @@ p38 = call_r(ConstClass(_ll_1_threadlocalref_get__Ptr_GcStruct_objectLlT_Signed), #, descr=<Callr . i EF=1 OS=5>) p39 = getfield_gc_r(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>) i40 = force_token() - p41 = getfield_gc_pure_r(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>) + p41 = getfield_gc_r(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>) guard_value(p41, ConstPtr(ptr42), descr=...) - i42 = getfield_gc_pure_i(p38, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>) + i42 = getfield_gc_i(p38, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>) i43 = int_is_zero(i42) guard_true(i43, descr=...) i50 = force_token() @@ -435,21 +435,21 @@ guard_isnull(p5, descr=...) guard_nonnull_class(p12, ConstClass(W_IntObject), descr=...) guard_value(p2, ConstPtr(ptr21), descr=...) - i22 = getfield_gc_pure_i(p12, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>) + i22 = getfield_gc_i(p12, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>) i24 = int_lt(i22, 5000) guard_true(i24, 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 .*>) p31 = force_token() - p32 = getfield_gc_pure_r(p29, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>) + p32 = getfield_gc_r(p29, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>) guard_value(p32, ConstPtr(ptr33), descr=...) - i34 = getfield_gc_pure_i(p29, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>) + i34 = getfield_gc_i(p29, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>) i35 = int_is_zero(i34) guard_true(i35, descr=...) p37 = getfield_gc_r(ConstPtr(ptr36), descr=<FieldP pypy.interpreter.nestedscope.Cell.inst_w_value .*>) guard_nonnull_class(p37, ConstClass(W_IntObject), descr=...) - i39 = getfield_gc_pure_i(p37, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>) + i39 = getfield_gc_i(p37, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>) i40 = int_add_ovf(i22, i39) guard_no_overflow(descr=...) --TICK-- @@ -466,7 +466,7 @@ """, []) loop, = log.loops_by_id('call') assert loop.match(""" - i8 = getfield_gc_pure_i(p6, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>) + i8 = getfield_gc_i(p6, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>) i10 = int_lt(i8, 5000) guard_true(i10, descr=...) guard_not_invalidated? diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -84,7 +84,7 @@ guard_no_exception(descr=...) p20 = new_with_vtable(descr=...) call_n(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=<Callv 0 rrrii EF=5>) - setfield_gc(p20, i5, descr=<FieldS .*W_IntObject.inst_intval .*>) + setfield_gc(p20, i5, descr=<FieldS .*W_IntObject.inst_intval .* pure>) guard_no_exception(descr=...) i23 = call_i(ConstClass(ll_call_lookup_function), p13, p10, i12, 0, descr=<Calli . rrii EF=5 OS=4>) guard_no_exception(descr=...) @@ -93,7 +93,7 @@ p28 = getfield_gc_r(p13, descr=<FieldP dicttable.entries .*>) p29 = getinteriorfield_gc_r(p28, i23, descr=<InteriorFieldDescr <FieldP odictentry.value .*>>) guard_nonnull_class(p29, ConstClass(W_IntObject), descr=...) - i31 = getfield_gc_pure_i(p29, descr=<FieldS .*W_IntObject.inst_intval .*>) + i31 = getfield_gc_i(p29, descr=<FieldS .*W_IntObject.inst_intval .* pure>) i32 = int_sub_ovf(i31, i5) guard_no_overflow(descr=...) i34 = int_add_ovf(i32, 1) diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -101,13 +101,13 @@ loop = log._filter(log.loops[0]) assert loop.match(""" guard_class(p1, #, descr=...) - p4 = getfield_gc_pure_r(p1, descr=<FieldP pypy.module.micronumpy.iterators.ArrayIter.inst_array \d+>) + p4 = getfield_gc_r(p1, descr=<FieldP pypy.module.micronumpy.iterators.ArrayIter.inst_array \d+ pure>) i5 = getfield_gc_i(p0, descr=<FieldS pypy.module.micronumpy.iterators.IterState.inst_offset \d+>) - p6 = getfield_gc_pure_r(p4, descr=<FieldP pypy.module.micronumpy.concrete.BaseConcreteArray.inst_dtype \d+>) - p7 = getfield_gc_pure_r(p6, descr=<FieldP pypy.module.micronumpy.descriptor.W_Dtype.inst_itemtype \d+>) + p6 = getfield_gc_r(p4, descr=<FieldP pypy.module.micronumpy.concrete.BaseConcreteArray.inst_dtype \d+ pure>) + p7 = getfield_gc_r(p6, descr=<FieldP pypy.module.micronumpy.descriptor.W_Dtype.inst_itemtype \d+ pure>) guard_class(p7, ConstClass(Float64), descr=...) - i9 = getfield_gc_pure_i(p4, descr=<FieldU pypy.module.micronumpy.concrete.BaseConcreteArray.inst_storage \d+>) - i10 = getfield_gc_pure_i(p6, descr=<FieldU pypy.module.micronumpy.descriptor.W_Dtype.inst_byteorder \d+>) + i9 = getfield_gc_i(p4, descr=<FieldU pypy.module.micronumpy.concrete.BaseConcreteArray.inst_storage \d+ pure>) + i10 = getfield_gc_i(p6, descr=<FieldU pypy.module.micronumpy.descriptor.W_Dtype.inst_byteorder \d+ pure>) i12 = int_eq(i10, 61) i14 = int_eq(i10, 60) i15 = int_or(i12, i14) @@ -117,28 +117,28 @@ i18 = float_ne(f16, 0.000000) guard_true(i18, descr=...) guard_nonnull_class(p2, ConstClass(W_BoolBox), descr=...) - i20 = getfield_gc_pure_i(p2, descr=<FieldU pypy.module.micronumpy.boxes.W_BoolBox.inst_value \d+>) + i20 = getfield_gc_i(p2, descr=<FieldU pypy.module.micronumpy.boxes.W_BoolBox.inst_value \d+ pure>) i21 = int_is_true(i20) guard_false(i21, descr=...) i22 = getfield_gc_i(p0, descr=<FieldS pypy.module.micronumpy.iterators.IterState.inst_index \d+>) - i23 = getfield_gc_pure_i(p1, descr=<FieldU pypy.module.micronumpy.iterators.ArrayIter.inst_track_index \d+>) + i23 = getfield_gc_i(p1, descr=<FieldU pypy.module.micronumpy.iterators.ArrayIter.inst_track_index \d+ pure>) guard_true(i23, descr=...) i25 = int_add(i22, 1) - p26 = getfield_gc_pure_r(p0, descr=<FieldP pypy.module.micronumpy.iterators.IterState.inst__indices \d+>) - i27 = getfield_gc_pure_i(p1, descr=<FieldS pypy.module.micronumpy.iterators.ArrayIter.inst_contiguous \d+>) + p26 = getfield_gc_r(p0, descr=<FieldP pypy.module.micronumpy.iterators.IterState.inst__indices \d+ pure>) + i27 = getfield_gc_i(p1, descr=<FieldS pypy.module.micronumpy.iterators.ArrayIter.inst_contiguous \d+ pure>) i28 = int_is_true(i27) guard_true(i28, descr=...) - i29 = getfield_gc_pure_i(p6, descr=<FieldS pypy.module.micronumpy.descriptor.W_Dtype.inst_elsize \d+>) + i29 = getfield_gc_i(p6, descr=<FieldS pypy.module.micronumpy.descriptor.W_Dtype.inst_elsize \d+ pure>) guard_value(i29, 8, descr=...) i30 = int_add(i5, 8) - i31 = getfield_gc_pure_i(p1, descr=<FieldS pypy.module.micronumpy.iterators.ArrayIter.inst_size \d+>) + i31 = getfield_gc_i(p1, descr=<FieldS pypy.module.micronumpy.iterators.ArrayIter.inst_size \d+ pure>) i32 = int_ge(i25, i31) guard_false(i32, descr=...) p34 = new_with_vtable(descr=...) {{{ - setfield_gc(p34, p1, descr=<FieldP pypy.module.micronumpy.iterators.IterState.inst_iterator \d+>) + setfield_gc(p34, p1, descr=<FieldP pypy.module.micronumpy.iterators.IterState.inst_iterator \d+ pure>) setfield_gc(p34, i25, descr=<FieldS pypy.module.micronumpy.iterators.IterState.inst_index \d+>) - setfield_gc(p34, p26, descr=<FieldP pypy.module.micronumpy.iterators.IterState.inst__indices \d+>) + setfield_gc(p34, p26, descr=<FieldP pypy.module.micronumpy.iterators.IterState.inst__indices \d+ pure>) setfield_gc(p34, i30, descr=<FieldS pypy.module.micronumpy.iterators.IterState.inst_offset \d+>) }}} jump(..., descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -54,7 +54,7 @@ i19 = int_add(i11, 1) setfield_gc(p2, i19, descr=...) guard_nonnull_class(p18, ConstClass(W_IntObject), descr=...) - i20 = getfield_gc_pure_i(p18, descr=...) + i20 = getfield_gc_i(p18, descr=...) i21 = int_gt(i20, i14) guard_true(i21, 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 @@ -113,7 +113,7 @@ i12 = int_is_true(i4) guard_true(i12, descr=...) guard_not_invalidated(descr=...) - i10p = getfield_gc_pure_i(p10, descr=...) + i10p = getfield_gc_i(p10, descr=...) i10 = int_mul_ovf(2, i10p) guard_no_overflow(descr=...) i14 = int_add_ovf(i13, i10) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -82,7 +82,7 @@ strsetitem(p25, 0, i23) p93 = call_r(ConstClass(fromstr), p25, 16, descr=<Callr . ri EF=4>) guard_no_exception(descr=...) - i95 = getfield_gc_pure_i(p93, descr=<FieldS rpython.rlib.rbigint.rbigint.inst_size .*>) + i95 = getfield_gc_i(p93, descr=<FieldS rpython.rlib.rbigint.rbigint.inst_size .*>) i96 = int_gt(i95, #) guard_false(i96, descr=...) i94 = call_i(ConstClass(rbigint._toint_helper), p93, descr=<Calli . r EF=4>) 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 @@ -30,10 +30,10 @@ assert isinstance(terminator, Terminator) self.terminator = terminator - def read(self, obj, selector): - attr = self.find_map_attr(selector) + def read(self, obj, name, index): + attr = self.find_map_attr(name, index) if attr is None: - return self.terminator._read_terminator(obj, selector) + return self.terminator._read_terminator(obj, name, index) if ( jit.isconstant(attr.storageindex) and jit.isconstant(obj) and @@ -47,39 +47,39 @@ def _pure_mapdict_read_storage(self, obj, storageindex): return obj._mapdict_read_storage(storageindex) - def write(self, obj, selector, w_value): - attr = self.find_map_attr(selector) + def write(self, obj, name, index, w_value): + attr = self.find_map_attr(name, index) if attr is None: - return self.terminator._write_terminator(obj, selector, w_value) + return self.terminator._write_terminator(obj, name, index, w_value) if not attr.ever_mutated: attr.ever_mutated = True obj._mapdict_write_storage(attr.storageindex, w_value) return True - def delete(self, obj, selector): + def delete(self, obj, name, index): pass - def find_map_attr(self, selector): + def find_map_attr(self, name, index): if jit.we_are_jitted(): # hack for the jit: # the _find_map_attr method is pure too, but its argument is never # constant, because it is always a new tuple - return self._find_map_attr_jit_pure(selector[0], selector[1]) + return self._find_map_attr_jit_pure(name, index) else: - return self._find_map_attr_indirection(selector) + return self._find_map_attr_indirection(name, index) @jit.elidable def _find_map_attr_jit_pure(self, name, index): - return self._find_map_attr_indirection((name, index)) + return self._find_map_attr_indirection(name, index) @jit.dont_look_inside - def _find_map_attr_indirection(self, selector): + def _find_map_attr_indirection(self, name, index): if (self.space.config.objspace.std.withmethodcache): - return self._find_map_attr_cache(selector) - return self._find_map_attr(selector) + return self._find_map_attr_cache(name, index) + return self._find_map_attr(name, index) @jit.dont_look_inside - def _find_map_attr_cache(self, selector): + def _find_map_attr_cache(self, name, index): space = self.space cache = space.fromcache(MapAttrCache) SHIFT2 = r_uint.BITS - space.config.objspace.std.methodcachesizeexp @@ -87,31 +87,36 @@ attrs_as_int = objectmodel.current_object_addr_as_int(self) # ^^^Note: see comment in typeobject.py for # _pure_lookup_where_with_method_cache() - hash_selector = objectmodel.compute_hash(selector) + + # unrolled hash computation for 2-tuple + c1 = 0x345678 + c2 = 1000003 + hash_name = objectmodel.compute_hash(name) + hash_selector = intmask((c2 * ((c2 * c1) ^ hash_name)) ^ index) product = intmask(attrs_as_int * hash_selector) attr_hash = (r_uint(product) ^ (r_uint(product) << SHIFT1)) >> SHIFT2 # ^^^Note2: same comment too cached_attr = cache.attrs[attr_hash] if cached_attr is self: - cached_selector = cache.selectors[attr_hash] - if cached_selector == selector: + cached_name = cache.names[attr_hash] + cached_index = cache.indexes[attr_hash] + if cached_name == name and cached_index == index: attr = cache.cached_attrs[attr_hash] if space.config.objspace.std.withmethodcachecounter: - name = selector[0] cache.hits[name] = cache.hits.get(name, 0) + 1 return attr - attr = self._find_map_attr(selector) + attr = self._find_map_attr(name, index) cache.attrs[attr_hash] = self - cache.selectors[attr_hash] = selector + cache.names[attr_hash] = name + cache.indexes[attr_hash] = index cache.cached_attrs[attr_hash] = attr if space.config.objspace.std.withmethodcachecounter: - name = selector[0] cache.misses[name] = cache.misses.get(name, 0) + 1 return attr - def _find_map_attr(self, selector): + def _find_map_attr(self, name, index): while isinstance(self, PlainAttribute): - if selector == self.selector: + if name == self.name and index == self.index: return self self = self.back return None @@ -137,23 +142,22 @@ @jit.elidable def _get_new_attr(self, name, index): - selector = name, index cache = self.cache_attrs if cache is None: cache = self.cache_attrs = {} - attr = cache.get(selector, None) + attr = cache.get((name, index), None) if attr is None: - attr = PlainAttribute(selector, self) - cache[selector] = attr + attr = PlainAttribute(name, index, self) + cache[name, index] = attr return attr - @jit.look_inside_iff(lambda self, obj, selector, w_value: + @jit.look_inside_iff(lambda self, obj, name, index, w_value: jit.isconstant(self) and - jit.isconstant(selector[0]) and - jit.isconstant(selector[1])) - def add_attr(self, obj, selector, w_value): + jit.isconstant(name) and + jit.isconstant(index)) + def add_attr(self, obj, name, index, w_value): # grumble, jit needs this - attr = self._get_new_attr(selector[0], selector[1]) + attr = self._get_new_attr(name, index) oldattr = obj._get_mapdict_map() if not jit.we_are_jitted(): size_est = (oldattr._size_estimate + attr.size_estimate() @@ -189,11 +193,11 @@ AbstractAttribute.__init__(self, space, self) self.w_cls = w_cls - def _read_terminator(self, obj, selector): + def _read_terminator(self, obj, name, index): return None - def _write_terminator(self, obj, selector, w_value): - obj._get_mapdict_map().add_attr(obj, selector, w_value) + def _write_terminator(self, obj, name, index, w_value): + obj._get_mapdict_map().add_attr(obj, name, index, w_value) return True def copy(self, obj): @@ -231,40 +235,40 @@ class NoDictTerminator(Terminator): - def _write_terminator(self, obj, selector, w_value): - if selector[1] == DICT: + def _write_terminator(self, obj, name, index, w_value): + if index == DICT: return False - return Terminator._write_terminator(self, obj, selector, w_value) + return Terminator._write_terminator(self, obj, name, index, w_value) class DevolvedDictTerminator(Terminator): - def _read_terminator(self, obj, selector): - if selector[1] == DICT: + def _read_terminator(self, obj, name, index): + if index == DICT: space = self.space w_dict = obj.getdict(space) - return space.finditem_str(w_dict, selector[0]) - return Terminator._read_terminator(self, obj, selector) + return space.finditem_str(w_dict, name) + return Terminator._read_terminator(self, obj, name, index) - def _write_terminator(self, obj, selector, w_value): - if selector[1] == DICT: + def _write_terminator(self, obj, name, index, w_value): + if index == DICT: space = self.space w_dict = obj.getdict(space) - space.setitem_str(w_dict, selector[0], w_value) + space.setitem_str(w_dict, name, w_value) return True - return Terminator._write_terminator(self, obj, selector, w_value) + return Terminator._write_terminator(self, obj, name, index, w_value) - def delete(self, obj, selector): + def delete(self, obj, name, index): from pypy.interpreter.error import OperationError - if selector[1] == DICT: + if index == DICT: space = self.space w_dict = obj.getdict(space) try: - space.delitem(w_dict, space.wrap(selector[0])) + space.delitem(w_dict, space.wrap(name)) except OperationError, ex: if not ex.match(space, space.w_KeyError): raise return Terminator.copy(self, obj) - return Terminator.delete(self, obj, selector) + return Terminator.delete(self, obj, name, index) def remove_dict_entries(self, obj): assert 0, "should be unreachable" @@ -276,27 +280,28 @@ return Terminator.set_terminator(self, obj, terminator) class PlainAttribute(AbstractAttribute): - _immutable_fields_ = ['selector', 'storageindex', 'back', 'ever_mutated?'] + _immutable_fields_ = ['name', 'index', 'storageindex', 'back', 'ever_mutated?'] - def __init__(self, selector, back): + def __init__(self, name, index, back): AbstractAttribute.__init__(self, back.space, back.terminator) - self.selector = selector + self.name = name + self.index = index self.storageindex = back.length() self.back = back self._size_estimate = self.length() * NUM_DIGITS_POW2 self.ever_mutated = False def _copy_attr(self, obj, new_obj): - w_value = self.read(obj, self.selector) - new_obj._get_mapdict_map().add_attr(new_obj, self.selector, w_value) + w_value = self.read(obj, self.name, self.index) + new_obj._get_mapdict_map().add_attr(new_obj, self.name, self.index, w_value) - def delete(self, obj, selector): - if selector == self.selector: + def delete(self, obj, name, index): + if name == self.name and index == self.index: # ok, attribute is deleted if not self.ever_mutated: self.ever_mutated = True return self.back.copy(obj) - new_obj = self.back.delete(obj, selector) + new_obj = self.back.delete(obj, name, index) if new_obj is not None: self._copy_attr(obj, new_obj) return new_obj @@ -315,14 +320,14 @@ return new_obj def search(self, attrtype): - if self.selector[1] == attrtype: + if self.index == attrtype: return self return self.back.search(attrtype) def materialize_r_dict(self, space, obj, dict_w): new_obj = self.back.materialize_r_dict(space, obj, dict_w) - if self.selector[1] == DICT: - w_attr = space.wrap(self.selector[0]) + if self.index == DICT: + w_attr = space.wrap(self.name) dict_w[w_attr] = obj._mapdict_read_storage(self.storageindex) else: self._copy_attr(obj, new_obj) @@ -330,12 +335,12 @@ def remove_dict_entries(self, obj): new_obj = self.back.remove_dict_entries(obj) - if self.selector[1] != DICT: + if self.index != DICT: self._copy_attr(obj, new_obj) return new_obj def __repr__(self): - return "<PlainAttribute %s %s %r>" % (self.selector, self.storageindex, self.back) + return "<PlainAttribute %s %s %s %r>" % (self.name, self.index, self.storageindex, self.back) def _become(w_obj, new_obj): # this is like the _become method, really, but we cannot use that due to @@ -347,8 +352,8 @@ assert space.config.objspace.std.withmethodcache SIZE = 1 << space.config.objspace.std.methodcachesizeexp self.attrs = [None] * SIZE - self._empty_selector = (None, INVALID) - self.selectors = [self._empty_selector] * SIZE + self.names = [None] * SIZE + self.indexes = [INVALID] * SIZE self.cached_attrs = [None] * SIZE if space.config.objspace.std.withmethodcachecounter: self.hits = {} @@ -357,8 +362,9 @@ def clear(self): for i in range(len(self.attrs)): self.attrs[i] = None - for i in range(len(self.selectors)): - self.selectors[i] = self._empty_selector + for i in range(len(self.names)): + self.names[i] = None + self.indexes[i] = INVALID for i in range(len(self.cached_attrs)): self.cached_attrs[i] = None @@ -388,20 +394,20 @@ # objspace interface def getdictvalue(self, space, attrname): - return self._get_mapdict_map().read(self, (attrname, DICT)) + return self._get_mapdict_map().read(self, attrname, DICT) def setdictvalue(self, space, attrname, w_value): - return self._get_mapdict_map().write(self, (attrname, DICT), w_value) + return self._get_mapdict_map().write(self, attrname, DICT, w_value) def deldictvalue(self, space, attrname): - new_obj = self._get_mapdict_map().delete(self, (attrname, DICT)) + new_obj = self._get_mapdict_map().delete(self, attrname, DICT) if new_obj is None: return False self._become(new_obj) return True def getdict(self, space): - w_dict = self._get_mapdict_map().read(self, ("dict", SPECIAL)) + w_dict = self._get_mapdict_map().read(self, "dict", SPECIAL) if w_dict is not None: assert isinstance(w_dict, W_DictMultiObject) return w_dict @@ -409,7 +415,7 @@ strategy = space.fromcache(MapDictStrategy) storage = strategy.erase(self) w_dict = W_DictObject(space, strategy, storage) - flag = self._get_mapdict_map().write(self, ("dict", SPECIAL), w_dict) + flag = self._get_mapdict_map().write(self, "dict", SPECIAL, w_dict) assert flag return w_dict @@ -425,7 +431,7 @@ # shell that continues to delegate to 'self'. 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) + flag = self._get_mapdict_map().write(self, "dict", SPECIAL, w_dict) assert flag def getclass(self, space): @@ -443,16 +449,16 @@ self._init_empty(w_subtype.terminator) def getslotvalue(self, slotindex): - key = ("slot", SLOTS_STARTING_FROM + slotindex) - return self._get_mapdict_map().read(self, key) + index = SLOTS_STARTING_FROM + slotindex + return self._get_mapdict_map().read(self, "slot", index) def setslotvalue(self, slotindex, w_value): - key = ("slot", SLOTS_STARTING_FROM + slotindex) - self._get_mapdict_map().write(self, key, w_value) + index = SLOTS_STARTING_FROM + slotindex + self._get_mapdict_map().write(self, "slot", index, w_value) def delslotvalue(self, slotindex): - key = ("slot", SLOTS_STARTING_FROM + slotindex) - new_obj = self._get_mapdict_map().delete(self, key) + index = SLOTS_STARTING_FROM + slotindex + new_obj = self._get_mapdict_map().delete(self, "slot", index) if new_obj is None: return False self._become(new_obj) @@ -462,7 +468,7 @@ def getweakref(self): from pypy.module._weakref.interp__weakref import WeakrefLifeline - lifeline = self._get_mapdict_map().read(self, ("weakref", SPECIAL)) + lifeline = self._get_mapdict_map().read(self, "weakref", SPECIAL) if lifeline is None: return None assert isinstance(lifeline, WeakrefLifeline) @@ -472,11 +478,11 @@ def setweakref(self, space, weakreflifeline): from pypy.module._weakref.interp__weakref import WeakrefLifeline assert isinstance(weakreflifeline, WeakrefLifeline) - self._get_mapdict_map().write(self, ("weakref", SPECIAL), weakreflifeline) + self._get_mapdict_map().write(self, "weakref", SPECIAL, weakreflifeline) setweakref._cannot_really_call_random_things_ = True def delweakref(self): - self._get_mapdict_map().write(self, ("weakref", SPECIAL), None) + self._get_mapdict_map().write(self, "weakref", SPECIAL, None) delweakref._cannot_really_call_random_things_ = True class ObjectMixin(object): @@ -721,7 +727,7 @@ curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT) if curr is None: raise KeyError - key = curr.selector[0] + key = curr.name w_value = self.getitem_str(w_dict, key) w_key = self.space.wrap(key) self.delitem(w_dict, w_key) @@ -758,7 +764,7 @@ curr_map = self.curr_map.search(DICT) if curr_map: self.curr_map = curr_map.back - attr = curr_map.selector[0] + attr = curr_map.name w_attr = self.space.wrap(attr) return w_attr return None @@ -780,7 +786,7 @@ curr_map = self.curr_map.search(DICT) if curr_map: self.curr_map = curr_map.back - attr = curr_map.selector[0] + attr = curr_map.name return self.w_obj.getdictvalue(self.space, attr) return None @@ -801,7 +807,7 @@ curr_map = self.curr_map.search(DICT) if curr_map: self.curr_map = curr_map.back - attr = curr_map.selector[0] + attr = curr_map.name w_attr = self.space.wrap(attr) return w_attr, self.w_obj.getdictvalue(self.space, attr) return None, None @@ -884,9 +890,9 @@ _, w_descr = w_type._pure_lookup_where_possibly_with_method_cache( name, version_tag) # - selector = ("", INVALID) + attrname, index = ("", INVALID) if w_descr is None: - selector = (name, DICT) # common case: no such attr in the class + attrname, index = (name, DICT) # common case: no such attr in the class elif isinstance(w_descr, MutableCell): pass # we have a MutableCell in the class: give up elif space.is_data_descr(w_descr): @@ -894,20 +900,21 @@ # (if any) has no relevance. from pypy.interpreter.typedef import Member if isinstance(w_descr, Member): # it is a slot -- easy case - selector = ("slot", SLOTS_STARTING_FROM + w_descr.index) + attrname, index = ("slot", SLOTS_STARTING_FROM + w_descr.index) else: # There is a non-data descriptor in the class. If there is # also a dict attribute, use the latter, caching its storageindex. # If not, we loose. We could do better in this case too, # but we don't care too much; the common case of a method # invocation is handled by LOOKUP_METHOD_xxx below. - selector = (name, DICT) + attrname = name + index = DICT # - if selector[1] != INVALID: - attr = map.find_map_attr(selector) + if index != INVALID: + attr = map.find_map_attr(attrname, index) if attr is not None: # Note that if map.terminator is a DevolvedDictTerminator, - # map.find_map_attr will always return None if selector[1]==DICT. + # map.find_map_attr will always return None if index==DICT. _fill_cache(pycode, nameindex, map, version_tag, attr.storageindex) return w_obj._mapdict_read_storage(attr.storageindex) if space.config.objspace.std.withmethodcachecounter: 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 @@ -34,8 +34,8 @@ def test_plain_attribute(): w_cls = "class" - aa = PlainAttribute(("b", DICT), - PlainAttribute(("a", DICT), + aa = PlainAttribute("b", DICT, + PlainAttribute("a", DICT, Terminator(space, w_cls))) assert aa.space is space assert aa.terminator.w_cls is w_cls @@ -63,16 +63,16 @@ def test_huge_chain(): current = Terminator(space, "cls") for i in range(20000): - current = PlainAttribute((str(i), DICT), current) - assert current.find_map_attr(("0", DICT)).storageindex == 0 + current = PlainAttribute(str(i), DICT, current) + assert current.find_map_attr("0", DICT).storageindex == 0 def test_search(): - aa = PlainAttribute(("b", DICT), PlainAttribute(("a", DICT), Terminator(None, None))) + aa = PlainAttribute("b", DICT, PlainAttribute("a", DICT, Terminator(None, None))) assert aa.search(DICT) is aa assert aa.search(SLOTS_STARTING_FROM) is None assert aa.search(SPECIAL) is None - bb = PlainAttribute(("C", SPECIAL), PlainAttribute(("A", SLOTS_STARTING_FROM), aa)) + bb = PlainAttribute("C", SPECIAL, PlainAttribute("A", SLOTS_STARTING_FROM, aa)) assert bb.search(DICT) is aa assert bb.search(SLOTS_STARTING_FROM) is bb.back assert bb.search(SPECIAL) is bb @@ -320,7 +320,7 @@ d = {} w_d = FakeDict(d) - flag = obj.map.write(obj, ("dict", SPECIAL), w_d) + flag = obj.map.write(obj, "dict", SPECIAL, w_d) assert flag materialize_r_dict(space, obj, d) assert d == {"a": 5, "b": 6, "c": 7} 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 @@ -152,7 +152,7 @@ self.fieldname = fieldname self.FIELD = getattr(S, fieldname) self.index = heaptracker.get_fielddescr_index_in(S, fieldname) - self._is_pure = S._immutable_field(fieldname) + self._is_pure = S._immutable_field(fieldname) != False def is_always_pure(self): return self._is_pure @@ -608,9 +608,6 @@ p = support.cast_arg(lltype.Ptr(descr.S), p) return support.cast_result(descr.FIELD, getattr(p, descr.fieldname)) - bh_getfield_gc_pure_i = bh_getfield_gc - bh_getfield_gc_pure_r = bh_getfield_gc - bh_getfield_gc_pure_f = bh_getfield_gc bh_getfield_gc_i = bh_getfield_gc bh_getfield_gc_r = bh_getfield_gc bh_getfield_gc_f = bh_getfield_gc diff --git a/rpython/jit/backend/llsupport/descr.py b/rpython/jit/backend/llsupport/descr.py --- a/rpython/jit/backend/llsupport/descr.py +++ b/rpython/jit/backend/llsupport/descr.py @@ -180,7 +180,8 @@ return self.offset def repr_of_descr(self): - return '<Field%s %s %s>' % (self.flag, self.name, self.offset) + ispure = " pure" if self._is_pure else "" + return '<Field%s %s %s%s>' % (self.flag, self.name, self.offset, ispure) def get_parent_descr(self): return self.parent_descr @@ -200,7 +201,7 @@ flag = get_type_flag(FIELDTYPE) name = '%s.%s' % (STRUCT._name, fieldname) index_in_parent = heaptracker.get_fielddescr_index_in(STRUCT, fieldname) - is_pure = bool(STRUCT._immutable_field(fieldname)) + is_pure = STRUCT._immutable_field(fieldname) != False fielddescr = FieldDescr(name, offset, size, flag, index_in_parent, is_pure) cachedict = cache.setdefault(STRUCT, {}) diff --git a/rpython/jit/backend/llsupport/rewrite.py b/rpython/jit/backend/llsupport/rewrite.py --- a/rpython/jit/backend/llsupport/rewrite.py +++ b/rpython/jit/backend/llsupport/rewrite.py @@ -234,7 +234,6 @@ self.emit_gc_store_or_indexed(op, ptr_box, index_box, value_box, fieldsize, itemsize, ofs) elif op.getopnum() in (rop.GETFIELD_GC_I, rop.GETFIELD_GC_F, rop.GETFIELD_GC_R, - rop.GETFIELD_GC_PURE_I, rop.GETFIELD_GC_PURE_F, rop.GETFIELD_GC_PURE_R, rop.GETFIELD_RAW_I, rop.GETFIELD_RAW_F, rop.GETFIELD_RAW_R): ofs, itemsize, sign = unpack_fielddescr(op.getdescr()) ptr_box = op.getarg(0) diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1477,9 +1477,6 @@ genop_getfield_gc_f = _genop_getfield genop_getfield_raw_i = _genop_getfield genop_getfield_raw_f = _genop_getfield - genop_getfield_gc_pure_i = _genop_getfield - genop_getfield_gc_pure_r = _genop_getfield - genop_getfield_gc_pure_f = _genop_getfield def _genop_gc_load(self, op, arglocs, resloc): base_loc, ofs_loc, size_loc, sign_loc = arglocs diff --git a/rpython/jit/metainterp/heapcache.py b/rpython/jit/metainterp/heapcache.py --- a/rpython/jit/metainterp/heapcache.py +++ b/rpython/jit/metainterp/heapcache.py @@ -168,9 +168,6 @@ elif (opnum != rop.GETFIELD_GC_R and opnum != rop.GETFIELD_GC_I and opnum != rop.GETFIELD_GC_F and - opnum != rop.GETFIELD_GC_PURE_R and - opnum != rop.GETFIELD_GC_PURE_I and - opnum != rop.GETFIELD_GC_PURE_F and opnum != rop.PTR_EQ and opnum != rop.PTR_NE and opnum != rop.INSTANCE_PTR_EQ and diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -816,9 +816,6 @@ if 'getfield_gc' in check: assert check.pop('getfield_gc') == 0 check['getfield_gc_i'] = check['getfield_gc_r'] = check['getfield_gc_f'] = 0 - if 'getfield_gc_pure' in check: - assert check.pop('getfield_gc_pure') == 0 - check['getfield_gc_pure_i'] = check['getfield_gc_pure_r'] = check['getfield_gc_pure_f'] = 0 if 'getarrayitem_gc_pure' in check: assert check.pop('getarrayitem_gc_pure') == 0 check['getarrayitem_gc_pure_i'] = check['getarrayitem_gc_pure_r'] = check['getarrayitem_gc_pure_f'] = 0 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 @@ -183,6 +183,8 @@ return res def invalidate(self, descr): + if descr.is_always_pure(): + return for opinfo in self.cached_infos: assert isinstance(opinfo, info.AbstractStructPtrInfo) opinfo._fields[descr.get_index()] = None @@ -515,9 +517,14 @@ return pendingfields def optimize_GETFIELD_GC_I(self, op): + descr = op.getdescr() + if descr.is_always_pure() and self.get_constant_box(op.getarg(0)) is not None: + resbox = self.optimizer.constant_fold(op) + self.optimizer.make_constant(op, resbox) + return structinfo = self.ensure_ptr_info_arg0(op) - cf = self.field_cache(op.getdescr()) - field = cf.getfield_from_cache(self, structinfo, op.getdescr()) + cf = self.field_cache(descr) + field = cf.getfield_from_cache(self, structinfo, descr) if field is not None: self.make_equal_to(op, field) return @@ -525,23 +532,10 @@ 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, optheap=self, cf=cf) + structinfo.setfield(descr, op.getarg(0), op, optheap=self, cf=cf) optimize_GETFIELD_GC_R = optimize_GETFIELD_GC_I optimize_GETFIELD_GC_F = optimize_GETFIELD_GC_I - def optimize_GETFIELD_GC_PURE_I(self, op): - structinfo = self.ensure_ptr_info_arg0(op) - cf = self.field_cache(op.getdescr()) - field = cf.getfield_from_cache(self, structinfo, op.getdescr()) - if field is not None: - self.make_equal_to(op, field) - return - # default case: produce the operation - self.make_nonnull(op.getarg(0)) - self.emit_operation(op) - optimize_GETFIELD_GC_PURE_R = optimize_GETFIELD_GC_PURE_I - optimize_GETFIELD_GC_PURE_F = optimize_GETFIELD_GC_PURE_I - def optimize_SETFIELD_GC(self, op): self.setfield(op) #opnum = OpHelpers.getfield_pure_for_descr(op.getdescr()) @@ -631,12 +625,12 @@ def optimize_QUASIIMMUT_FIELD(self, op): # Pattern: QUASIIMMUT_FIELD(s, descr=QuasiImmutDescr) - # x = GETFIELD_GC_PURE(s, descr='inst_x') + # x = GETFIELD_GC(s, descr='inst_x') # pure # If 's' is a constant (after optimizations) we rely on the rest of the - # optimizations to constant-fold the following getfield_gc_pure. + # optimizations to constant-fold the following pure getfield_gc. # in addition, we record the dependency here to make invalidation work # correctly. - # NB: emitting the GETFIELD_GC_PURE is only safe because the + # NB: emitting the pure GETFIELD_GC is only safe because the # QUASIIMMUT_FIELD is also emitted to make sure the dependency is # registered. structvalue = self.ensure_ptr_info_arg0(op) diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py b/rpython/jit/metainterp/optimizeopt/optimizer.py --- a/rpython/jit/metainterp/optimizeopt/optimizer.py +++ b/rpython/jit/metainterp/optimizeopt/optimizer.py @@ -10,6 +10,7 @@ from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.objectmodel import specialize, we_are_translated from rpython.rlib.debug import debug_print +from rpython.jit.metainterp.optimize import SpeculativeError @@ -374,6 +375,7 @@ if (box.type == 'i' and box.get_forwarded() and box.get_forwarded().is_constant()): return ConstInt(box.get_forwarded().getint()) + return None #self.ensure_imported(value) def get_newoperations(self): @@ -736,12 +738,64 @@ self.emit_operation(op) def constant_fold(self, op): + self.protect_speculative_operation(op) argboxes = [self.get_constant_box(op.getarg(i)) for i in range(op.numargs())] return execute_nonspec_const(self.cpu, None, op.getopnum(), argboxes, op.getdescr(), op.type) + def protect_speculative_operation(self, op): + """When constant-folding a pure operation that reads memory from + a gcref, make sure that the gcref is non-null and of a valid type. + Otherwise, raise SpeculativeError. This should only occur when + unrolling and optimizing the unrolled loop. Note that if + cpu.supports_guard_gc_type is false, we can't really do this + check at all, but then we don't unroll in that case. + """ + opnum = op.getopnum() + cpu = self.cpu + + if OpHelpers.is_pure_getfield(opnum, op.getdescr()): + fielddescr = op.getdescr() + ref = self.get_constant_box(op.getarg(0)).getref_base() + cpu.protect_speculative_field(ref, fielddescr) + return + + elif (opnum == rop.GETARRAYITEM_GC_PURE_I or + opnum == rop.GETARRAYITEM_GC_PURE_R or + opnum == rop.GETARRAYITEM_GC_PURE_F or + opnum == rop.ARRAYLEN_GC): + arraydescr = op.getdescr() + array = self.get_constant_box(op.getarg(0)).getref_base() + cpu.protect_speculative_array(array, arraydescr) + if opnum == rop.ARRAYLEN_GC: + return + arraylength = cpu.bh_arraylen_gc(array, arraydescr) + + elif (opnum == rop.STRGETITEM or + opnum == rop.STRLEN): + string = self.get_constant_box(op.getarg(0)).getref_base() + cpu.protect_speculative_string(string) + if opnum == rop.STRLEN: + return + arraylength = cpu.bh_strlen(string) + + elif (opnum == rop.UNICODEGETITEM or + opnum == rop.UNICODELEN): + unicode = self.get_constant_box(op.getarg(0)).getref_base() + cpu.protect_speculative_unicode(unicode) + if opnum == rop.UNICODELEN: + return + arraylength = cpu.bh_unicodelen(unicode) + + else: + return + + index = self.get_constant_box(op.getarg(1)).getint() + if not (0 <= index < arraylength): + raise SpeculativeError + def is_virtual(self, op): if op.type == 'r': opinfo = self.getptrinfo(op) diff --git a/rpython/jit/metainterp/optimizeopt/pure.py b/rpython/jit/metainterp/optimizeopt/pure.py --- a/rpython/jit/metainterp/optimizeopt/pure.py +++ b/rpython/jit/metainterp/optimizeopt/pure.py @@ -94,7 +94,6 @@ break else: # all constant arguments: constant-fold away - self.protect_speculative_operation(op) resbox = self.optimizer.constant_fold(op) # note that INT_xxx_OVF is not done from here, and the # overflows in the INT_xxx operations are ignored @@ -119,59 +118,6 @@ if nextop: self.emit_operation(nextop) - def protect_speculative_operation(self, op): - """When constant-folding a pure operation that reads memory from - a gcref, make sure that the gcref is non-null and of a valid type. - Otherwise, raise SpeculativeError. This should only occur when - unrolling and optimizing the unrolled loop. Note that if - cpu.supports_guard_gc_type is false, we can't really do this - check at all, but then we don't unroll in that case. - """ - opnum = op.getopnum() - cpu = self.optimizer.cpu - - if (opnum == rop.GETFIELD_GC_PURE_I or - opnum == rop.GETFIELD_GC_PURE_R or - opnum == rop.GETFIELD_GC_PURE_F): - fielddescr = op.getdescr() - ref = self.get_constant_box(op.getarg(0)).getref_base() - cpu.protect_speculative_field(ref, fielddescr) - return - - elif (opnum == rop.GETARRAYITEM_GC_PURE_I or - opnum == rop.GETARRAYITEM_GC_PURE_R or - opnum == rop.GETARRAYITEM_GC_PURE_F or - opnum == rop.ARRAYLEN_GC): - arraydescr = op.getdescr() - array = self.get_constant_box(op.getarg(0)).getref_base() - cpu.protect_speculative_array(array, arraydescr) - if opnum == rop.ARRAYLEN_GC: - return - arraylength = cpu.bh_arraylen_gc(array, arraydescr) - - elif (opnum == rop.STRGETITEM or - opnum == rop.STRLEN): - string = self.get_constant_box(op.getarg(0)).getref_base() - cpu.protect_speculative_string(string) - if opnum == rop.STRLEN: - return - arraylength = cpu.bh_strlen(string) - - elif (opnum == rop.UNICODEGETITEM or - opnum == rop.UNICODELEN): - unicode = self.get_constant_box(op.getarg(0)).getref_base() - cpu.protect_speculative_unicode(unicode) - if opnum == rop.UNICODELEN: - return - arraylength = cpu.bh_unicodelen(unicode) - - else: - return - - index = self.get_constant_box(op.getarg(1)).getint() - if not (0 <= index < arraylength): - raise SpeculativeError - def getrecentops(self, opnum): if rop._OVF_FIRST <= opnum <= rop._OVF_LAST: opnum = opnum - rop._OVF_FIRST diff --git a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py --- a/rpython/jit/metainterp/optimizeopt/test/test_dependency.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_dependency.py @@ -521,8 +521,8 @@ def test_getfield(self): graph = self.build_dependency(""" [p0, p1] # 0: 1,2,5 - p2 = getfield_gc_r(p0) # 1: 3,5 - p3 = getfield_gc_r(p0) # 2: 4 + p2 = getfield_gc_r(p0, descr=valuedescr) # 1: 3,5 + p3 = getfield_gc_r(p0, descr=valuedescr) # 2: 4 guard_nonnull(p2) [p2] # 3: 4,5 guard_nonnull(p3) [p3] # 4: 5 jump(p0,p2) # 5: @@ -532,10 +532,10 @@ def test_cyclic(self): graph = self.build_dependency(""" [p0, p1, p5, p6, p7, p9, p11, p12] # 0: 1,6 - p13 = getfield_gc_r(p9) # 1: 2,5 + p13 = getfield_gc_r(p9, descr=valuedescr) # 1: 2,5 guard_nonnull(p13) [] # 2: 4,5 - i14 = getfield_gc_i(p9) # 3: 5 - p15 = getfield_gc_r(p13) # 4: 5 + i14 = getfield_gc_i(p9, descr=valuedescr) # 3: 5 + p15 = getfield_gc_r(p13, descr=valuedescr) # 4: 5 guard_class(p15, 14073732) [p1, p0, p9, i14, p15, p13, p5, p6, p7] # 5: 6 jump(p0,p1,p5,p6,p7,p9,p11,p12) # 6: """) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -955,12 +955,12 @@ """ self.optimize_loop(ops, expected) - def test_getfield_gc_pure_1(self): + def test_getfield_gc_1(self): ops = """ [i] - p1 = new_with_vtable(descr=nodesize) - setfield_gc(p1, i, descr=valuedescr) - i1 = getfield_gc_pure_i(p1, descr=valuedescr) + p1 = new_with_vtable(descr=nodesize3) + setfield_gc(p1, i, descr=valuedescr3) + i1 = getfield_gc_i(p1, descr=valuedescr3) jump(i1) """ expected = """ @@ -969,17 +969,16 @@ """ self.optimize_loop(ops, expected) - def test_getfield_gc_pure_2(self): + def test_getfield_gc_2(self): ops = """ [i] - i1 = getfield_gc_pure_i(ConstPtr(myptr), descr=valuedescr) + i1 = getfield_gc_i(ConstPtr(myptr3), descr=valuedescr3) jump(i1) """ expected = """ [i] - jump(5) - """ - self.node.value = 5 + jump(7) + """ self.optimize_loop(ops, expected) def test_getfield_gc_nonpure_2(self): @@ -1343,7 +1342,7 @@ setfield_gc(p1, i1, descr=valuedescr) # # some operations on which the above setfield_gc cannot have effect - i3 = getarrayitem_gc_pure_i(p3, 1, descr=arraydescr) + i3 = getarrayitem_gc_i(p3, 1, descr=arraydescr) i4 = getarrayitem_gc_i(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) setarrayitem_gc(p3, 0, i5, descr=arraydescr) @@ -1355,7 +1354,7 @@ expected = """ [p1, i1, i2, p3] # - i3 = getarrayitem_gc_pure_i(p3, 1, descr=arraydescr) + i3 = getarrayitem_gc_i(p3, 1, descr=arraydescr) i4 = getarrayitem_gc_i(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) # @@ -1597,7 +1596,7 @@ ops = """ [p1, p2] p3 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) - i4 = getfield_gc_pure_i(ConstPtr(myptr), descr=valuedescr) + i4 = getfield_gc_i(ConstPtr(myptr3), descr=valuedescr3) p5 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) escape_n(p3) escape_n(i4) @@ -1608,7 +1607,7 @@ [p1, p2] p3 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) escape_n(p3) - escape_n(5) + escape_n(7) escape_n(p3) jump(p1, p2) """ @@ -5076,7 +5075,7 @@ [] quasiimmut_field(ConstPtr(quasiptr), descr=quasiimmutdescr) guard_not_invalidated() [] - i0 = getfield_gc_pure_i(ConstPtr(quasiptr), descr=quasifielddescr) + i0 = getfield_gc_i(ConstPtr(quasiptr), descr=quasifielddescr) i1 = call_pure_i(123, i0, descr=nonwritedescr) finish(i1) """ @@ -5462,15 +5461,15 @@ def test_getarrayitem_gc_pure_not_invalidated(self): ops = """ [p0] - i1 = getarrayitem_gc_pure_i(p0, 1, descr=arraydescr) + i1 = getarrayitem_gc_pure_i(p0, 1, descr=arrayimmutdescr) escape_n(p0) - i2 = getarrayitem_gc_pure_i(p0, 1, descr=arraydescr) + i2 = getarrayitem_gc_pure_i(p0, 1, descr=arrayimmutdescr) escape_n(i2) jump(p0) """ expected = """ [p0] - i1 = getarrayitem_gc_pure_i(p0, 1, descr=arraydescr) + i1 = getarrayitem_gc_pure_i(p0, 1, descr=arrayimmutdescr) escape_n(p0) escape_n(i1) jump(p0) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1409,12 +1409,12 @@ """ self.optimize_loop(ops, expected) - def test_getfield_gc_pure_1(self): + def test_pure_getfield_gc_1(self): ops = """ [i] p1 = new_with_vtable(descr=nodesize) setfield_gc(p1, i, descr=valuedescr) - i1 = getfield_gc_pure_i(p1, descr=valuedescr) + i1 = getfield_gc_i(p1, descr=valuedescr) jump(i1) """ expected = """ @@ -1423,10 +1423,10 @@ """ self.optimize_loop(ops, expected) - def test_getfield_gc_pure_2(self): + def test_pure_getfield_gc_2(self): ops = """ [i] - i1 = getfield_gc_pure_i(ConstPtr(myptr), descr=valuedescr) + i1 = getfield_gc_i(ConstPtr(myptr3), descr=valuedescr3) jump(i1) """ expected = """ @@ -1436,20 +1436,20 @@ self.node.value = 5 self.optimize_loop(ops, expected) - def test_getfield_gc_pure_3(self): + def test_pure_getfield_gc_3(self): ops = """ [] p1 = escape_r() - p2 = getfield_gc_pure_r(p1, descr=nextdescr) + p2 = getfield_gc_r(p1, descr=nextdescr3) escape_n(p2) - p3 = getfield_gc_pure_r(p1, descr=nextdescr) + p3 = getfield_gc_r(p1, descr=nextdescr3) escape_n(p3) jump() """ expected = """ [] p1 = escape_r() - p2 = getfield_gc_pure_r(p1, descr=nextdescr) + p2 = getfield_gc_r(p1, descr=nextdescr3) escape_n(p2) escape_n(p2) jump() @@ -2319,7 +2319,7 @@ setfield_gc(p1, i1, descr=valuedescr) # # some operations on which the above setfield_gc cannot have effect - i3 = getarrayitem_gc_pure_i(p3, 1, descr=arraydescr) + i3 = getarrayitem_gc_i(p3, 1, descr=arraydescr) i4 = getarrayitem_gc_i(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) setarrayitem_gc(p3, 0, i5, descr=arraydescr) @@ -2332,7 +2332,7 @@ preamble = """ [p1, i1, i2, p3] # - i3 = getarrayitem_gc_pure_i(p3, 1, descr=arraydescr) + i3 = getarrayitem_gc_i(p3, 1, descr=arraydescr) i4 = getarrayitem_gc_i(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) # @@ -2340,11 +2340,12 @@ setfield_gc(p1, i4, descr=nextdescr) setarrayitem_gc(p3, 0, i5, descr=arraydescr) escape_n() - jump(p1, i1, i2, p3, i3) - """ - expected = """ - [p1, i1, i2, p3, i3] + jump(p1, i1, i2, p3) + """ + expected = """ + [p1, i1, i2, p3] # + i3 = getarrayitem_gc_i(p3, 1, descr=arraydescr) i4 = getarrayitem_gc_i(p3, i3, descr=arraydescr) i5 = int_add(i3, i4) # @@ -2352,8 +2353,7 @@ setfield_gc(p1, i4, descr=nextdescr) setarrayitem_gc(p3, 0, i5, descr=arraydescr) escape_n() - ifoo = arraylen_gc(p3, descr=arraydescr) # killed by the backend - jump(p1, i1, i2, p3, i3) + jump(p1, i1, i2, p3) """ self.optimize_loop(ops, expected, preamble) @@ -2669,7 +2669,7 @@ ops = """ [p1, p2] p3 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) - i4 = getfield_gc_pure_i(ConstPtr(myptr), descr=valuedescr) + i4 = getfield_gc_i(ConstPtr(myptr3), descr=valuedescr3) p5 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) escape_n(p3) escape_n(i4) @@ -2680,7 +2680,7 @@ [p1, p2] p3 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) escape_n(p3) - escape_n(5) + escape_n(7) escape_n(p3) jump(p1, p2) """ @@ -3302,8 +3302,8 @@ [p8, p11, i24] p26 = new(descr=ssize) setfield_gc(p26, i24, descr=adescr) - i34 = getfield_gc_pure_i(p11, descr=abisdescr) - i35 = getfield_gc_pure_i(p26, descr=adescr) + i34 = getfield_gc_i(p11, descr=abisdescr) + i35 = getfield_gc_i(p26, descr=adescr) i36 = int_add_ovf(i34, i35) guard_no_overflow() [] jump(p8, p11, i35) @@ -3330,8 +3330,8 @@ setfield_gc(p26, i24, descr=adescr) i28 = int_add(i17, 1) setfield_gc(p8, i28, descr=valuedescr) - i34 = getfield_gc_pure_i(p11, descr=valuedescr3) - i35 = getfield_gc_pure_i(p26, descr=adescr) + i34 = getfield_gc_i(p11, descr=valuedescr3) + i35 = getfield_gc_i(p26, descr=adescr) guard_nonnull(p12) [] i36 = int_add_ovf(i34, i35) guard_no_overflow() [] @@ -3522,14 +3522,14 @@ def test_residual_call_does_not_invalidate_immutable_caches(self): ops = """ [p1] - i1 = getfield_gc_pure_i(p1, descr=valuedescr3) + i1 = getfield_gc_i(p1, descr=valuedescr3) i2 = call_i(i1, descr=writevalue3descr) - i3 = getfield_gc_pure_i(p1, descr=valuedescr3) + i3 = getfield_gc_i(p1, descr=valuedescr3) jump(p1) """ expected_preamble = """ [p1] - i1 = getfield_gc_pure_i(p1, descr=valuedescr3) + i1 = getfield_gc_i(p1, descr=valuedescr3) i2 = call_i(i1, descr=writevalue3descr) jump(p1, i1) """ @@ -4878,11 +4878,11 @@ def test_add_sub_ovf_virtual_unroll(self): ops = """ [p15] - i886 = getfield_gc_pure_i(p15, descr=valuedescr) + i886 = getfield_gc_i(p15, descr=valuedescr) i888 = int_sub_ovf(i886, 1) guard_no_overflow() [] escape_n(i888) - i4360 = getfield_gc_pure_i(p15, descr=valuedescr) + i4360 = getfield_gc_i(p15, descr=valuedescr) i4362 = int_add_ovf(i4360, 1) guard_no_overflow() [] i4360p = int_sub_ovf(i4362, 1) @@ -4972,18 +4972,16 @@ def test_pure(self): ops = """ [p42] - p53 = getfield_gc_r(ConstPtr(myptr), descr=nextdescr) - p59 = getfield_gc_pure_r(p53, descr=valuedescr) + p53 = getfield_gc_r(ConstPtr(myptr3), descr=nextdescr3) + p59 = getfield_gc_r(p53, descr=valuedescr3) i61 = call_i(1, p59, descr=nonwritedescr) jump(p42) """ expected = """ - [p42, p59] - i61 = call_i(1, p59, descr=nonwritedescr) - jump(p42, p59) - - """ - self.node.value = 5 + [p42] + i61 = call_i(1, 7, descr=nonwritedescr) + jump(p42) + """ self.optimize_loop(ops, expected) def test_complains_getfieldpure_setfield(self): @@ -4992,7 +4990,7 @@ ops = """ [p3] p1 = escape_r() - p2 = getfield_gc_pure_r(p1, descr=nextdescr) + p2 = getfield_gc_r(p1, descr=nextdescr) setfield_gc(p1, p3, descr=nextdescr) jump(p3) """ @@ -5002,7 +5000,7 @@ ops = """ [p3] p1 = escape_r() - p2 = getfield_gc_pure_r(p1, descr=nextdescr) + p2 = getfield_gc_r(p1, descr=nextdescr3) setfield_gc(p1, p3, descr=otherdescr) escape_n(p2) jump(p3) @@ -5010,7 +5008,7 @@ expected = """ [p3] p1 = escape_r() - p2 = getfield_gc_pure_r(p1, descr=nextdescr) + p2 = getfield_gc_r(p1, descr=nextdescr3) setfield_gc(p1, p3, descr=otherdescr) escape_n(p2) jump(p3) @@ -5021,7 +5019,7 @@ ops = """ [] p1 = escape_r() - p2 = getfield_gc_pure_r(p1, descr=nextdescr) + p2 = getfield_gc_r(p1, descr=nextdescr) p3 = escape_r() setfield_gc(p3, p1, descr=nextdescr) jump() @@ -6167,14 +6165,14 @@ def test_bug_unroll_with_immutables(self): ops = """ [p0] - i2 = getfield_gc_pure_i(p0, descr=immut_intval) + i2 = getfield_gc_i(p0, descr=immut_intval) p1 = new_with_vtable(descr=immut_descr) setfield_gc(p1, 1242, descr=immut_intval) jump(p1) """ preamble = """ [p0] - i2 = getfield_gc_pure_i(p0, descr=immut_intval) + i2 = getfield_gc_i(p0, descr=immut_intval) jump() """ expected = """ @@ -7229,13 +7227,13 @@ [p0, p1, i0] quasiimmut_field(p0, descr=quasiimmutdescr) guard_not_invalidated() [] - i1 = getfield_gc_pure_i(p0, descr=quasifielddescr) + i1 = getfield_gc_i(p0, descr=quasifielddescr) escape_n(i1) jump(p1, p0, i1) """ expected = """ [p0, p1, i0] - i1 = getfield_gc_pure_i(p0, descr=quasifielddescr) + i1 = getfield_gc_i(p0, descr=quasifielddescr) escape_n(i1) jump(p1, p0, i1) """ @@ -7246,7 +7244,7 @@ [] quasiimmut_field(ConstPtr(quasiptr), descr=quasiimmutdescr) guard_not_invalidated() [] - i1 = getfield_gc_pure_i(ConstPtr(quasiptr), descr=quasifielddescr) + i1 = getfield_gc_i(ConstPtr(quasiptr), descr=quasifielddescr) escape_n(i1) jump() """ @@ -7298,11 +7296,11 @@ [i0a, i0b] quasiimmut_field(ConstPtr(quasiptr), descr=quasiimmutdescr) guard_not_invalidated() [] - i1 = getfield_gc_pure_i(ConstPtr(quasiptr), descr=quasifielddescr) + i1 = getfield_gc_i(ConstPtr(quasiptr), descr=quasifielddescr) call_may_force_n(i0b, descr=mayforcevirtdescr) quasiimmut_field(ConstPtr(quasiptr), descr=quasiimmutdescr) guard_not_invalidated() [] - i2 = getfield_gc_pure_i(ConstPtr(quasiptr), descr=quasifielddescr) + i2 = getfield_gc_i(ConstPtr(quasiptr), descr=quasifielddescr) i3 = escape_i(i1) i4 = escape_i(i2) jump(i3, i4) @@ -7325,11 +7323,11 @@ setfield_gc(p, 421, descr=quasifielddescr) quasiimmut_field(p, descr=quasiimmutdescr) guard_not_invalidated() [] - i1 = getfield_gc_pure_i(p, descr=quasifielddescr) + i1 = getfield_gc_i(p, descr=quasifielddescr) call_may_force_n(i0b, descr=mayforcevirtdescr) quasiimmut_field(p, descr=quasiimmutdescr) guard_not_invalidated() [] - i2 = getfield_gc_pure_i(p, descr=quasifielddescr) + i2 = getfield_gc_i(p, descr=quasifielddescr) i3 = escape_i(i1) i4 = escape_i(i2) jump(i3, i4) @@ -7568,7 +7566,7 @@ def test_forced_virtual_pure_getfield(self): ops = """ [p0] - p1 = getfield_gc_pure_r(p0, descr=valuedescr) + p1 = getfield_gc_r(p0, descr=valuedescr3) jump(p1) """ self.optimize_loop(ops, ops) @@ -7578,7 +7576,7 @@ p1 = new_with_vtable(descr=nodesize3) setfield_gc(p1, p0, descr=valuedescr3) escape_n(p1) - p2 = getfield_gc_pure_r(p1, descr=valuedescr3) + p2 = getfield_gc_r(p1, descr=valuedescr3) escape_n(p2) jump(p0) """ @@ -7852,14 +7850,14 @@ def test_loopinvariant_getarrayitem_gc_pure(self): ops = """ [p9, i1] - i843 = getarrayitem_gc_pure_i(p9, i1, descr=arraydescr) + i843 = getarrayitem_gc_pure_i(p9, i1, descr=arrayimmutdescr) call_n(i843, descr=nonwritedescr) jump(p9, i1) """ expected = """ [p9, i1, i843] call_n(i843, descr=nonwritedescr) - ifoo = arraylen_gc(p9, descr=arraydescr) + ifoo = arraylen_gc(p9, descr=arrayimmutdescr) jump(p9, i1, i843) """ self.optimize_loop(ops, expected) @@ -7868,7 +7866,7 @@ ops = """ [p0] p1 = getfield_gc_r(p0, descr=nextdescr) - p2 = getarrayitem_gc_pure_r(p1, 7, descr=gcarraydescr) + p2 = getarrayitem_gc_r(p1, 7, descr=gcarraydescr) call_n(p2, descr=nonwritedescr) jump(p0) """ @@ -7883,14 +7881,14 @@ i1 = arraylen_gc(p1, descr=gcarraydescr) i2 = int_ge(i1, 8) guard_true(i2) [] - p2 = getarrayitem_gc_pure_r(p1, 7, descr=gcarraydescr) - jump(p2, p1) - """ - expected = """ - [p0, p2, p1] + p2 = getarrayitem_gc_r(p1, 7, descr=gcarraydescr) + jump(p1, p2) + """ + expected = """ + [p0, p1, p2] call_n(p2, descr=nonwritedescr) i3 = arraylen_gc(p1, descr=gcarraydescr) # Should be killed by backend - jump(p0, p2, p1) + jump(p0, p1, p2) """ self.optimize_loop(ops, expected, expected_short=short) @@ -8065,7 +8063,7 @@ def test_dont_mixup_equal_boxes(self): ops = """ [p8] - i9 = getfield_gc_pure_i(p8, descr=valuedescr) + i9 = getfield_gc_i(p8, descr=valuedescr3) i10 = int_gt(i9, 0) guard_true(i10) [] i29 = int_lshift(i9, 1) @@ -8160,9 +8158,9 @@ py.test.skip("would be fixed by make heap optimizer aware of virtual setfields") ops = """ [p5, p8] - i9 = getfield_gc_pure_i(p5, descr=valuedescr) + i9 = getfield_gc_i(p5, descr=valuedescr) call_n(i9, descr=nonwritedescr) - i11 = getfield_gc_pure_i(p8, descr=valuedescr) + i11 = getfield_gc_i(p8, descr=valuedescr) i13 = int_add_ovf(i11, 1) guard_no_overflow() [] p22 = new_with_vtable(descr=nodesize) @@ -8201,14 +8199,14 @@ ops = """ [p0] p10 = getfield_gc_r(ConstPtr(myptr), descr=otherdescr) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit