Author: Richard Plangger <planri...@gmail.com> Branch: s390x-backend Changeset: r81944:c6029ee6abcc Date: 2016-01-26 08:47 +0100 http://bitbucket.org/pypy/pypy/changeset/c6029ee6abcc/
Log: merged default 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 @@ -124,6 +124,15 @@ 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. + .. branch: memop-simplify3 Further simplifying the backend operations malloc_cond_varsize and zero_array. 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/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/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/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 @@ -243,7 +243,6 @@ self.emit_gc_store_or_indexed(op, ptr_box, index_box, value_box, fieldsize, itemsize, ofs) elif opnum 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) @@ -497,8 +496,8 @@ elif arraydescr.itemsize == 0: total_size = arraydescr.basesize elif (self.gc_ll_descr.can_use_nursery_malloc(1) and - self.gen_malloc_nursery_varsize(arraydescr.itemsize, v_length, - op, arraydescr, kind=kind)): + self.gen_malloc_nursery_varsize(arraydescr.itemsize, + v_length, op, arraydescr, kind=kind)): # note that we cannot initialize tid here, because the array # might end up being allocated by malloc_external or some # stuff that initializes GC header fields differently @@ -534,8 +533,6 @@ # See emit_pending_zeros(). (This optimization is done by # hacking the object 'o' in-place: e.g., o.getarg(1) may be # replaced with another constant greater than 0.) - #o = ResOperation(rop.ZERO_ARRAY, [v_arr, self.c_zero, v_length], - # descr=arraydescr) assert isinstance(arraydescr, ArrayDescr) scale = arraydescr.itemsize v_length_scaled = v_length 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) - guard_value(p10, ConstPtr(myptr2)) [] + guard_value(p10, ConstPtr(myptrb)) [] call_n(p10, descr=nonwritedescr) - setfield_gc(ConstPtr(myptr), ConstPtr(myptr2), descr=otherdescr) + setfield_gc(ConstPtr(myptr), ConstPtr(myptrb), descr=otherdescr) jump(p0) """ expected = """ [p0] - call_n(ConstPtr(myptr2), descr=nonwritedescr) + call_n(ConstPtr(myptrb), descr=nonwritedescr) jump(p0) """ self.optimize_loop(ops, expected) @@ -8232,14 +8230,14 @@ ops = """ [p0] p10 = getfield_gc_r(p0, descr=otherdescr) - guard_value(p10, ConstPtr(myptr2)) [] + guard_value(p10, ConstPtr(myptrb)) [] call_n(p10, descr=nonwritedescr) - setfield_gc(p0, ConstPtr(myptr2), descr=otherdescr) + setfield_gc(p0, ConstPtr(myptrb), descr=otherdescr) jump(p0) """ expected = """ [p0] - call_n(ConstPtr(myptr2), descr=nonwritedescr) + call_n(ConstPtr(myptrb), descr=nonwritedescr) jump(p0) """ self.optimize_loop(ops, expected) @@ -8624,17 +8622,17 @@ [p10] p52 = getfield_gc_r(p10, descr=nextdescr) # inst_storage p54 = getarrayitem_gc_r(p52, 0, descr=arraydescr) - p69 = getfield_gc_pure_r(p54, descr=otherdescr) # inst_w_function + p69 = getfield_gc_r(p54, descr=otherdescr) # inst_w_function quasiimmut_field(p69, descr=quasiimmutdescr) guard_not_invalidated() [] - p71 = getfield_gc_pure_r(p69, descr=quasifielddescr) # inst_code + p71 = getfield_gc_r(p69, descr=quasifielddescr) # inst_code guard_value(p71, -4247) [] p106 = new_with_vtable(descr=nodesize) p108 = new_array(3, descr=arraydescr) p110 = new_with_vtable(descr=nodesize) - setfield_gc(p110, ConstPtr(myptr2), descr=otherdescr) # inst_w_function + setfield_gc(p110, ConstPtr(myptrb), descr=otherdescr) # inst_w_function setarrayitem_gc(p108, 0, p110, descr=arraydescr) setfield_gc(p106, p108, descr=nextdescr) # inst_storage jump(p106) @@ -8650,7 +8648,7 @@ [p69] quasiimmut_field(p69, descr=quasiimmutdescr) guard_not_invalidated() [] - p71 = getfield_gc_pure_r(p69, descr=quasifielddescr) # inst_code + p71 = getfield_gc_r(p69, descr=quasifielddescr) # inst_code guard_value(p71, -4247) [] jump(ConstPtr(myptr)) """ @@ -8852,13 +8850,13 @@ def test_virtual_back_and_forth(self): ops = """ [p0] - p1 = getfield_gc_pure_r(p0, descr=bdescr) + p1 = getfield_gc_r(p0, descr=nextdescr3) ptemp = new_with_vtable(descr=nodesize) setfield_gc(ptemp, p1, descr=nextdescr) p2 = getfield_gc_r(ptemp, descr=nextdescr) - ix = getarrayitem_gc_pure_i(p2, 0, descr=arraydescr) + ix = getarrayitem_gc_pure_i(p2, 0, descr=arrayimmutdescr) pfoo = getfield_gc_r(ptemp, descr=nextdescr) - guard_value(pfoo, ConstPtr(myarray)) [] + guard_value(pfoo, ConstPtr(immutarray)) [] ifoo = int_add(ix, 13) escape_n(ix) jump(p0) @@ -8888,13 +8886,13 @@ def test_constant_float_pure(self): ops = """ [p0] - f0 = getarrayitem_gc_pure_f(p0, 3, descr=floatarraydescr) + f0 = getarrayitem_gc_pure_f(p0, 3, descr=floatarrayimmutdescr) guard_value(f0, 1.03) [] jump(p0) """ expected = """ [p0] - ifoo = arraylen_gc(p0, descr=floatarraydescr) + ifoo = arraylen_gc(p0, descr=floatarrayimmutdescr) jump(p0) """ self.optimize_loop(ops, expected) @@ -9102,7 +9100,7 @@ [p0, i1] i2 = int_gt(i1, 0) guard_true(i2) [] - getfield_gc_pure_i(p0, descr=valuedescr) + getfield_gc_i(p0, descr=valuedescr3) i3 = int_sub(i1, 1) jump(NULL, i3) """ @@ -9113,9 +9111,9 @@ [p0, i1] i2 = int_gt(i1, 0) guard_true(i2) [] - getfield_gc_pure_i(p0, descr=valuedescr) + getfield_gc_i(p0, descr=valuedescr3) i3 = int_sub(i1, 1) - jump(ConstPtr(myptr4), i3) + jump(ConstPtr(myptr2), i3) """ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops) @@ -9265,9 +9263,126 @@ guard_value(i1, 5) [] jump() """ - a = lltype.malloc(lltype.GcArray(lltype.Ptr(self.NODE)), 5, zero=True) + a = lltype.malloc(lltype.GcArray(lltype.Ptr(self.NODE3)), 5, zero=True) self.optimize_loop(ops, expected, jump_values=[a]) + def test_large_number_of_immutable_references(self): + ops = """ + [p0] + i0 = getfield_gc_i(p0, descr=bigadescr) + i1 = getfield_gc_i(p0, descr=bigbdescr) + i2 = getfield_gc_i(p0, descr=bigcdescr) + i3 = getfield_gc_i(p0, descr=bigddescr) + i4 = getfield_gc_i(p0, descr=bigedescr) + i5 = getfield_gc_i(p0, descr=bigfdescr) + i6 = getfield_gc_i(p0, descr=biggdescr) + i7 = getfield_gc_i(p0, descr=bighdescr) + i8 = getfield_gc_i(p0, descr=bigidescr) + i9 = getfield_gc_i(p0, descr=bigjdescr) + i10 = getfield_gc_i(p0, descr=bigkdescr) + i11 = getfield_gc_i(p0, descr=bigldescr) + i12 = getfield_gc_i(p0, descr=bigmdescr) + i13 = getfield_gc_i(p0, descr=bigndescr) + i14 = getfield_gc_i(p0, descr=bigodescr) + i15 = getfield_gc_i(p0, descr=bigpdescr) + i16 = getfield_gc_i(p0, descr=bigqdescr) + i17 = getfield_gc_i(p0, descr=bigrdescr) + i18 = getfield_gc_i(p0, descr=bigsdescr) + i19 = getfield_gc_i(p0, descr=bigtdescr) + i20 = getfield_gc_i(p0, descr=bigudescr) + i21 = getfield_gc_i(p0, descr=bigvdescr) + i22 = getfield_gc_i(p0, descr=bigwdescr) + i23 = getfield_gc_i(p0, descr=bigxdescr) + i24 = getfield_gc_i(p0, descr=bigydescr) + i25 = getfield_gc_i(p0, descr=bigzdescr) + i27 = getfield_gc_i(p0, descr=bigbdescr) + i28 = getfield_gc_i(p0, descr=bigcdescr) + i29 = getfield_gc_i(p0, descr=bigddescr) + i30 = getfield_gc_i(p0, descr=bigedescr) + i31 = getfield_gc_i(p0, descr=bigfdescr) + i32 = getfield_gc_i(p0, descr=biggdescr) + i33 = getfield_gc_i(p0, descr=bighdescr) + i34 = getfield_gc_i(p0, descr=bigidescr) + i35 = getfield_gc_i(p0, descr=bigjdescr) + i36 = getfield_gc_i(p0, descr=bigkdescr) + i37 = getfield_gc_i(p0, descr=bigldescr) + i38 = getfield_gc_i(p0, descr=bigmdescr) + i39 = getfield_gc_i(p0, descr=bigndescr) + i40 = getfield_gc_i(p0, descr=bigodescr) + i41 = getfield_gc_i(p0, descr=bigpdescr) + i42 = getfield_gc_i(p0, descr=bigqdescr) + i43 = getfield_gc_i(p0, descr=bigrdescr) + i44 = getfield_gc_i(p0, descr=bigsdescr) + i45 = getfield_gc_i(p0, descr=bigtdescr) + i46 = getfield_gc_i(p0, descr=bigudescr) + i47 = getfield_gc_i(p0, descr=bigvdescr) + i48 = getfield_gc_i(p0, descr=bigwdescr) + i49 = getfield_gc_i(p0, descr=bigxdescr) + i50 = getfield_gc_i(p0, descr=bigydescr) + i51 = getfield_gc_i(p0, descr=bigzdescr) + i26 = getfield_gc_i(p0, descr=bigadescr) + i99 = int_add(i26, i51) + escape_i(i27) + escape_i(i28) + escape_i(i29) + escape_i(i30) + escape_i(i31) + escape_i(i32) + escape_i(i33) + escape_i(i34) + escape_i(i35) + escape_i(i36) + escape_i(i37) + escape_i(i38) + escape_i(i39) + escape_i(i40) + escape_i(i41) + escape_i(i42) + escape_i(i43) + escape_i(i44) + escape_i(i45) + escape_i(i46) + escape_i(i47) + escape_i(i48) + escape_i(i49) + escape_i(i50) + escape_i(i51) + escape_i(i26) + escape_i(i99) + jump(p0) + """ + expected = """ + [p0,i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15,i16,i17,i18,i19,i20,i21,i22,i23,i24,i25,i0,i99] + escape_i(i1) + escape_i(i2) + escape_i(i3) + escape_i(i4) + escape_i(i5) + escape_i(i6) + escape_i(i7) + escape_i(i8) + escape_i(i9) + escape_i(i10) + escape_i(i11) + escape_i(i12) + escape_i(i13) + escape_i(i14) + escape_i(i15) + escape_i(i16) + escape_i(i17) + escape_i(i18) + escape_i(i19) + escape_i(i20) + escape_i(i21) + escape_i(i22) + escape_i(i23) + escape_i(i24) + escape_i(i25) + escape_i(i0) + escape_i(i99) + jump(p0,i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15,i16,i17,i18,i19,i20,i21,i22,i23,i24,i25,i0,i99) + """ + self.optimize_loop(ops, expected) class TestLLtype(OptimizeOptTest, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/test/test_unroll.py b/rpython/jit/metainterp/optimizeopt/test/test_unroll.py --- a/rpython/jit/metainterp/optimizeopt/test/test_unroll.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_unroll.py @@ -220,16 +220,16 @@ def test_double_getfield_plus_pure(self): loop = """ [p0] - pc = getfield_gc_pure_r(p0, descr=nextdescr) + pc = getfield_gc_r(p0, descr=nextdescr3) escape_n(p0) # that should flush the caches - p1 = getfield_gc_r(pc, descr=nextdescr) - i0 = getfield_gc_i(p1, descr=valuedescr) + p1 = getfield_gc_r(pc, descr=nextdescr3) + i0 = getfield_gc_i(p1, descr=valuedescr3) jump(p0) """ es, loop, preamble = self.optimize(loop) assert len(es.short_boxes) == 4 # both getfields are available as - # well as getfield_gc_pure + # well as getfield_gc def test_p123_anti_nested(self): loop = """ diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py --- a/rpython/jit/metainterp/optimizeopt/test/test_util.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py @@ -1,4 +1,4 @@ -import py, random +import py, random, string from rpython.rlib.debug import debug_print from rpython.rtyper.lltypesystem import lltype, llmemory, rffi @@ -122,7 +122,14 @@ ('value', lltype.Signed), ('next', lltype.Ptr(NODE3)), hints={'immutable': True})) - + + big_fields = [('big' + i, lltype.Signed) for i in string.ascii_lowercase] + BIG = lltype.GcForwardReference() + BIG.become(lltype.GcStruct('BIG', *big_fields, hints={'immutable': True})) + + for field, _ in big_fields: + locals()[field + 'descr'] = cpu.fielddescrof(BIG, field) + node = lltype.malloc(NODE) node.value = 5 node.next = node @@ -133,16 +140,25 @@ node2.parent.parent.typeptr = node_vtable2 node2addr = lltype.cast_opaque_ptr(llmemory.GCREF, node2) myptr = lltype.cast_opaque_ptr(llmemory.GCREF, node) - mynode2 = lltype.malloc(NODE) + mynodeb = lltype.malloc(NODE) myarray = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(lltype.GcArray(lltype.Signed), 13, zero=True)) - mynode2.parent.typeptr = node_vtable - myptr2 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode2) - mynode3 = lltype.malloc(NODE2) - mynode3.parent.parent.typeptr = node_vtable2 + mynodeb.parent.typeptr = node_vtable + myptrb = lltype.cast_opaque_ptr(llmemory.GCREF, mynodeb) + myptr2 = lltype.malloc(NODE2) + myptr2.parent.parent.typeptr = node_vtable2 + myptr2 = lltype.cast_opaque_ptr(llmemory.GCREF, myptr2) + nullptr = lltype.nullptr(llmemory.GCREF.TO) + + mynode3 = lltype.malloc(NODE3) + mynode3.parent.typeptr = node_vtable3 + mynode3.value = 7 + mynode3.next = mynode3 myptr3 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode3) # a NODE2 mynode4 = lltype.malloc(NODE3) mynode4.parent.typeptr = node_vtable3 myptr4 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode4) # a NODE3 + + nullptr = lltype.nullptr(llmemory.GCREF.TO) #nodebox2 = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, node2)) nodesize = cpu.sizeof(NODE, node_vtable) @@ -203,7 +219,6 @@ arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed)) int32arraydescr = cpu.arraydescrof(lltype.GcArray(rffi.INT)) int16arraydescr = cpu.arraydescrof(lltype.GcArray(rffi.SHORT)) - floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float)) float32arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.SingleFloat)) arraydescr_tid = arraydescr.get_type_id() array = lltype.malloc(lltype.GcArray(lltype.Signed), 15, zero=True) @@ -212,6 +227,12 @@ array2ref = lltype.cast_opaque_ptr(llmemory.GCREF, array2) gcarraydescr = cpu.arraydescrof(lltype.GcArray(llmemory.GCREF)) gcarraydescr_tid = gcarraydescr.get_type_id() + floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float)) + + arrayimmutdescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed, hints={"immutable": True})) + immutarray = lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(arrayimmutdescr.A, 13, zero=True)) + gcarrayimmutdescr = cpu.arraydescrof(lltype.GcArray(llmemory.GCREF, hints={"immutable": True})) + floatarrayimmutdescr = cpu.arraydescrof(lltype.GcArray(lltype.Float, hints={"immutable": True})) # a GcStruct not inheriting from OBJECT tpl = lltype.malloc(S, zero=True) @@ -244,7 +265,7 @@ tsize = cpu.sizeof(T, None) cdescr = cpu.fielddescrof(T, 'c') ddescr = cpu.fielddescrof(T, 'd') - arraydescr3 = cpu.arraydescrof(lltype.GcArray(lltype.Ptr(NODE))) + arraydescr3 = cpu.arraydescrof(lltype.GcArray(lltype.Ptr(NODE3))) U = lltype.GcStruct('U', ('parent', OBJECT), diff --git a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py --- a/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_virtualstate.py @@ -1103,8 +1103,8 @@ jump(p0) """ self.optimize_bridge(loops, bridge, loops[0], 'Loop0', [self.myptr]) - self.optimize_bridge(loops, bridge, loops[1], 'Loop1', [self.myptr3]) - self.optimize_bridge(loops[0], bridge, 'RETRACE', [self.myptr3]) + self.optimize_bridge(loops, bridge, loops[1], 'Loop1', [self.myptr2]) + self.optimize_bridge(loops[0], bridge, 'RETRACE', [self.myptr2]) self.optimize_bridge(loops, loops[0], loops[0], 'Loop0', [self.nullptr]) self.optimize_bridge(loops, loops[1], loops[1], 'Loop1', [self.nullptr]) diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -188,12 +188,6 @@ optimize_GETFIELD_GC_R = optimize_GETFIELD_GC_I optimize_GETFIELD_GC_F = optimize_GETFIELD_GC_I - # note: the following line does not mean that the two operations are - # completely equivalent, because GETFIELD_GC_PURE is_always_pure(). - optimize_GETFIELD_GC_PURE_I = optimize_GETFIELD_GC_I - optimize_GETFIELD_GC_PURE_R = optimize_GETFIELD_GC_I - optimize_GETFIELD_GC_PURE_F = optimize_GETFIELD_GC_I - def optimize_SETFIELD_GC(self, op): struct = op.getarg(0) opinfo = self.getptrinfo(struct) diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -653,46 +653,37 @@ @arguments("box", "descr") def opimpl_getfield_gc_i(self, box, fielddescr): + if fielddescr.is_always_pure() and isinstance(box, ConstPtr): + # if 'box' is directly a ConstPtr, bypass the heapcache completely + resbox = executor.execute(self.metainterp.cpu, self.metainterp, + rop.GETFIELD_GC_I, fielddescr, box) + return ConstInt(resbox) return self._opimpl_getfield_gc_any_pureornot( rop.GETFIELD_GC_I, box, fielddescr, 'i') + + @arguments("box", "descr") + def opimpl_getfield_gc_f(self, box, fielddescr): + if fielddescr.is_always_pure() and isinstance(box, ConstPtr): + # if 'box' is directly a ConstPtr, bypass the heapcache completely + resvalue = executor.execute(self.metainterp.cpu, self.metainterp, + rop.GETFIELD_GC_F, fielddescr, box) + return ConstFloat(resvalue) + return self._opimpl_getfield_gc_any_pureornot( + rop.GETFIELD_GC_F, box, fielddescr, 'f') + @arguments("box", "descr") def opimpl_getfield_gc_r(self, box, fielddescr): + if fielddescr.is_always_pure() and isinstance(box, ConstPtr): + # if 'box' is directly a ConstPtr, bypass the heapcache completely + val = executor.execute(self.metainterp.cpu, self.metainterp, + rop.GETFIELD_GC_R, fielddescr, box) + return ConstPtr(val) return self._opimpl_getfield_gc_any_pureornot( rop.GETFIELD_GC_R, box, fielddescr, 'r') - @arguments("box", "descr") - def opimpl_getfield_gc_f(self, box, fielddescr): - return self._opimpl_getfield_gc_any_pureornot( - rop.GETFIELD_GC_F, box, fielddescr, 'f') - - @arguments("box", "descr") - def opimpl_getfield_gc_i_pure(self, box, fielddescr): - if isinstance(box, ConstPtr): - # if 'box' is directly a ConstPtr, bypass the heapcache completely - resbox = executor.execute(self.metainterp.cpu, self.metainterp, - rop.GETFIELD_GC_PURE_I, fielddescr, box) - return ConstInt(resbox) - return self._opimpl_getfield_gc_any_pureornot( - rop.GETFIELD_GC_PURE_I, box, fielddescr, 'i') - - @arguments("box", "descr") - def opimpl_getfield_gc_f_pure(self, box, fielddescr): - if isinstance(box, ConstPtr): - # if 'box' is directly a ConstPtr, bypass the heapcache completely - resvalue = executor.execute(self.metainterp.cpu, self.metainterp, - rop.GETFIELD_GC_PURE_F, fielddescr, box) - return ConstFloat(resvalue) - return self._opimpl_getfield_gc_any_pureornot( - rop.GETFIELD_GC_PURE_F, box, fielddescr, 'f') - - @arguments("box", "descr") - def opimpl_getfield_gc_r_pure(self, box, fielddescr): - if isinstance(box, ConstPtr): - # if 'box' is directly a ConstPtr, bypass the heapcache completely - val = executor.execute(self.metainterp.cpu, self.metainterp, - rop.GETFIELD_GC_PURE_R, fielddescr, box) - return ConstPtr(val) - return self._opimpl_getfield_gc_any_pureornot( - rop.GETFIELD_GC_PURE_R, box, fielddescr, 'r') + + opimpl_getfield_gc_i_pure = opimpl_getfield_gc_i + opimpl_getfield_gc_r_pure = opimpl_getfield_gc_r + opimpl_getfield_gc_f_pure = opimpl_getfield_gc_f @arguments("box", "box", "descr") def opimpl_getinteriorfield_gc_i(self, array, index, descr): @@ -733,7 +724,7 @@ @arguments("box", "descr", "orgpc") def _opimpl_getfield_gc_greenfield_any(self, box, fielddescr, pc): ginfo = self.metainterp.jitdriver_sd.greenfield_info - opnum = OpHelpers.getfield_pure_for_descr(fielddescr) + opnum = OpHelpers.getfield_for_descr(fielddescr) if (ginfo is not None and fielddescr in ginfo.green_field_descrs and not self._nonstandard_virtualizable(pc, box, fielddescr)): # fetch the result, but consider it as a Const box and don't @@ -2104,17 +2095,7 @@ profiler = self.staticdata.profiler profiler.count_ops(opnum) resvalue = executor.execute(self.cpu, self, opnum, descr, *argboxes) - # - is_pure = rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST - if not is_pure: - if (opnum == rop.GETFIELD_RAW_I or - opnum == rop.GETFIELD_RAW_R or - opnum == rop.GETFIELD_RAW_F or - opnum == rop.GETARRAYITEM_RAW_I or - opnum == rop.GETARRAYITEM_RAW_F): - is_pure = descr.is_always_pure() - # - if is_pure: + if OpHelpers.is_pure_with_descr(opnum, descr): return self._record_helper_pure(opnum, resvalue, descr, *argboxes) if rop._OVF_FIRST <= opnum <= rop._OVF_LAST: return self._record_helper_ovf(opnum, resvalue, descr, *argboxes) diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -231,7 +231,7 @@ class AbstractResOpOrInputArg(AbstractValue): _attrs_ = ('_forwarded',) - _forwarded = None # either another resop or OptInfo + _forwarded = None # either another resop or OptInfo def get_forwarded(self): return self._forwarded @@ -412,6 +412,8 @@ return rop._JIT_DEBUG_FIRST <= self.getopnum() <= rop._JIT_DEBUG_LAST def is_always_pure(self): + # Tells whether an operation is pure based solely on the opcode. + # Other operations (e.g. getfield ops) may be pure in some cases are well. return rop._ALWAYS_PURE_FIRST <= self.getopnum() <= rop._ALWAYS_PURE_LAST def has_no_side_effect(self): @@ -434,9 +436,7 @@ return self.opnum in (rop.SAME_AS_I, rop.SAME_AS_F, rop.SAME_AS_R) def is_getfield(self): - return self.opnum in (rop.GETFIELD_GC_I, rop.GETFIELD_GC_F, - rop.GETFIELD_GC_R, rop.GETFIELD_GC_PURE_I, - rop.GETFIELD_GC_PURE_R, rop.GETFIELD_GC_PURE_F) + return self.opnum in (rop.GETFIELD_GC_I, rop.GETFIELD_GC_F, rop.GETFIELD_GC_R) def is_getarrayitem(self): return self.opnum in (rop.GETARRAYITEM_GC_I, rop.GETARRAYITEM_GC_F, @@ -1154,7 +1154,6 @@ 'ARRAYLEN_GC/1d/i', 'STRLEN/1/i', 'STRGETITEM/2/i', - 'GETFIELD_GC_PURE/1d/rfi', 'GETARRAYITEM_GC_PURE/2d/rfi', #'GETFIELD_RAW_PURE/1d/rfi', these two operations not useful and #'GETARRAYITEM_RAW_PURE/2d/fi', dangerous when unrolling speculatively @@ -1602,14 +1601,6 @@ return rop.CALL_LOOPINVARIANT_N @staticmethod - def getfield_pure_for_descr(descr): - if descr.is_pointer_field(): - return rop.GETFIELD_GC_PURE_R - elif descr.is_float_field(): - return rop.GETFIELD_GC_PURE_F - return rop.GETFIELD_GC_PURE_I - - @staticmethod def getfield_for_descr(descr): if descr.is_pointer_field(): return rop.GETFIELD_GC_R @@ -1760,4 +1751,26 @@ opnum = rop.VEC_UNPACK_F return VecOperationNew(opnum, args, datatype, bytesize, signed, count) + @staticmethod + def is_pure_getfield(opnum, descr): + if (opnum == rop.GETFIELD_GC_I or + opnum == rop.GETFIELD_GC_F or + opnum == rop.GETFIELD_GC_R): + return descr is not None and descr.is_always_pure() + return False + @staticmethod + def is_pure_with_descr(opnum, descr): + is_pure = rop._ALWAYS_PURE_FIRST <= opnum <= rop._ALWAYS_PURE_LAST + if not is_pure: + if (opnum == rop.GETFIELD_RAW_I or + opnum == rop.GETFIELD_RAW_R or + opnum == rop.GETFIELD_RAW_F or + opnum == rop.GETFIELD_GC_I or + opnum == rop.GETFIELD_GC_R or + opnum == rop.GETFIELD_GC_F or + opnum == rop.GETARRAYITEM_RAW_I or + opnum == rop.GETARRAYITEM_RAW_F): + is_pure = descr.is_always_pure() + return is_pure + diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py --- a/rpython/jit/metainterp/test/test_ajit.py +++ b/rpython/jit/metainterp/test/test_ajit.py @@ -320,7 +320,7 @@ assert res == 252 self.check_trace_count(1) self.check_resops({'jump': 1, 'int_gt': 2, 'int_add': 2, - 'getfield_gc_pure_i': 1, 'int_mul': 1, + 'getfield_gc_i': 1, 'int_mul': 1, 'guard_true': 2, 'int_sub': 2}) def test_loops_are_transient(self): @@ -1405,7 +1405,7 @@ return tup[1] res = self.interp_operations(f, [3, 5]) assert res == 5 - self.check_operations_history(setfield_gc=2, getfield_gc_pure_i=0) + self.check_operations_history(setfield_gc=2, getfield_gc_i=0) def test_oosend_look_inside_only_one(self): class A: @@ -2522,7 +2522,7 @@ if counter > 10: return 7 assert self.meta_interp(build, []) == 7 - self.check_resops(getfield_gc_pure_r=2) + self.check_resops(getfield_gc_r=2) def test_args_becomming_equal(self): myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a', 'b']) diff --git a/rpython/jit/metainterp/test/test_immutable.py b/rpython/jit/metainterp/test/test_immutable.py --- a/rpython/jit/metainterp/test/test_immutable.py +++ b/rpython/jit/metainterp/test/test_immutable.py @@ -19,7 +19,7 @@ return y.x + 5 res = self.interp_operations(f, [23]) assert res == 28 - self.check_operations_history(getfield_gc_i=0, getfield_gc_pure_i=1, int_add=1) + self.check_operations_history(getfield_gc_i=1, int_add=1) def test_fields_subclass(self): class X(object): @@ -41,8 +41,7 @@ return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 - self.check_operations_history(getfield_gc_i=0, getfield_gc_pure_i=2, - int_add=2) + self.check_operations_history(getfield_gc_i=2, int_add=2) def f(x, y): # this time, the field 'x' only shows up on subclass 'Y' @@ -50,8 +49,7 @@ return z.x + z.y + 5 res = self.interp_operations(f, [23, 11]) assert res == 39 - self.check_operations_history(getfield_gc_i=0, getfield_gc_pure_i=2, - int_add=2) + self.check_operations_history(getfield_gc_i=2, int_add=2) def test_array(self): class X(object): @@ -66,8 +64,7 @@ return a.y[index] res = self.interp_operations(f, [2], listops=True) assert res == 30 - self.check_operations_history(getfield_gc_r=0, getfield_gc_pure_r=1, - getarrayitem_gc_i=0, getarrayitem_gc_pure_i=1) + self.check_operations_history(getfield_gc_r=1, getarrayitem_gc_i=0, getarrayitem_gc_pure_i=1) def test_array_index_error(self): class X(object): @@ -89,8 +86,7 @@ return a.get(index) res = self.interp_operations(f, [2], listops=True) assert res == 30 - self.check_operations_history(getfield_gc_r=0, getfield_gc_pure_r=1, - getarrayitem_gc_i=0, getarrayitem_gc_pure_i=1) + self.check_operations_history(getfield_gc_r=1, getarrayitem_gc_i=0, getarrayitem_gc_pure_i=1) def test_array_in_immutable(self): class X(object): @@ -106,8 +102,7 @@ return y.lst[index] + y.y + 5 res = self.interp_operations(f, [23, 0], listops=True) assert res == 23 + 24 + 5 - self.check_operations_history(getfield_gc_r=0, getfield_gc_pure_r=1, - getfield_gc_pure_i=1, + self.check_operations_history(getfield_gc_r=1, getfield_gc_i=1, getarrayitem_gc_i=0, getarrayitem_gc_pure_i=1, int_add=3) diff --git a/rpython/jit/metainterp/test/test_quasiimmut.py b/rpython/jit/metainterp/test/test_quasiimmut.py --- a/rpython/jit/metainterp/test/test_quasiimmut.py +++ b/rpython/jit/metainterp/test/test_quasiimmut.py @@ -74,7 +74,7 @@ # res = self.meta_interp(f, [100, 7]) assert res == 700 - self.check_resops(guard_not_invalidated=2, getfield_gc=0) + self.check_resops(guard_not_invalidated=2) # from rpython.jit.metainterp.warmspot import get_stats loops = get_stats().loops @@ -101,7 +101,7 @@ res = self.meta_interp(f, [100, 7], enable_opts="") assert res == 700 # there should be no getfields, even though optimizations are turned off - self.check_resops(guard_not_invalidated=1, getfield_gc=0) + self.check_resops(guard_not_invalidated=1) def test_nonopt_1(self): myjitdriver = JitDriver(greens=[], reds=['x', 'total', 'lst']) @@ -124,8 +124,7 @@ assert f(100, 7) == 721 res = self.meta_interp(f, [100, 7]) assert res == 721 - self.check_resops(guard_not_invalidated=0, getfield_gc_r=1, - getfield_gc_pure_i=2) + self.check_resops(guard_not_invalidated=0, getfield_gc_r=1, getfield_gc_i=2) # from rpython.jit.metainterp.warmspot import get_stats loops = get_stats().loops @@ -156,7 +155,7 @@ # res = self.meta_interp(f, [100, 7]) assert res == 700 - self.check_resops(guard_not_invalidated=2, getfield_gc=0) + self.check_resops(guard_not_invalidated=2) def test_change_during_tracing_1(self): myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) @@ -208,7 +207,7 @@ assert f(100, 7) == 700 res = self.meta_interp(f, [100, 7]) assert res == 700 - self.check_resops(guard_not_invalidated=0, getfield_gc=0) + self.check_resops(guard_not_invalidated=0) def test_change_invalidate_reentering(self): myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) @@ -234,7 +233,7 @@ assert g(100, 7) == 700707 res = self.meta_interp(g, [100, 7]) assert res == 700707 - self.check_resops(guard_not_invalidated=4, getfield_gc=0) + self.check_resops(guard_not_invalidated=4) def test_invalidate_while_running(self): jitdriver = JitDriver(greens=['foo'], reds=['i', 'total']) @@ -348,7 +347,7 @@ res = self.meta_interp(f, [100, 30]) assert res == 6019 self.check_resops(guard_not_invalidated=8, guard_not_forced=0, - call_may_force=0, getfield_gc=0) + call_may_force=0) def test_list_simple_1(self): myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) @@ -374,8 +373,7 @@ getarrayitem_gc_pure_r=0, getarrayitem_gc_i=0, getarrayitem_gc_r=0, - getfield_gc_i=0, getfield_gc_pure_i=0, - getfield_gc_r=0, getfield_gC_pure_r=0) + getfield_gc_i=0, getfield_gc_r=0) # from rpython.jit.metainterp.warmspot import get_stats loops = get_stats().loops @@ -405,9 +403,7 @@ assert res == 700 # operations must have been removed by the frontend self.check_resops(getarrayitem_gc_pure_i=0, guard_not_invalidated=1, - getarrayitem_gc_i=0, - getfield_gc=0, getfield_gc_pure_i=0, - getfield_gc_pure_r=0) + getarrayitem_gc_i=0, getfield_gc_i=0, getfield_gc_r=0) def test_list_length_1(self): myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total']) diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -436,10 +436,10 @@ return p.x[0] + p.x[1] res = self.interp_operations(fn, [7]) assert res == 7 + 7 + 1 - self.check_operations_history(getfield_gc_r=0, getfield_gc_pure_r=0) + self.check_operations_history(getfield_gc_r=0) res = self.interp_operations(fn, [-7]) assert res == -7 - 7 + 1 - self.check_operations_history(getfield_gc_r=0, getfield_gc_pure_r=0) + self.check_operations_history(getfield_gc_r=0) def test_heap_caching_and_elidable_function(self): class A: @@ -517,12 +517,12 @@ return a1[0] + a2[0] + gn(a1, a2) res = self.interp_operations(fn, [7]) assert res == 2 * 7 + 2 * 6 - self.check_operations_history(getfield_gc_pure_i=0, - getfield_gc_pure_r=0) + self.check_operations_history(getfield_gc_i=0, + getfield_gc_r=0) res = self.interp_operations(fn, [-7]) assert res == 2 * -7 + 2 * -8 - self.check_operations_history(getfield_gc_pure_i=0, - getfield_gc_pure_r=0) + self.check_operations_history(getfield_gc_i=0, + getfield_gc_r=0) def test_heap_caching_multiple_arrays(self): class Gbl(object): diff --git a/rpython/jit/metainterp/test/test_virtual.py b/rpython/jit/metainterp/test/test_virtual.py --- a/rpython/jit/metainterp/test/test_virtual.py +++ b/rpython/jit/metainterp/test/test_virtual.py @@ -1077,7 +1077,7 @@ res = self.meta_interp(f, [], repeat=7) assert res == f() - def test_getfield_gc_pure_nobug(self): + def test_pure_getfield_gc_nobug(self): mydriver = JitDriver(reds=['i', 's', 'a'], greens=[]) class A(object): diff --git a/rpython/rlib/test/test_rpath.py b/rpython/rlib/test/test_rpath.py --- a/rpython/rlib/test/test_rpath.py +++ b/rpython/rlib/test/test_rpath.py @@ -68,8 +68,8 @@ assert rpath._nt_rabspath('d:\\foo\\bar\\..') == 'd:\\foo' assert rpath._nt_rabspath('d:\\foo\\bar\\..\\x') == 'd:\\foo\\x' curdrive = _ = rpath._nt_rsplitdrive(os.getcwd()) - assert len(curdrive) == 2 and curdrive[1] == ':' - assert rpath.rabspath('\\foo') == '%s\\foo' % curdrive + assert len(curdrive) == 2 and curdrive[0][1] == ':' + assert rpath.rabspath('\\foo') == '%s\\foo' % curdrive[0] def test_risabs_posix(): assert rpath._posix_risabs('/foo/bar') diff --git a/rpython/translator/platform/windows.py b/rpython/translator/platform/windows.py --- a/rpython/translator/platform/windows.py +++ b/rpython/translator/platform/windows.py @@ -151,7 +151,7 @@ # Increase stack size, for the linker and the stack check code. stack_size = 8 << 20 # 8 Mb - self.link_flags.append('/STACK:%d' % stack_size) + self.link_flags = self.link_flags + ('/STACK:%d' % stack_size,) # The following symbol is used in c/src/stack.h self.cflags.append('/DMAX_STACK_SIZE=%d' % (stack_size - 1024)) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit