[pypy-commit] pypy s390x-backend: merged default

plan_rich pypy.commits at gmail.com
Tue Jan 26 02:47:54 EST 2016


Author: Richard Plangger <planrichi at 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)
 
- at cpython_api([PyObject, rffi.CCHARP], rffi.INT_real, error=-1)
+ at 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)
 
- at cpython_api([rffi.CCHARP, rffi.INT_real, PyObject, PyObject,
+ at 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
 
- at cpython_api([rffi.CCHARP, rffi.CCHARP, rffi.INT_real, PyCompilerFlagsPtr],
+ at 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
 }
 
- at cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0)
+ at 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))
 


More information about the pypy-commit mailing list