Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit