Author: mattip <[email protected]>
Branch: win32-fixes5
Changeset: r73748:0559342425bb
Date: 2014-09-30 20:32 +0300
http://bitbucket.org/pypy/pypy/changeset/0559342425bb/

Log:    merge default into branch

diff too long, truncating to 2000 out of 5071 lines

diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -367,3 +367,43 @@
 Detailed license information is contained in the NOTICE file in the
 directory.
 
+
+Licenses and Acknowledgements for Incorporated Software
+=======================================================
+
+This section is an incomplete, but growing list of licenses and
+acknowledgements for third-party software incorporated in the PyPy
+distribution.
+
+License for 'Tcl/Tk'
+--------------------
+
+This copy of PyPy contains library code that may, when used, result in
+the Tcl/Tk library to be loaded.  PyPy also includes code that may be
+regarded as being a copy of some parts of the Tcl/Tk header files.
+You may see a copy of the License for Tcl/Tk in the file
+`lib_pypy/_tkinter/license.terms` included here.
+
+License for 'bzip2'
+-------------------
+
+This copy of PyPy may be linked (dynamically or statically) with the
+bzip2 library.  You may see a copy of the License for bzip2/libbzip2 at
+
+    http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html
+
+License for 'openssl'
+---------------------
+
+This copy of PyPy may be linked (dynamically or statically) with the
+openssl library.  You may see a copy of the License for OpenSSL at
+
+    https://www.openssl.org/source/license.html
+
+License for 'gdbm'
+------------------
+
+The gdbm module includes code from gdbm.h, which is distributed under
+the terms of the GPL license version 2 or any later version.  Thus the
+gdbm module, provided in the file lib_pypy/gdbm.py, is redistributed
+under the terms of the GPL license as well.
diff --git a/lib-python/2.7/test/test_select.py 
b/lib-python/2.7/test/test_select.py
--- a/lib-python/2.7/test/test_select.py
+++ b/lib-python/2.7/test/test_select.py
@@ -57,7 +57,17 @@
                 del a[-1]
                 return sys.__stdout__.fileno()
         a[:] = [F()] * 10
-        self.assertEqual(select.select([], a, []), ([], a[:5], []))
+        result = select.select([], a, [])
+        # CPython: 'a' ends up with 5 items, because each fileno()
+        # removes an item and at the middle the iteration stops.
+        # PyPy: 'a' ends up empty, because the iteration is done on
+        # a copy of the original list: fileno() is called 10 times.
+        if test_support.check_impl_detail(cpython=True):
+            self.assertEqual(len(result[1]), 5)
+            self.assertEqual(len(a), 5)
+        if test_support.check_impl_detail(pypy=True):
+            self.assertEqual(len(result[1]), 10)
+            self.assertEqual(len(a), 0)
 
 def test_main():
     test_support.run_unittest(SelectTestCase)
diff --git a/pypy/module/_winreg/interp_winreg.py 
b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -266,10 +266,16 @@
     buf = None
 
     if typ == rwinreg.REG_DWORD:
-        if space.isinstance_w(w_value, space.w_int):
+        if space.is_none(w_value) or (
+                space.isinstance_w(w_value, space.w_int) or
+                space.isinstance_w(w_value, space.w_long)):
+            if space.is_none(w_value):
+                value = r_uint(0)
+            else:
+                value = space.c_uint_w(w_value)
             buflen = rffi.sizeof(rwin32.DWORD)
             buf1 = lltype.malloc(rffi.CArray(rwin32.DWORD), 1, flavor='raw')
-            buf1[0] = space.uint_w(w_value)
+            buf1[0] = value
             buf = rffi.cast(rffi.CCHARP, buf1)
 
     elif typ == rwinreg.REG_SZ or typ == rwinreg.REG_EXPAND_SZ:
diff --git a/pypy/module/_winreg/test/test_winreg.py 
b/pypy/module/_winreg/test/test_winreg.py
--- a/pypy/module/_winreg/test/test_winreg.py
+++ b/pypy/module/_winreg/test/test_winreg.py
@@ -40,7 +40,7 @@
         cls.w_tmpfilename = space.wrap(str(udir.join('winreg-temp')))
 
         test_data = [
-            ("Int Value", 45, _winreg.REG_DWORD),
+            ("Int Value", 0xFEDCBA98, _winreg.REG_DWORD),
             ("Str Value", "A string Value", _winreg.REG_SZ),
             ("Unicode Value", u"A unicode Value", _winreg.REG_SZ),
             ("Str Expand", "The path is %path%", _winreg.REG_EXPAND_SZ),
@@ -137,9 +137,11 @@
             assert 0, "Did not raise"
 
     def test_SetValueEx(self):
-        from _winreg import CreateKey, SetValueEx, REG_BINARY
+        from _winreg import CreateKey, SetValueEx, REG_BINARY, REG_DWORD
         key = CreateKey(self.root_key, self.test_key_name)
         sub_key = CreateKey(key, "sub_key")
+        SetValueEx(sub_key, 'Int Value', 0, REG_DWORD, None)
+        SetValueEx(sub_key, 'Int Value', 0, REG_DWORD, 45)
         for name, value, type in self.test_data:
             SetValueEx(sub_key, name, 0, type, value)
         exc = raises(TypeError, SetValueEx, sub_key, 'test_name', None,
diff --git a/pypy/module/micronumpy/test/test_zjit.py 
b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -617,7 +617,7 @@
             'raw_store': 1,
             'same_as': 2,
             'setarrayitem_gc': 8,
-            'setfield_gc': 21,
+            'setfield_gc': 22,
         })
 
     def define_argsort():
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
@@ -382,12 +382,16 @@
             ...
             p20 = force_token()
             p22 = new_with_vtable(...)
-            p24 = new_array(1, descr=<ArrayP .>)
+            p24 = new_array_clear(1, descr=<ArrayP .>)
             p26 = new_with_vtable(ConstClass(W_ListObject))
             {{{
             setfield_gc(p0, p20, descr=<FieldP .*PyFrame.vable_token .*>)
+            setfield_gc(p22, ConstPtr(null), descr=<FieldP 
pypy.interpreter.argument.Arguments.inst_keywords_w .*>)
+            setfield_gc(p22, ConstPtr(null), descr=<FieldP 
pypy.interpreter.argument.Arguments.inst_keywords .*>)
             setfield_gc(p22, 1, descr=<FieldU 
pypy.interpreter.argument.Arguments.inst__jit_few_keywords .*>)
+            setfield_gc(p22, ConstPtr(null), descr=<FieldP 
pypy.interpreter.argument.Arguments.inst_keyword_names_w .*>)
             setfield_gc(p26, ConstPtr(ptr22), descr=<FieldP 
pypy.objspace.std.listobject.W_ListObject.inst_strategy .*>)
+            setfield_gc(p26, ConstPtr(null), descr=<FieldP 
pypy.objspace.std.listobject.W_ListObject.inst_lstorage .*>)
             setarrayitem_gc(p24, 0, p26, descr=<ArrayP .>)
             setfield_gc(p22, p24, descr=<FieldP .*Arguments.inst_arguments_w 
.*>)
             }}}
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
@@ -68,10 +68,13 @@
             guard_no_exception(descr=...)
             i12 = call(ConstClass(ll_strhash), p10, descr=<Calli . r EF=0>)
             p13 = new(descr=...)
-            p15 = new_array(8, descr=<ArrayX .*>)
+            p15 = new_array_clear(8, descr=<ArrayX .*>)
             setfield_gc(p13, p15, descr=<FieldP dicttable.entries .*>)
             i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, 
descr=<Calli . rri EF=4 OS=4>)
+            {{{
             setfield_gc(p13, 16, descr=<FieldS dicttable.resize_counter .*>)
+            setfield_gc(p13, 0, descr=<FieldS dicttable.num_items .+>)
+            }}}
             guard_no_exception(descr=...)
             p20 = new_with_vtable(ConstClass(W_IntObject))
             call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, 
p10, p20, i12, i17, descr=<Callv 0 rrrii EF=4>)
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
@@ -110,9 +110,12 @@
             i85 = strlen(p80)
             p86 = new(descr=<SizeDescr .+>)
             p88 = newstr(23)
-            setfield_gc(..., descr=<Field. stringbuilder.+>)
-            setfield_gc(..., descr=<Field. stringbuilder.+>)
-            setfield_gc(..., descr=<Field. stringbuilder.+>)
+            {{{
+            setfield_gc(p86, 0, descr=<FieldS stringbuilder.current_pos .+>)
+            setfield_gc(p86, p88, descr=<FieldP stringbuilder.current_buf .+>)
+            setfield_gc(p86, 23, descr=<FieldS stringbuilder.current_end .+>)
+            setfield_gc(p86, 23, descr=<FieldS stringbuilder.total_size .+>)
+            }}}
             call(ConstClass(ll_append_res0__stringbuilderPtr_rpy_stringPtr), 
p86, p80, descr=<Callv 0 rr EF=4>)
             guard_no_exception(descr=...)
             i89 = getfield_gc(p86, descr=<FieldS stringbuilder.current_pos .+>)
diff --git a/pypy/module/select/interp_select.py 
b/pypy/module/select/interp_select.py
--- a/pypy/module/select/interp_select.py
+++ b/pypy/module/select/interp_select.py
@@ -173,9 +173,9 @@
 On Windows, only sockets are supported; on Unix, all file descriptors.
 """
 
-    iwtd_w = space.listview(w_iwtd)
-    owtd_w = space.listview(w_owtd)
-    ewtd_w = space.listview(w_ewtd)
+    iwtd_w = space.unpackiterable(w_iwtd)
+    owtd_w = space.unpackiterable(w_owtd)
+    ewtd_w = space.unpackiterable(w_ewtd)
 
     if space.is_w(w_timeout, space.w_None):
         timeout = -1.0
diff --git a/pypy/module/select/test/test_select.py 
b/pypy/module/select/test/test_select.py
--- a/pypy/module/select/test/test_select.py
+++ b/pypy/module/select/test/test_select.py
@@ -85,17 +85,18 @@
                 assert owtd == [writeend]
                 total_out += writeend.send(b'x' * 512)
             total_in = 0
-            while True:
-                iwtd, owtd, ewtd = select.select([readend], [], [], 0)
+            while total_in < total_out:
+                iwtd, owtd, ewtd = select.select([readend], [], [], 5)
                 assert owtd == ewtd == []
-                if iwtd == []:
-                    break
-                assert iwtd == [readend]
+                assert iwtd == [readend]    # there is more expected
                 data = readend.recv(4096)
                 assert len(data) > 0
                 assert data == b'x' * len(data)
                 total_in += len(data)
             assert total_in == total_out
+            iwtd, owtd, ewtd = select.select([readend], [], [], 0)
+            assert owtd == ewtd == []
+            assert iwtd == []    # there is not more expected
         finally:
             writeend.close()
             readend.close()
@@ -304,6 +305,20 @@
             for fd in rfds:
                 os.close(fd)
 
+    def test_resize_list_in_select(self):
+        import select
+        class Foo(object):
+            def fileno(self):
+                print len(l)
+                if len(l) < 100:
+                    l.append(Foo())
+                return 0
+        l = [Foo()]
+        select.select(l, (), (), 0)
+        assert 1 <= len(l) <= 100    
+        # ^^^ CPython gives 100, PyPy gives 1.  I think both are OK as
+        # long as there is no crash.
+
 
 class AppTestSelectWithSockets(_AppTestSelect):
     """Same tests with connected sockets.
diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -15,6 +15,7 @@
 from rpython.rlib.rbigint import rbigint
 from rpython.rlib import rfloat
 from rpython.tool.sourcetools import func_with_new_name
+from rpython.rtyper.lltypesystem.module.ll_math import math_fmod
 
 from pypy.objspace.std.intobject import W_IntObject
 
@@ -360,21 +361,17 @@
     y = w_float2.floatval
     if y == 0.0:
         raise FailedToImplementArgs(space.w_ZeroDivisionError, 
space.wrap("float modulo"))
-    try:
-        mod = math.fmod(x, y)
-    except ValueError:
-        mod = rfloat.NAN
+    mod = math_fmod(x, y)
+    if mod:
+        # ensure the remainder has the same sign as the denominator
+        if (y < 0.0) != (mod < 0.0):
+            mod += y
     else:
-        if mod:
-            # ensure the remainder has the same sign as the denominator
-            if (y < 0.0) != (mod < 0.0):
-                mod += y
-        else:
-            # the remainder is zero, and in the presence of signed zeroes
-            # fmod returns different results across platforms; ensure
-            # it has the same sign as the denominator; we'd like to do
-            # "mod = y * 0.0", but that may get optimized away
-            mod = copysign(0.0, y)
+        # the remainder is zero, and in the presence of signed zeroes
+        # fmod returns different results across platforms; ensure
+        # it has the same sign as the denominator; we'd like to do
+        # "mod = y * 0.0", but that may get optimized away
+        mod = copysign(0.0, y)
 
     return W_FloatObject(mod)
 
@@ -383,10 +380,7 @@
     y = w_float2.floatval
     if y == 0.0:
         raise FailedToImplementArgs(space.w_ZeroDivisionError, 
space.wrap("float modulo"))
-    try:
-        mod = math.fmod(x, y)
-    except ValueError:
-        return [W_FloatObject(rfloat.NAN), W_FloatObject(rfloat.NAN)]
+    mod = math_fmod(x, y)
     # fmod is typically exact, so vx-mod is *mathematically* an
     # exact multiple of wx.  But this is fp arithmetic, and fp
     # vx - mod is an approximation; the result is that div may
diff --git a/pypy/objspace/std/newformat.py b/pypy/objspace/std/newformat.py
--- a/pypy/objspace/std/newformat.py
+++ b/pypy/objspace/std/newformat.py
@@ -580,11 +580,11 @@
             elif self._thousands_sep:
                 dec = "."
                 thousands = ","
-                grouping = "\3\0"
+                grouping = "\3"
             else:
                 dec = "."
                 thousands = ""
-                grouping = "\256"
+                grouping = "\xFF"    # special value to mean 'stop'
             if self.is_unicode:
                 self._loc_dec = dec.decode("ascii")
                 self._loc_thousands = thousands.decode("ascii")
@@ -677,14 +677,16 @@
             done = False
             previous = 0
             while True:
-                group = ord(grouping[grouping_state])
-                if group > 0:
-                    if group == 256:
+                if grouping_state >= len(grouping):
+                    group = previous     # end of string
+                else:
+                    # else, get the next value from the string
+                    group = ord(grouping[grouping_state])
+                    if group == 0xFF:    # special value to mean 'stop'
                         break
                     grouping_state += 1
                     previous = group
-                else:
-                    group = previous
+                #
                 final_grouping = min(group, max(left, max(min_width, 1)))
                 n_zeros = max(0, final_grouping - left)
                 n_chars = max(0, min(left, final_grouping))
diff --git a/pypy/objspace/std/test/test_floatobject.py 
b/pypy/objspace/std/test/test_floatobject.py
--- a/pypy/objspace/std/test/test_floatobject.py
+++ b/pypy/objspace/std/test/test_floatobject.py
@@ -794,7 +794,7 @@
         raises(ValueError, float.fromhex, "0P")
 
     def test_division_edgecases(self):
-        import math
+        import math, os
 
         # inf
         inf = float("inf")
@@ -803,6 +803,16 @@
         x, y = divmod(inf, 3)
         assert math.isnan(x)
         assert math.isnan(y)
+        x, y = divmod(3, inf)
+        z = 3 % inf
+        if os.name == 'nt':
+            assert math.isnan(x)
+            assert math.isnan(y)
+            assert math.isnan(z)
+        else:
+            assert x == 0
+            assert y == 3
+            assert z == 3
 
         # divide by 0
         raises(ZeroDivisionError, lambda: inf % 0)
diff --git a/pypy/objspace/std/test/test_newformat.py 
b/pypy/objspace/std/test/test_newformat.py
--- a/pypy/objspace/std/test/test_newformat.py
+++ b/pypy/objspace/std/test/test_newformat.py
@@ -372,6 +372,7 @@
         try:
             assert locale.format('%g', x, grouping=True) == '1,234.57'
             assert format(x, 'n') == '1,234.57'
+            assert format(12345678901234, 'n') == '12,345,678,901,234'
         finally:
             locale.setlocale(locale.LC_NUMERIC, 'C')
 
diff --git a/pypy/tool/pypyjit_child.py b/pypy/tool/pypyjit_child.py
--- a/pypy/tool/pypyjit_child.py
+++ b/pypy/tool/pypyjit_child.py
@@ -10,10 +10,6 @@
     graph = loc['graph']
     interp.malloc_check = False
 
-    def returns_null(T, *args, **kwds):
-        return lltype.nullptr(T)
-    interp.heap.malloc_nonmovable = returns_null     # XXX
-
     from rpython.jit.backend.llgraph.runner import LLGraphCPU
     #LLtypeCPU.supports_floats = False     # for now
     apply_jit(interp, graph, LLGraphCPU)
diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -49,6 +49,16 @@
         os.system("chmod -R a+rX %s" % dirname)
         os.system("chmod -R g-w %s" % dirname)
 
+
+#
+# Some crazy nonsense (imho) about including automatically the license
+# of various libraries as they happen to be on this system.  This is
+# strange because most of these libraries are linked to dynamically,
+# and so at runtime might end up with a different version.  I (arigo)
+# killed this logic and wrote some general info (which I hope is more
+# sensible anyway) into our ../../../LICENSE file.
+#
+'''
 sep_template = "\nThis copy of PyPy includes a copy of %s, which is licensed 
under the following terms:\n\n"
 
 def generate_license(basedir, options):
@@ -95,6 +105,7 @@
     # Do something for gdbm, which is GPL
     txt += gdbm_bit
     return txt
+'''
 
 def create_cffi_import_libraries(pypy_c, options):
     modules = ['_sqlite3']
@@ -216,19 +227,19 @@
     for file in ['_testcapimodule.c', '_ctypes_test.c']:
         shutil.copyfile(str(basedir.join('lib_pypy', file)),
                         str(pypydir.join('lib_pypy', file)))
-    try:
+    if 0:  # disabled
         license = generate_license(basedir, options)
         with open(str(pypydir.join('LICENSE')), 'w') as LICENSE:
             LICENSE.write(license)
-    except:
-        # Non-fatal error, use original LICENCE file
-        import traceback;traceback.print_exc()
+    else:
+        # Use original LICENCE file
+        #import traceback;traceback.print_exc()
         base_file = str(basedir.join('LICENSE'))
         with open(base_file) as fid:
             license = fid.read()
         with open(str(pypydir.join('LICENSE')), 'w') as LICENSE:
             LICENSE.write(license)
-        retval = -1
+        #retval = -1
     #
     spdir = pypydir.ensure('site-packages', dir=True)
     shutil.copy(str(basedir.join('site-packages', 'README')), str(spdir))
@@ -321,7 +332,8 @@
     parser.add_argument('--archive-name', dest='name', type=str, default='',
         help='pypy-VER-PLATFORM')
     parser.add_argument('--license_base', type=str, default=license_base,
-        help='where to start looking for third party upstream licensing info')
+        #help='where to start looking for third party upstream licensing info')
+        help='(ignored)')
     parser.add_argument('--builddir', type=str, default='',
         help='tmp dir for packaging')
     parser.add_argument('--targetdir', type=str, default='',
@@ -356,24 +368,6 @@
     return create_package(basedir, options)
 
 
-third_party_header = '''\n\nLicenses and Acknowledgements for Incorporated 
Software
-=======================================================
-
-This section is an incomplete, but growing list of licenses and 
acknowledgements
-for third-party software incorporated in the PyPy distribution.
-
-'''
-
-gdbm_bit = '''gdbm
-----
-
-The gdbm module includes code from gdbm.h, which is distributed under the terms
-of the GPL license version 2 or any later version.  Thus the gdbm module, 
provided in
-the file lib_pypy/gdbm.py, is redistributed under the terms of the GPL license 
as
-well.
-'''
-
-
 if __name__ == '__main__':
     import sys
     if sys.platform == 'win32':
diff --git a/rpython/jit/backend/arm/assembler.py 
b/rpython/jit/backend/arm/assembler.py
--- a/rpython/jit/backend/arm/assembler.py
+++ b/rpython/jit/backend/arm/assembler.py
@@ -931,6 +931,7 @@
                                         guard, fcond)
                 fcond = asm_operations_with_guard[opnum](self, op,
                                         guard, arglocs, regalloc, fcond)
+                assert fcond is not None
                 regalloc.next_instruction()
                 regalloc.possibly_free_vars_for_op(guard)
                 regalloc.possibly_free_vars(guard.getfailargs())
@@ -941,6 +942,7 @@
                 if arglocs is not None:
                     fcond = asm_operations[opnum](self, op, arglocs,
                                                         regalloc, fcond)
+                    assert fcond is not None
             if op.is_guard():
                 regalloc.possibly_free_vars(op.getfailargs())
             if op.result:
diff --git a/rpython/jit/backend/arm/opassembler.py 
b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -25,7 +25,7 @@
 from rpython.jit.backend.llsupport.descr import InteriorFieldDescr
 from rpython.jit.backend.llsupport.assembler import GuardToken, BaseAssembler
 from rpython.jit.backend.llsupport.regalloc import get_scale
-from rpython.jit.metainterp.history import (Box, AbstractFailDescr,
+from rpython.jit.metainterp.history import (Box, AbstractFailDescr, ConstInt,
                                             INT, FLOAT, REF)
 from rpython.jit.metainterp.history import TargetToken
 from rpython.jit.metainterp.resoperation import rop
@@ -578,6 +578,7 @@
         return fcond
 
     emit_op_setfield_raw = emit_op_setfield_gc
+    emit_op_zero_ptr_field = emit_op_setfield_gc
 
     def emit_op_getfield_gc(self, op, arglocs, regalloc, fcond):
         base_loc, ofs, res, size = arglocs
@@ -1174,3 +1175,87 @@
         self.mc.VMOV_cs(r.svfp_ip.value, arg.value)
         self.mc.VCVT_f32_f64(res.value, r.svfp_ip.value)
         return fcond
+
+    #from ../x86/regalloc.py:1388
+    def emit_op_zero_array(self, op, arglocs, regalloc, fcond):
+        from rpython.jit.backend.llsupport.descr import unpack_arraydescr
+        assert len(arglocs) == 0
+        length_box = op.getarg(2)
+        if isinstance(length_box, ConstInt) and length_box.getint() == 0:
+            return fcond     # nothing to do
+        itemsize, baseofs, _ = unpack_arraydescr(op.getdescr())
+        args = op.getarglist()
+        base_loc = regalloc.rm.make_sure_var_in_reg(args[0], args)
+        sibox = args[1]
+        if isinstance(sibox, ConstInt):
+            startindex_loc = None
+            startindex = sibox.getint()
+            assert startindex >= 0
+        else:
+            startindex_loc = regalloc.rm.make_sure_var_in_reg(sibox, args)
+            startindex = -1
+
+        # base_loc and startindex_loc are in two regs here (or they are
+        # immediates).  Compute the dstaddr_loc, which is the raw
+        # address that we will pass as first argument to memset().
+        # It can be in the same register as either one, but not in
+        # args[2], because we're still needing the latter.
+        dstaddr_box = TempBox()
+        dstaddr_loc = regalloc.rm.force_allocate_reg(dstaddr_box, [args[2]])
+        if startindex >= 0:    # a constant
+            ofs = baseofs + startindex * itemsize
+            reg = base_loc.value
+        else:
+            self.mc.gen_load_int(r.ip.value, itemsize)
+            self.mc.MLA(dstaddr_loc.value, r.ip.value,
+                        startindex_loc.value, base_loc.value)
+            ofs = baseofs
+            reg = dstaddr_loc.value
+        if check_imm_arg(ofs):
+            self.mc.ADD_ri(dstaddr_loc.value, reg, imm=ofs)
+        else:
+            self.mc.gen_load_int(r.ip.value, ofs)
+            self.mc.ADD_rr(dstaddr_loc.value, reg, r.ip.value)
+
+        if (isinstance(length_box, ConstInt) and
+                length_box.getint() <= 14 and     # same limit as GCC
+                itemsize in (4, 2, 1)):
+            # Inline a series of STR operations, starting at 'dstaddr_loc'.
+            # XXX we could optimize STRB/STRH into STR, but this needs care:
+            # XXX it only works if startindex_loc is a constant, otherwise
+            # XXX we'd be doing unaligned accesses
+            self.mc.gen_load_int(r.ip.value, 0)
+            for i in range(length_box.getint()):
+                if itemsize == 4:
+                    self.mc.STR_ri(r.ip.value, dstaddr_loc.value, imm=i*4)
+                elif itemsize == 2:
+                    self.mc.STRH_ri(r.ip.value, dstaddr_loc.value, imm=i*2)
+                else:
+                    self.mc.STRB_ri(r.ip.value, dstaddr_loc.value, imm=i*1)
+
+        else:
+            if isinstance(length_box, ConstInt):
+                length_loc = imm(length_box.getint() * itemsize)
+            else:
+                # load length_loc in a register different than dstaddr_loc
+                length_loc = regalloc.rm.make_sure_var_in_reg(length_box,
+                                                              [dstaddr_box])
+                if itemsize > 1:
+                    # we need a register that is different from dstaddr_loc,
+                    # but which can be identical to length_loc (as usual,
+                    # only if the length_box is not used by future operations)
+                    bytes_box = TempBox()
+                    bytes_loc = regalloc.rm.force_allocate_reg(bytes_box,
+                                                               [dstaddr_box])
+                    self.mc.gen_load_int(r.ip.value, itemsize)
+                    self.mc.MUL(bytes_loc.value, r.ip.value, length_loc.value)
+                    length_box = bytes_box
+                    length_loc = bytes_loc
+            #
+            # call memset()
+            regalloc.before_call()
+            self.simple_call_no_collect(imm(self.memset_addr),
+                                        [dstaddr_loc, imm(0), length_loc])
+            regalloc.rm.possibly_free_var(length_box)
+        regalloc.rm.possibly_free_var(dstaddr_box)
+        return fcond
diff --git a/rpython/jit/backend/arm/regalloc.py 
b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -818,8 +818,11 @@
 
     def prepare_op_setfield_gc(self, op, fcond):
         boxes = op.getarglist()
+        ofs, size, sign = unpack_fielddescr(op.getdescr())
+        return self._prepare_op_setfield(boxes, ofs, size)
+
+    def _prepare_op_setfield(self, boxes, ofs, size):
         a0, a1 = boxes
-        ofs, size, sign = unpack_fielddescr(op.getdescr())
         base_loc = self.make_sure_var_in_reg(a0, boxes)
         value_loc = self.make_sure_var_in_reg(a1, boxes)
         ofs_size = default_imm_size if size < 8 else VMEM_imm_size
@@ -832,6 +835,11 @@
 
     prepare_op_setfield_raw = prepare_op_setfield_gc
 
+    def prepare_op_zero_ptr_field(self, op, fcond):
+        a0 = op.getarg(0)
+        ofs = op.getarg(1).getint()
+        return self._prepare_op_setfield([a0, ConstInt(0)], ofs, WORD)
+
     def prepare_op_getfield_gc(self, op, fcond):
         a0 = op.getarg(0)
         ofs, size, sign = unpack_fielddescr(op.getdescr())
@@ -988,6 +996,7 @@
 
     prepare_op_copystrcontent = void
     prepare_op_copyunicodecontent = void
+    prepare_op_zero_array = void
 
     def prepare_op_unicodelen(self, op, fcond):
         l0 = self.make_sure_var_in_reg(op.getarg(0))
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
@@ -225,6 +225,7 @@
                 'i': 0,
                 'f': 0.0}
 
+
 class LLGraphCPU(model.AbstractCPU):
     from rpython.jit.metainterp.typesystem import llhelper as ts
     supports_floats = True
@@ -641,6 +642,11 @@
 
     def bh_new_array(self, length, arraydescr):
         array = lltype.malloc(arraydescr.A, length, zero=True)
+        assert getkind(arraydescr.A.OF) != 'ref' # getkind crashes on structs
+        return lltype.cast_opaque_ptr(llmemory.GCREF, array)
+
+    def bh_new_array_clear(self, length, arraydescr):
+        array = lltype.malloc(arraydescr.A, length, zero=True)
         return lltype.cast_opaque_ptr(llmemory.GCREF, array)
 
     def bh_classof(self, struct):
diff --git a/rpython/jit/backend/llsupport/assembler.py 
b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -1,5 +1,5 @@
 from rpython.jit.backend.llsupport import jitframe
-from rpython.jit.backend.llsupport.memcpy import memcpy_fn
+from rpython.jit.backend.llsupport.memcpy import memcpy_fn, memset_fn
 from rpython.jit.backend.llsupport.symbolic import WORD
 from rpython.jit.metainterp.history import (INT, REF, FLOAT, JitCellToken,
     ConstInt, BoxInt, AbstractFailDescr)
@@ -63,6 +63,7 @@
     def __init__(self, cpu, translate_support_code=False):
         self.cpu = cpu
         self.memcpy_addr = 0
+        self.memset_addr = 0
         self.rtyper = cpu.rtyper
         self._debug = False
 
@@ -79,6 +80,7 @@
         else:
             self.gc_size_of_header = WORD # for tests
         self.memcpy_addr = self.cpu.cast_ptr_to_int(memcpy_fn)
+        self.memset_addr = self.cpu.cast_ptr_to_int(memset_fn)
         self._build_failure_recovery(False, withfloats=False)
         self._build_failure_recovery(True, withfloats=False)
         self._build_wb_slowpath(False)
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
@@ -35,9 +35,11 @@
     size = 0      # help translation
     tid = llop.combine_ushort(lltype.Signed, 0, 0)
 
-    def __init__(self, size, count_fields_if_immut=-1):
+    def __init__(self, size, count_fields_if_immut=-1,
+                 gc_fielddescrs=None):
         self.size = size
         self.count_fields_if_immut = count_fields_if_immut
+        self.gc_fielddescrs = gc_fielddescrs
 
     def count_fields_if_immutable(self):
         return self.count_fields_if_immut
@@ -58,10 +60,13 @@
     except KeyError:
         size = symbolic.get_size(STRUCT, gccache.translate_support_code)
         count_fields_if_immut = heaptracker.count_fields_if_immutable(STRUCT)
+        gc_fielddescrs = heaptracker.gc_fielddescrs(gccache, STRUCT)
         if heaptracker.has_gcstruct_a_vtable(STRUCT):
-            sizedescr = SizeDescrWithVTable(size, count_fields_if_immut)
+            sizedescr = SizeDescrWithVTable(size, count_fields_if_immut,
+                                            gc_fielddescrs)
         else:
-            sizedescr = SizeDescr(size, count_fields_if_immut)
+            sizedescr = SizeDescr(size, count_fields_if_immut,
+                                  gc_fielddescrs)
         gccache.init_size_descr(STRUCT, sizedescr)
         cache[STRUCT] = sizedescr
         return sizedescr
@@ -95,6 +100,9 @@
         self.field_size = field_size
         self.flag = flag
 
+    def __repr__(self):
+        return 'FieldDescr<%s>' % (self.name,)
+
     def is_pointer_field(self):
         return self.flag == FLAG_POINTER
 
diff --git a/rpython/jit/backend/llsupport/gc.py 
b/rpython/jit/backend/llsupport/gc.py
--- a/rpython/jit/backend/llsupport/gc.py
+++ b/rpython/jit/backend/llsupport/gc.py
@@ -18,10 +18,12 @@
 from rpython.jit.backend.llsupport.descr import get_call_descr
 from rpython.jit.backend.llsupport.rewrite import GcRewriterAssembler
 from rpython.memory.gctransform import asmgcroot
+from rpython.jit.codewriter.effectinfo import EffectInfo
 
 # ____________________________________________________________
 
 class GcLLDescription(GcCache):
+    malloc_zero_filled = True
 
     def __init__(self, gcdescr, translator=None, rtyper=None):
         GcCache.__init__(self, translator is not None, rtyper)
@@ -36,6 +38,8 @@
     def _setup_str(self):
         self.str_descr     = get_array_descr(self, rstr.STR)
         self.unicode_descr = get_array_descr(self, rstr.UNICODE)
+        self.str_hash_descr     = get_field_descr(self, rstr.STR,     'hash')
+        self.unicode_hash_descr = get_field_descr(self, rstr.UNICODE, 'hash')
 
     def generate_function(self, funcname, func, ARGS, RESULT=llmemory.GCREF):
         """Generates a variant of malloc with the given name and the given
@@ -118,7 +122,8 @@
         descrs = JitFrameDescrs()
         descrs.arraydescr = cpu.arraydescrof(jitframe.JITFRAME)
         for name in ['jf_descr', 'jf_guard_exc', 'jf_force_descr',
-                     'jf_frame_info', 'jf_gcmap', 'jf_extra_stack_depth']:
+                     'jf_frame_info', 'jf_gcmap', 'jf_extra_stack_depth',
+                     'jf_savedata', 'jf_forward']:
             setattr(descrs, name, cpu.fielddescrof(jitframe.JITFRAME, name))
         descrs.jfi_frame_size = cpu.fielddescrof(jitframe.JITFRAMEINFO,
                                                   'jfi_frame_size')
@@ -377,6 +382,7 @@
         from rpython.memory.gcheader import GCHeaderBuilder
         self.GCClass = self.layoutbuilder.GCClass
         self.moving_gc = self.GCClass.moving_gc
+        self.malloc_zero_filled = self.GCClass.malloc_zero_filled
         self.HDRPTR = lltype.Ptr(self.GCClass.HDR)
         self.gcheaderbuilder = GCHeaderBuilder(self.HDRPTR.TO)
         self.max_size_of_young_obj = self.GCClass.JIT_max_size_of_young_obj()
@@ -410,9 +416,9 @@
             if self.DEBUG:
                 self._random_usage_of_xmm_registers()
             type_id = rffi.cast(llgroup.HALFWORD, 0)    # missing here
-            return llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
-                                                   type_id, size,
-                                                   False, False, False)
+            return llop1.do_malloc_fixedsize(llmemory.GCREF,
+                                             type_id, size,
+                                             False, False, False)
 
         self.generate_function('malloc_nursery', malloc_nursery_slowpath,
                                [lltype.Signed])
@@ -455,7 +461,7 @@
 
         def malloc_str(length):
             type_id = llop.extract_ushort(llgroup.HALFWORD, str_type_id)
-            return llop1.do_malloc_varsize_clear(
+            return llop1.do_malloc_varsize(
                 llmemory.GCREF,
                 type_id, length, str_basesize, str_itemsize,
                 str_ofs_length)
@@ -464,7 +470,7 @@
 
         def malloc_unicode(length):
             type_id = llop.extract_ushort(llgroup.HALFWORD, unicode_type_id)
-            return llop1.do_malloc_varsize_clear(
+            return llop1.do_malloc_varsize(
                 llmemory.GCREF,
                 type_id, length, unicode_basesize, unicode_itemsize,
                 unicode_ofs_length)
diff --git a/rpython/jit/backend/llsupport/jitframe.py 
b/rpython/jit/backend/llsupport/jitframe.py
--- a/rpython/jit/backend/llsupport/jitframe.py
+++ b/rpython/jit/backend/llsupport/jitframe.py
@@ -45,8 +45,9 @@
 # detailed explanation how it is on your architecture
 
 def jitframe_allocate(frame_info):
-    frame = lltype.malloc(JITFRAME, frame_info.jfi_frame_depth, zero=True)
+    frame = lltype.malloc(JITFRAME, frame_info.jfi_frame_depth)
     frame.jf_frame_info = frame_info
+    frame.jf_extra_stack_depth = 0
     return frame
 
 def jitframe_resolve(frame):
diff --git a/rpython/jit/backend/llsupport/llmodel.py 
b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -14,6 +14,7 @@
     get_call_descr, get_interiorfield_descr,
     FieldDescr, ArrayDescr, CallDescr, InteriorFieldDescr,
     FLAG_POINTER, FLAG_FLOAT)
+from rpython.jit.backend.llsupport.memcpy import memset_fn
 from rpython.jit.backend.llsupport.asmmemmgr import AsmMemoryManager
 from rpython.rlib.unroll import unrolling_iterable
 
@@ -607,6 +608,7 @@
 
     def bh_new_array(self, length, arraydescr):
         return self.gc_ll_descr.gc_malloc_array(length, arraydescr)
+    bh_new_array_clear = bh_new_array
 
     def bh_newstr(self, length):
         return self.gc_ll_descr.gc_malloc_str(length)
diff --git a/rpython/jit/backend/llsupport/memcpy.py 
b/rpython/jit/backend/llsupport/memcpy.py
--- a/rpython/jit/backend/llsupport/memcpy.py
+++ b/rpython/jit/backend/llsupport/memcpy.py
@@ -3,3 +3,6 @@
 memcpy_fn = rffi.llexternal('memcpy', [llmemory.Address, llmemory.Address,
                                        rffi.SIZE_T], lltype.Void,
                             sandboxsafe=True, _nowrapper=True)
+memset_fn = rffi.llexternal('memset', [llmemory.Address, rffi.INT,
+                                       rffi.SIZE_T], lltype.Void,
+                            sandboxsafe=True, _nowrapper=True)
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
@@ -1,12 +1,13 @@
 from rpython.rlib import rgc
 from rpython.rlib.rarithmetic import ovfcheck
-from rpython.rtyper.lltypesystem import llmemory
+from rpython.rtyper.lltypesystem import llmemory, lltype
 from rpython.jit.metainterp import history
-from rpython.jit.metainterp.history import ConstInt, BoxPtr, ConstPtr
+from rpython.jit.metainterp.history import ConstInt, BoxPtr, ConstPtr, BoxInt
 from rpython.jit.metainterp.resoperation import ResOperation, rop
 from rpython.jit.codewriter import heaptracker
 from rpython.jit.backend.llsupport.symbolic import WORD
-from rpython.jit.backend.llsupport.descr import SizeDescr, ArrayDescr
+from rpython.jit.backend.llsupport.descr import SizeDescr, ArrayDescr,\
+     FLAG_POINTER
 from rpython.jit.metainterp.history import JitCellToken
 
 FLAG_ARRAY = 0
@@ -38,6 +39,7 @@
     _op_malloc_nursery = None
     _v_last_malloced_nursery = None
     c_zero = ConstInt(0)
+    c_null = ConstPtr(lltype.nullptr(llmemory.GCREF.TO))
 
     def __init__(self, gc_ll_descr, cpu):
         self.gc_ll_descr = gc_ll_descr
@@ -45,6 +47,9 @@
         self.newops = []
         self.known_lengths = {}
         self.write_barrier_applied = {}
+        self.delayed_zero_setfields = {}
+        self.last_zero_arrays = []
+        self.setarrayitems_occurred = {}   # {box: {set-of-indexes}}
 
     def rewrite(self, operations):
         # we can only remember one malloc since the next malloc can possibly
@@ -60,6 +65,8 @@
             if op.is_malloc():
                 self.handle_malloc_operation(op)
                 continue
+            if op.is_guard():
+                self.emit_pending_zeros()
             elif op.can_malloc():
                 self.emitting_an_operation_that_can_collect()
             elif op.getopnum() == rop.LABEL:
@@ -68,18 +75,30 @@
             # ---------- write barriers ----------
             if self.gc_ll_descr.write_barrier_descr is not None:
                 if op.getopnum() == rop.SETFIELD_GC:
+                    self.consider_setfield_gc(op)
                     self.handle_write_barrier_setfield(op)
                     continue
                 if op.getopnum() == rop.SETINTERIORFIELD_GC:
                     self.handle_write_barrier_setinteriorfield(op)
                     continue
                 if op.getopnum() == rop.SETARRAYITEM_GC:
+                    self.consider_setarrayitem_gc(op)
                     self.handle_write_barrier_setarrayitem(op)
                     continue
+            else:
+                # this is dead code, but in case we have a gc that does
+                # not have a write barrier and does not zero memory, we would
+                # need to clal it
+                if op.getopnum() == rop.SETFIELD_GC:
+                    self.consider_setfield_gc(op)
+                elif op.getopnum() == rop.SETARRAYITEM_GC:
+                    self.consider_setarrayitem_gc(op)
             # ---------- call assembler -----------
             if op.getopnum() == rop.CALL_ASSEMBLER:
                 self.handle_call_assembler(op)
                 continue
+            if op.getopnum() == rop.JUMP or op.getopnum() == rop.FINISH:
+                self.emit_pending_zeros()
             #
             self.newops.append(op)
         return self.newops
@@ -99,7 +118,7 @@
                                   [op.result, ConstInt(classint)], None,
                                   descr=self.gc_ll_descr.fielddescr_vtable)
                 self.newops.append(op)
-        elif opnum == rop.NEW_ARRAY:
+        elif opnum == rop.NEW_ARRAY or opnum == rop.NEW_ARRAY_CLEAR:
             descr = op.getdescr()
             assert isinstance(descr, ArrayDescr)
             self.handle_new_array(descr, op)
@@ -112,6 +131,54 @@
         else:
             raise NotImplementedError(op.getopname())
 
+    def clear_gc_fields(self, descr, result):
+        if self.gc_ll_descr.malloc_zero_filled:
+            return
+        try:
+            d = self.delayed_zero_setfields[result]
+        except KeyError:
+            d = {}
+            self.delayed_zero_setfields[result] = d
+        for fielddescr in descr.gc_fielddescrs:
+            ofs = self.cpu.unpack_fielddescr(fielddescr)
+            d[ofs] = None
+
+    def consider_setfield_gc(self, op):
+        offset = self.cpu.unpack_fielddescr(op.getdescr())
+        try:
+            del self.delayed_zero_setfields[op.getarg(0)][offset]
+        except KeyError:
+            pass
+
+    def consider_setarrayitem_gc(self, op):
+        array_box = op.getarg(0)
+        index_box = op.getarg(1)
+        if isinstance(array_box, BoxPtr) and isinstance(index_box, ConstInt):
+            try:
+                intset = self.setarrayitems_occurred[array_box]
+            except KeyError:
+                intset = self.setarrayitems_occurred[array_box] = {}
+            intset[index_box.getint()] = None
+
+    def clear_varsize_gc_fields(self, kind, descr, result, v_length, opnum):
+        if self.gc_ll_descr.malloc_zero_filled:
+            return
+        if kind == FLAG_ARRAY:
+            if descr.is_array_of_structs() or descr.is_array_of_pointers():
+                assert opnum == rop.NEW_ARRAY_CLEAR
+            if opnum == rop.NEW_ARRAY_CLEAR:
+                self.handle_clear_array_contents(descr, result, v_length)
+            return
+        if kind == FLAG_STR:
+            hash_descr = self.gc_ll_descr.str_hash_descr
+        elif kind == FLAG_UNICODE:
+            hash_descr = self.gc_ll_descr.unicode_hash_descr
+        else:
+            return
+        op = ResOperation(rop.SETFIELD_GC, [result, self.c_zero], None,
+                          descr=hash_descr)
+        self.newops.append(op)
+
     def handle_new_fixedsize(self, descr, op):
         assert isinstance(descr, SizeDescr)
         size = descr.size
@@ -119,6 +186,7 @@
             self.gen_initialize_tid(op.result, descr.tid)
         else:
             self.gen_malloc_fixedsize(size, descr.tid, op.result)
+        self.clear_gc_fields(descr, op.result)
 
     def handle_new_array(self, arraydescr, op, kind=FLAG_ARRAY):
         v_length = op.getarg(0)
@@ -140,6 +208,8 @@
             # might end up being allocated by malloc_external or some
             # stuff that initializes GC header fields differently
             self.gen_initialize_len(op.result, v_length, arraydescr.lendescr)
+            self.clear_varsize_gc_fields(kind, op.getdescr(), op.result,
+                                         v_length, op.getopnum())
             return
         if (total_size >= 0 and
                 self.gen_malloc_nursery(total_size, op.result)):
@@ -149,7 +219,7 @@
             self.gen_boehm_malloc_array(arraydescr, v_length, op.result)
         else:
             opnum = op.getopnum()
-            if opnum == rop.NEW_ARRAY:
+            if opnum == rop.NEW_ARRAY or opnum == rop.NEW_ARRAY_CLEAR:
                 self.gen_malloc_array(arraydescr, v_length, op.result)
             elif opnum == rop.NEWSTR:
                 self.gen_malloc_str(v_length, op.result)
@@ -157,6 +227,21 @@
                 self.gen_malloc_unicode(v_length, op.result)
             else:
                 raise NotImplementedError(op.getopname())
+        self.clear_varsize_gc_fields(kind, op.getdescr(), op.result, v_length,
+                                     op.getopnum())
+
+    def handle_clear_array_contents(self, arraydescr, v_arr, v_length):
+        assert v_length is not None
+        if isinstance(v_length, ConstInt) and v_length.getint() == 0:
+            return
+        # the ZERO_ARRAY operation will be optimized according to what
+        # SETARRAYITEM_GC we see before the next allocation operation.
+        # See emit_pending_zeros().
+        o = ResOperation(rop.ZERO_ARRAY, [v_arr, self.c_zero, v_length], None,
+                         descr=arraydescr)
+        self.newops.append(o)
+        if isinstance(v_length, ConstInt):
+            self.last_zero_arrays.append(o)
 
     def gen_malloc_frame(self, frame_info, frame, size_box):
         descrs = self.gc_ll_descr.getframedescrs(self.cpu)
@@ -177,10 +262,25 @@
             self.gen_malloc_nursery_varsize_frame(size_box, frame)
             self.gen_initialize_tid(frame, descrs.arraydescr.tid)
             length_box = history.BoxInt()
-            op1 = ResOperation(rop.GETFIELD_GC, [history.ConstInt(frame_info)],
-                               length_box,
-                               descr=descrs.jfi_frame_depth)
-            self.newops.append(op1)
+            # we need to explicitely zero all the gc fields, because
+            # of the unusal malloc pattern
+            extra_ops = [
+                ResOperation(rop.GETFIELD_GC, [history.ConstInt(frame_info)],
+                             length_box, descr=descrs.jfi_frame_depth),
+                ResOperation(rop.SETFIELD_GC, [frame, self.c_zero],
+                             None, descr=descrs.jf_extra_stack_depth),
+                ResOperation(rop.SETFIELD_GC, [frame, self.c_null],
+                             None, descr=descrs.jf_savedata),
+                ResOperation(rop.SETFIELD_GC, [frame, self.c_null],
+                             None, descr=descrs.jf_force_descr),
+                ResOperation(rop.SETFIELD_GC, [frame, self.c_null],
+                             None, descr=descrs.jf_descr),
+                ResOperation(rop.SETFIELD_GC, [frame, self.c_null],
+                             None, descr=descrs.jf_guard_exc),
+                ResOperation(rop.SETFIELD_GC, [frame, self.c_null],
+                             None, descr=descrs.jf_forward),
+            ]
+            self.newops += extra_ops
             self.gen_initialize_len(frame, length_box,
                                     descrs.arraydescr.lendescr)
 
@@ -225,8 +325,42 @@
         # forgets the previous MALLOC_NURSERY, if any; and empty the
         # set 'write_barrier_applied', so that future SETFIELDs will generate
         # a write barrier as usual.
+        # it also writes down all the pending zero ptr fields
         self._op_malloc_nursery = None
         self.write_barrier_applied.clear()
+        self.emit_pending_zeros()
+
+    def emit_pending_zeros(self):
+        # First, try to rewrite the existing ZERO_ARRAY operations from
+        # the 'last_zero_arrays' list.  Note that these operation objects
+        # are also already in 'newops', which is the point.
+        for op in self.last_zero_arrays:
+            assert op.getopnum() == rop.ZERO_ARRAY
+            box = op.getarg(0)
+            try:
+                intset = self.setarrayitems_occurred[box]
+            except KeyError:
+                continue
+            assert op.getarg(1).getint() == 0   # always 'start=0' initially
+            start = 0
+            while start in intset:
+                start += 1
+            op.setarg(1, ConstInt(start))
+            stop = op.getarg(2).getint()
+            assert start <= stop
+            while stop > start and (stop - 1) in intset:
+                stop -= 1
+            op.setarg(2, ConstInt(stop - start))
+            # ^^ may be ConstInt(0); then the operation becomes a no-op
+        del self.last_zero_arrays[:]
+        self.setarrayitems_occurred.clear()
+        #
+        # Then write the ZERO_PTR_FIELDs that are still pending
+        for v, d in self.delayed_zero_setfields.iteritems():
+            for ofs in d.iterkeys():
+                op = ResOperation(rop.ZERO_PTR_FIELD, [v, ConstInt(ofs)], None)
+                self.newops.append(op)
+        self.delayed_zero_setfields.clear()
 
     def _gen_call_malloc_gc(self, args, v_result, descr):
         """Generate a CALL_MALLOC_GC with the given args."""
@@ -338,7 +472,8 @@
 
     def gen_malloc_nursery(self, size, v_result):
         """Try to generate or update a CALL_MALLOC_NURSERY.
-        If that fails, generate a plain CALL_MALLOC_GC instead.
+        If that succeeds, return True; you still need to write the tid.
+        If that fails, return False.
         """
         size = self.round_up_for_allocation(size)
         if not self.gc_ll_descr.can_use_nursery_malloc(size):
diff --git a/rpython/jit/backend/llsupport/test/test_descr.py 
b/rpython/jit/backend/llsupport/test/test_descr.py
--- a/rpython/jit/backend/llsupport/test/test_descr.py
+++ b/rpython/jit/backend/llsupport/test/test_descr.py
@@ -19,6 +19,8 @@
     assert descr_t.size == symbolic.get_size(T, False)
     assert descr_s.count_fields_if_immutable() == -1
     assert descr_t.count_fields_if_immutable() == -1
+    assert descr_t.gc_fielddescrs == []
+    assert len(descr_s.gc_fielddescrs) == 1
     assert descr_s == get_size_descr(c0, S)
     assert descr_s != get_size_descr(c1, S)
     #
@@ -26,6 +28,11 @@
     assert isinstance(descr_s.size, Symbolic)
     assert descr_s.count_fields_if_immutable() == -1
 
+    PARENT = lltype.Struct('P', ('x', lltype.Ptr(T)))
+    STRUCT = lltype.GcStruct('S', ('parent', PARENT), ('y', lltype.Ptr(T)))
+    descr_struct = get_size_descr(c0, STRUCT)
+    assert len(descr_struct.gc_fielddescrs) == 2
+
 def test_get_size_descr_immut():
     S = lltype.GcStruct('S', hints={'immutable': True})
     T = lltype.GcStruct('T', ('parent', S),
diff --git a/rpython/jit/backend/llsupport/test/test_gc.py 
b/rpython/jit/backend/llsupport/test/test_gc.py
--- a/rpython/jit/backend/llsupport/test/test_gc.py
+++ b/rpython/jit/backend/llsupport/test/test_gc.py
@@ -59,7 +59,7 @@
         x += self.gcheaderbuilder.size_gc_header
         return x, tid
 
-    def do_malloc_fixedsize_clear(self, RESTYPE, type_id, size,
+    def do_malloc_fixedsize(self, RESTYPE, type_id, size,
                                   has_finalizer, has_light_finalizer,
                                   contains_weakptr):
         assert not contains_weakptr
@@ -70,7 +70,9 @@
         self.record.append(("fixedsize", repr(size), tid, p))
         return p
 
-    def do_malloc_varsize_clear(self, RESTYPE, type_id, length, size,
+    do_malloc_fixedsize_clear = do_malloc_fixedsize
+
+    def do_malloc_varsize(self, RESTYPE, type_id, length, size,
                                 itemsize, offset_to_length):
         p, tid = self._malloc(type_id, size + itemsize * length)
         (p + offset_to_length).signed[0] = length
@@ -80,6 +82,8 @@
                             repr(offset_to_length), p))
         return p
 
+    do_malloc_varsize_clear = do_malloc_varsize
+
     def _write_barrier_failing_case(self, adr_struct):
         self.record.append(('barrier', adr_struct))
 
diff --git a/rpython/jit/backend/llsupport/test/test_rewrite.py 
b/rpython/jit/backend/llsupport/test/test_rewrite.py
--- a/rpython/jit/backend/llsupport/test/test_rewrite.py
+++ b/rpython/jit/backend/llsupport/test/test_rewrite.py
@@ -69,6 +69,8 @@
         unicodedescr = self.gc_ll_descr.unicode_descr
         strlendescr     = strdescr.lendescr
         unicodelendescr = unicodedescr.lendescr
+        strhashdescr     = self.gc_ll_descr.str_hash_descr
+        unicodehashdescr = self.gc_ll_descr.unicode_hash_descr
 
         casmdescr = JitCellToken()
         clt = FakeLoopToken()
@@ -82,10 +84,15 @@
         jfi_frame_depth = framedescrs.jfi_frame_depth
         jfi_frame_size = framedescrs.jfi_frame_size
         jf_frame_info = framedescrs.jf_frame_info
+        jf_savedata = framedescrs.jf_savedata
+        jf_force_descr = framedescrs.jf_force_descr
+        jf_descr = framedescrs.jf_descr
+        jf_guard_exc = framedescrs.jf_guard_exc
+        jf_forward = framedescrs.jf_forward
+        jf_extra_stack_depth = framedescrs.jf_extra_stack_depth
         signedframedescr = self.cpu.signedframedescr
         floatframedescr = self.cpu.floatframedescr
         casmdescr.compiled_loop_token = clt
-        tzdescr = None # noone cares
         #
         namespace.update(locals())
         #
@@ -123,6 +130,9 @@
     def unpack_arraydescr_size(self, d):
         return 0, d.itemsize, 0
 
+    def unpack_fielddescr(self, d):
+        return d.offset
+
     def arraydescrof(self, ARRAY):
         try:
             return self._cache[ARRAY]
@@ -144,7 +154,7 @@
     def setup_method(self, meth):
         class FakeCPU(BaseFakeCPU):
             def sizeof(self, STRUCT):
-                return SizeDescrWithVTable(102)
+                return SizeDescrWithVTable(102, gc_fielddescrs=[])
         self.cpu = FakeCPU()
         self.gc_ll_descr = GcLLDescr_boehm(None, None, None)
 
@@ -277,10 +287,11 @@
                                                really_not_translated=True)
         self.gc_ll_descr.write_barrier_descr.has_write_barrier_from_array = (
             lambda cpu: True)
+        self.gc_ll_descr.malloc_zero_filled = False
         #
         class FakeCPU(BaseFakeCPU):
             def sizeof(self, STRUCT):
-                descr = SizeDescrWithVTable(104)
+                descr = SizeDescrWithVTable(104, gc_fielddescrs=[])
                 descr.tid = 9315
                 return descr
         self.cpu = FakeCPU()
@@ -313,6 +324,7 @@
             setfield_gc(p1, 5678, descr=tiddescr)
             p2 = int_add(p1, %(tdescr.size)d)
             setfield_gc(p2, 1234, descr=tiddescr)
+            zero_ptr_field(p1, %(tdescr.gc_fielddescrs[0].offset)s)
             jump()
         """)
 
@@ -422,6 +434,7 @@
         [i0]
         p0 = call_malloc_nursery_varsize(1, 1, i0, descr=strdescr)
         setfield_gc(p0, i0, descr=strlendescr)
+        setfield_gc(p0, 0, descr=strhashdescr)
         jump(i0)
         """)
 
@@ -545,15 +558,19 @@
                         unicodedescr.basesize + 10 * unicodedescr.itemsize)d)
             setfield_gc(p0, %(strdescr.tid)d, descr=tiddescr)
             setfield_gc(p0, 14, descr=strlendescr)
+            setfield_gc(p0, 0, descr=strhashdescr)
             p1 = int_add(p0, %(strdescr.basesize + 16 * strdescr.itemsize)d)
             setfield_gc(p1, %(unicodedescr.tid)d, descr=tiddescr)
             setfield_gc(p1, 10, descr=unicodelendescr)
+            setfield_gc(p1, 0, descr=unicodehashdescr)
             p2 = call_malloc_nursery_varsize(2, %(unicodedescr.itemsize)d, i2,\
                                 descr=unicodedescr)
             setfield_gc(p2, i2, descr=unicodelendescr)
+            setfield_gc(p2, 0, descr=unicodehashdescr)
             p3 = call_malloc_nursery_varsize(1, 1, i2, \
                                 descr=strdescr)
             setfield_gc(p3, i2, descr=strlendescr)
+            setfield_gc(p3, 0, descr=strhashdescr)
             jump()
         """)
 
@@ -587,7 +604,7 @@
         self.gc_ll_descr.max_size_of_young_obj = 2000
         self.check_rewrite("""
             [i2, p3]
-            p1 = new_array(129, descr=cdescr)
+            p1 = new_array_clear(129, descr=cdescr)
             call(123456)
             setarrayitem_gc(p1, i2, p3, descr=cdescr)
             jump()
@@ -597,6 +614,7 @@
                                 %(cdescr.basesize + 129 * cdescr.itemsize)d)
             setfield_gc(p1, 8111, descr=tiddescr)
             setfield_gc(p1, 129, descr=clendescr)
+            zero_array(p1, 0, 129, descr=cdescr)
             call(123456)
             cond_call_gc_wb(p1, descr=wbdescr)
             setarrayitem_gc(p1, i2, p3, descr=cdescr)
@@ -608,7 +626,7 @@
         self.gc_ll_descr.max_size_of_young_obj = 2000
         self.check_rewrite("""
             [i2, p3]
-            p1 = new_array(130, descr=cdescr)
+            p1 = new_array_clear(130, descr=cdescr)
             call(123456)
             setarrayitem_gc(p1, i2, p3, descr=cdescr)
             jump()
@@ -618,6 +636,7 @@
                                 %(cdescr.basesize + 130 * cdescr.itemsize)d)
             setfield_gc(p1, 8111, descr=tiddescr)
             setfield_gc(p1, 130, descr=clendescr)
+            zero_array(p1, 0, 130, descr=cdescr)
             call(123456)
             cond_call_gc_wb_array(p1, i2, descr=wbdescr)
             setarrayitem_gc(p1, i2, p3, descr=cdescr)
@@ -639,7 +658,7 @@
     def test_label_makes_size_unknown(self):
         self.check_rewrite("""
             [i2, p3]
-            p1 = new_array(5, descr=cdescr)
+            p1 = new_array_clear(5, descr=cdescr)
             label(p1, i2, p3)
             setarrayitem_gc(p1, i2, p3, descr=cdescr)
             jump()
@@ -649,6 +668,7 @@
                                 %(cdescr.basesize + 5 * cdescr.itemsize)d)
             setfield_gc(p1, 8111, descr=tiddescr)
             setfield_gc(p1, 5, descr=clendescr)
+            zero_array(p1, 0, 5, descr=cdescr)
             label(p1, i2, p3)
             cond_call_gc_wb_array(p1, i2, descr=wbdescr)
             setarrayitem_gc(p1, i2, p3, descr=cdescr)
@@ -709,7 +729,7 @@
     def test_initialization_store_array(self):
         self.check_rewrite("""
             [p1, i2]
-            p0 = new_array(5, descr=cdescr)
+            p0 = new_array_clear(5, descr=cdescr)
             setarrayitem_gc(p0, i2, p1, descr=cdescr)
             jump()
         """, """
@@ -718,10 +738,168 @@
                                 %(cdescr.basesize + 5 * cdescr.itemsize)d)
             setfield_gc(p0, 8111, descr=tiddescr)
             setfield_gc(p0, 5, descr=clendescr)
+            zero_array(p0, 0, 5, descr=cdescr)
             setarrayitem_gc(p0, i2, p1, descr=cdescr)
             jump()
         """)
 
+    def test_zero_array_reduced_left(self):
+        self.check_rewrite("""
+            [p1, p2]
+            p0 = new_array_clear(5, descr=cdescr)
+            setarrayitem_gc(p0, 1, p1, descr=cdescr)
+            setarrayitem_gc(p0, 0, p2, descr=cdescr)
+            jump()
+        """, """
+            [p1, p2]
+            p0 = call_malloc_nursery(    \
+                                %(cdescr.basesize + 5 * cdescr.itemsize)d)
+            setfield_gc(p0, 8111, descr=tiddescr)
+            setfield_gc(p0, 5, descr=clendescr)
+            zero_array(p0, 2, 3, descr=cdescr)
+            setarrayitem_gc(p0, 1, p1, descr=cdescr)
+            setarrayitem_gc(p0, 0, p2, descr=cdescr)
+            jump()
+        """)
+
+    def test_zero_array_reduced_right(self):
+        self.check_rewrite("""
+            [p1, p2]
+            p0 = new_array_clear(5, descr=cdescr)
+            setarrayitem_gc(p0, 3, p1, descr=cdescr)
+            setarrayitem_gc(p0, 4, p2, descr=cdescr)
+            jump()
+        """, """
+            [p1, p2]
+            p0 = call_malloc_nursery(    \
+                                %(cdescr.basesize + 5 * cdescr.itemsize)d)
+            setfield_gc(p0, 8111, descr=tiddescr)
+            setfield_gc(p0, 5, descr=clendescr)
+            zero_array(p0, 0, 3, descr=cdescr)
+            setarrayitem_gc(p0, 3, p1, descr=cdescr)
+            setarrayitem_gc(p0, 4, p2, descr=cdescr)
+            jump()
+        """)
+
+    def test_zero_array_not_reduced_at_all(self):
+        self.check_rewrite("""
+            [p1, p2]
+            p0 = new_array_clear(5, descr=cdescr)
+            setarrayitem_gc(p0, 3, p1, descr=cdescr)
+            setarrayitem_gc(p0, 2, p2, descr=cdescr)
+            setarrayitem_gc(p0, 1, p2, descr=cdescr)
+            jump()
+        """, """
+            [p1, p2]
+            p0 = call_malloc_nursery(    \
+                                %(cdescr.basesize + 5 * cdescr.itemsize)d)
+            setfield_gc(p0, 8111, descr=tiddescr)
+            setfield_gc(p0, 5, descr=clendescr)
+            zero_array(p0, 0, 5, descr=cdescr)
+            setarrayitem_gc(p0, 3, p1, descr=cdescr)
+            setarrayitem_gc(p0, 2, p2, descr=cdescr)
+            setarrayitem_gc(p0, 1, p2, descr=cdescr)
+            jump()
+        """)
+
+    def test_zero_array_reduced_completely(self):
+        self.check_rewrite("""
+            [p1, p2]
+            p0 = new_array_clear(5, descr=cdescr)
+            setarrayitem_gc(p0, 3, p1, descr=cdescr)
+            setarrayitem_gc(p0, 4, p2, descr=cdescr)
+            setarrayitem_gc(p0, 0, p1, descr=cdescr)
+            setarrayitem_gc(p0, 2, p2, descr=cdescr)
+            setarrayitem_gc(p0, 1, p2, descr=cdescr)
+            jump()
+        """, """
+            [p1, p2]
+            p0 = call_malloc_nursery(    \
+                                %(cdescr.basesize + 5 * cdescr.itemsize)d)
+            setfield_gc(p0, 8111, descr=tiddescr)
+            setfield_gc(p0, 5, descr=clendescr)
+            zero_array(p0, 5, 0, descr=cdescr)
+            setarrayitem_gc(p0, 3, p1, descr=cdescr)
+            setarrayitem_gc(p0, 4, p2, descr=cdescr)
+            setarrayitem_gc(p0, 0, p1, descr=cdescr)
+            setarrayitem_gc(p0, 2, p2, descr=cdescr)
+            setarrayitem_gc(p0, 1, p2, descr=cdescr)
+            jump()
+        """)
+
+    def test_zero_array_reduced_left_with_call(self):
+        self.check_rewrite("""
+            [p1, p2]
+            p0 = new_array_clear(5, descr=cdescr)
+            setarrayitem_gc(p0, 0, p1, descr=cdescr)
+            call(321321)
+            setarrayitem_gc(p0, 1, p2, descr=cdescr)
+            jump()
+        """, """
+            [p1, p2]
+            p0 = call_malloc_nursery(    \
+                                %(cdescr.basesize + 5 * cdescr.itemsize)d)
+            setfield_gc(p0, 8111, descr=tiddescr)
+            setfield_gc(p0, 5, descr=clendescr)
+            zero_array(p0, 1, 4, descr=cdescr)
+            setarrayitem_gc(p0, 0, p1, descr=cdescr)
+            call(321321)
+            cond_call_gc_wb(p0, descr=wbdescr)
+            setarrayitem_gc(p0, 1, p2, descr=cdescr)
+            jump()
+        """)
+
+    def test_zero_array_reduced_left_with_label(self):
+        self.check_rewrite("""
+            [p1, p2]
+            p0 = new_array_clear(5, descr=cdescr)
+            setarrayitem_gc(p0, 0, p1, descr=cdescr)
+            label(p0, p2)
+            setarrayitem_gc(p0, 1, p2, descr=cdescr)
+            jump()
+        """, """
+            [p1, p2]
+            p0 = call_malloc_nursery(    \
+                                %(cdescr.basesize + 5 * cdescr.itemsize)d)
+            setfield_gc(p0, 8111, descr=tiddescr)
+            setfield_gc(p0, 5, descr=clendescr)
+            zero_array(p0, 1, 4, descr=cdescr)
+            setarrayitem_gc(p0, 0, p1, descr=cdescr)
+            label(p0, p2)
+            cond_call_gc_wb_array(p0, 1, descr=wbdescr)
+            setarrayitem_gc(p0, 1, p2, descr=cdescr)
+            jump()
+        """)
+
+    def test_zero_array_varsize(self):
+        self.check_rewrite("""
+            [p1, p2, i3]
+            p0 = new_array_clear(i3, descr=bdescr)
+            jump()
+        """, """
+            [p1, p2, i3]
+            p0 = call_malloc_nursery_varsize(0, 1, i3, descr=bdescr)
+            setfield_gc(p0, i3, descr=blendescr)
+            zero_array(p0, 0, i3, descr=bdescr)
+            jump()
+        """)
+
+    def test_zero_array_varsize_cannot_reduce(self):
+        self.check_rewrite("""
+            [p1, p2, i3]
+            p0 = new_array_clear(i3, descr=bdescr)
+            setarrayitem_gc(p0, 0, p1, descr=bdescr)
+            jump()
+        """, """
+            [p1, p2, i3]
+            p0 = call_malloc_nursery_varsize(0, 1, i3, descr=bdescr)
+            setfield_gc(p0, i3, descr=blendescr)
+            zero_array(p0, 0, i3, descr=bdescr)
+            cond_call_gc_wb_array(p0, 0, descr=wbdescr)
+            setarrayitem_gc(p0, 0, p1, descr=bdescr)
+            jump()
+        """)
+
     def test_initialization_store_potentially_large_array(self):
         # the write barrier cannot be omitted, because we might get
         # an array with cards and the GC assumes that the write
@@ -751,9 +929,11 @@
             [i0]
             p0 = call_malloc_nursery(%(tdescr.size)d)
             setfield_gc(p0, 5678, descr=tiddescr)
+            zero_ptr_field(p0, %(tdescr.gc_fielddescrs[0].offset)s)
             p1 = call_malloc_nursery_varsize(1, 1, i0, \
                                 descr=strdescr)
             setfield_gc(p1, i0, descr=strlendescr)
+            setfield_gc(p1, 0, descr=strhashdescr)
             cond_call_gc_wb(p0, descr=wbdescr)
             setfield_gc(p0, p1, descr=tzdescr)
             jump()
@@ -770,6 +950,7 @@
             [p1]
             p0 = call_malloc_nursery(%(tdescr.size)d)
             setfield_gc(p0, 5678, descr=tiddescr)
+            zero_ptr_field(p0, %(tdescr.gc_fielddescrs[0].offset)s)
             label(p0, p1)
             cond_call_gc_wb(p0, descr=wbdescr)
             setfield_gc(p0, p1, descr=tzdescr)
@@ -800,6 +981,12 @@
         p1 = call_malloc_nursery_varsize_frame(i1)
         setfield_gc(p1, 0, descr=tiddescr)
         i2 = getfield_gc(ConstClass(frame_info), descr=jfi_frame_depth)
+        setfield_gc(p1, 0, descr=jf_extra_stack_depth)
+        setfield_gc(p1, NULL, descr=jf_savedata)
+        setfield_gc(p1, NULL, descr=jf_force_descr)
+        setfield_gc(p1, NULL, descr=jf_descr)
+        setfield_gc(p1, NULL, descr=jf_guard_exc)
+        setfield_gc(p1, NULL, descr=jf_forward)
         setfield_gc(p1, i2, descr=framelendescr)
         setfield_gc(p1, ConstClass(frame_info), descr=jf_frame_info)
         setarrayitem_gc(p1, 0, i0, descr=signedframedescr)
diff --git a/rpython/jit/backend/llsupport/test/zrpy_gc_test.py 
b/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
--- a/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
+++ b/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
@@ -223,7 +223,7 @@
 ##        return None, f, None
 
     def define_compile_framework_1(cls):
-        # a moving GC.  Supports malloc_varsize_nonmovable.  Simple test, works
+        # a moving GC.  Simple test, works
         # without write_barriers and root stack enumeration.
         def f(n, x, *args):
             y = X()
diff --git a/rpython/jit/backend/test/runner_test.py 
b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -2036,6 +2036,14 @@
                                     'ref', descr=arraydescr)
         assert r1.value != r2.value
         a = lltype.cast_opaque_ptr(lltype.Ptr(A), r1.value)
+        assert len(a) == 342
+
+    def test_new_array_clear(self):
+        A = lltype.GcArray(lltype.Signed)
+        arraydescr = self.cpu.arraydescrof(A)
+        r1 = self.execute_operation(rop.NEW_ARRAY_CLEAR, [BoxInt(342)],
+                                    'ref', descr=arraydescr)
+        a = lltype.cast_opaque_ptr(lltype.Ptr(A), r1.value)
         assert a[0] == 0
         assert len(a) == 342
 
@@ -4272,9 +4280,6 @@
         fail = self.cpu.get_latest_descr(deadframe)
         assert fail.identifier == 23
         assert self.cpu.get_int_value(deadframe, 0) == 42
-        # make sure that force reads the registers from a zeroed piece of
-        # memory
-        assert values[0] == 0
 
     def test_compile_bridge_while_running(self):
         def func():
@@ -4442,3 +4447,99 @@
         res = self.execute_operation(rop.CAST_FLOAT_TO_SINGLEFLOAT,
                                    [boxfloat(12.5)], 'int')
         assert res.getint() == struct.unpack("I", struct.pack("f", 12.5))[0]
+
+    def test_zero_ptr_field(self):
+        from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
+        
+        if not isinstance(self.cpu, AbstractLLCPU):
+            py.test.skip("llgraph can't do zero_ptr_field")
+        T = lltype.GcStruct('T')
+        S = lltype.GcStruct('S', ('x', lltype.Ptr(T)))
+        tdescr = self.cpu.sizeof(T)
+        sdescr = self.cpu.sizeof(S)
+        fielddescr = self.cpu.fielddescrof(S, 'x')
+        loop = parse("""
+        []
+        p0 = new(descr=tdescr)
+        p1 = new(descr=sdescr)
+        setfield_gc(p1, p0, descr=fielddescr)
+        zero_ptr_field(p1, %d)
+        finish(p1)
+        """ % fielddescr.offset, namespace=locals())
+        looptoken = JitCellToken()
+        self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+        deadframe = self.cpu.execute_token(looptoken)
+        ref = self.cpu.get_ref_value(deadframe, 0)
+        s = lltype.cast_opaque_ptr(lltype.Ptr(S), ref)
+        assert not s.x
+
+    def test_zero_ptr_field_2(self):
+        from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
+
+        if not isinstance(self.cpu, AbstractLLCPU):
+            py.test.skip("llgraph does not do zero_ptr_field")
+        
+        from rpython.jit.backend.llsupport import symbolic
+        S = lltype.GcStruct('S', ('x', lltype.Signed),
+                                 ('p', llmemory.GCREF),
+                                 ('y', lltype.Signed))
+        s = lltype.malloc(S)
+        s.x = -1296321
+        s.y = -4398176
+        s_ref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
+        s.p = s_ref
+        ofs_p, _ = symbolic.get_field_token(S, 'p', False)
+        #
+        self.execute_operation(rop.ZERO_PTR_FIELD, [
+            BoxPtr(s_ref), ConstInt(ofs_p)],   # OK for now to assume that the
+            'void')                            # 2nd argument is a constant
+        #
+        assert s.x == -1296321
+        assert s.p == lltype.nullptr(llmemory.GCREF.TO)
+        assert s.y == -4398176
+
+    def test_zero_array(self):
+        from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
+
+        if not isinstance(self.cpu, AbstractLLCPU):
+            py.test.skip("llgraph does not do zero_array")
+        
+        PAIR = lltype.Struct('PAIR', ('a', lltype.Signed), ('b', 
lltype.Signed))
+        for OF in [lltype.Signed, rffi.INT, rffi.SHORT, rffi.UCHAR, PAIR]:
+            A = lltype.GcArray(OF)
+            arraydescr = self.cpu.arraydescrof(A)
+            a = lltype.malloc(A, 100)
+            addr = llmemory.cast_ptr_to_adr(a)
+            a_int = heaptracker.adr2int(addr)
+            a_ref = lltype.cast_opaque_ptr(llmemory.GCREF, a)
+            for (start, length) in [(0, 100), (49, 49), (1, 98),
+                                    (15, 9), (10, 10), (47, 0),
+                                    (0, 4)]:
+                for cls1 in [ConstInt, BoxInt]:
+                    for cls2 in [ConstInt, BoxInt]:
+                        print 'a_int:', a_int
+                        print 'of:', OF
+                        print 'start:', cls1.__name__, start
+                        print 'length:', cls2.__name__, length
+                        for i in range(100):
+                            if OF == PAIR:
+                                a[i].a = a[i].b = -123456789
+                            else:
+                                a[i] = rffi.cast(OF, -123456789)
+                        startbox = cls1(start)
+                        lengthbox = cls2(length)
+                        if cls1 == cls2 and start == length:
+                            lengthbox = startbox    # same box!
+                        self.execute_operation(rop.ZERO_ARRAY,
+                                               [BoxPtr(a_ref),
+                                                startbox,
+                                                lengthbox],
+                                           'void', descr=arraydescr)
+                        assert len(a) == 100
+                        for i in range(100):
+                            val = (0 if start <= i < start + length
+                                     else -123456789)
+                            if OF == PAIR:
+                                assert a[i].a == a[i].b == val
+                            else:
+                                assert a[i] == rffi.cast(OF, val)
diff --git a/rpython/jit/backend/test/test_ll_random.py 
b/rpython/jit/backend/test/test_ll_random.py
--- a/rpython/jit/backend/test/test_ll_random.py
+++ b/rpython/jit/backend/test/test_ll_random.py
@@ -95,7 +95,10 @@
             fields.append(('parent', rclass.OBJECT))
             kwds['hints'] = {'vtable': with_vtable._obj}
         for i in range(r.randrange(1, 5)):
-            TYPE = self.get_random_primitive_type(r)
+            if r.random() < 0.1:
+                TYPE = llmemory.GCREF
+            else:
+                TYPE = self.get_random_primitive_type(r)
             fields.append(('f%d' % i, TYPE))
         S = type('S%d' % self.counter, *fields, **kwds)
         self.counter += 1
@@ -246,13 +249,43 @@
             op = ResOperation(self.opnum, [v, c_vtable2], None)
             return op, False
 
+class ZeroPtrFieldOperation(test_random.AbstractOperation):
+    def field_descr(self, builder, r):
+        if getattr(builder.cpu, 'is_llgraph', False):
+            raise test_random.CannotProduceOperation
+        v, S = builder.get_structptr_var(r, )
+        names = S._names
+        if names[0] == 'parent':
+            names = names[1:]
+        choice = []
+        for name in names:
+            FIELD = getattr(S, name)
+            if isinstance(FIELD, lltype.Ptr) and FIELD._needsgc():
+                choice.append(name)
+        if not choice:
+            raise test_random.CannotProduceOperation
+        name = r.choice(choice)
+        descr = builder.cpu.fielddescrof(S, name)
+        return v, descr.offset
+
+    def produce_into(self, builder, r):
+        v, offset = self.field_descr(builder, r)
+        builder.do(self.opnum, [v, ConstInt(offset)], None)
+
 class GetFieldOperation(test_random.AbstractOperation):
     def field_descr(self, builder, r):
         v, S = builder.get_structptr_var(r, )
         names = S._names
         if names[0] == 'parent':
             names = names[1:]
-        name = r.choice(names)
+        choice = []
+        for name in names:
+            FIELD = getattr(S, name)
+            if not isinstance(FIELD, lltype.Ptr):
+                choice.append(name)
+        if not choice:
+            raise test_random.CannotProduceOperation
+        name = r.choice(choice)
         descr = builder.cpu.fielddescrof(S, name)
         descr._random_info = 'cpu.fielddescrof(..., %r)' % (name,)
         descr._random_type = S
@@ -274,7 +307,14 @@
                                          array_of_structs=True)
         array = v.getref(lltype.Ptr(A))
         v_index = builder.get_index(len(array), r)
-        name = r.choice(A.OF._names)
+        choice = []
+        for name in A.OF._names:
+            FIELD = getattr(A.OF, name)
+            if not isinstance(FIELD, lltype.Ptr):
+                choice.append(name)
+        if not choice:
+            raise test_random.CannotProduceOperation
+        name = r.choice(choice)
         descr = builder.cpu.interiorfielddescrof(A, name)
         descr._random_info = 'cpu.interiorfielddescrof(..., %r)' % (name,)
         descr._random_type = A
@@ -682,6 +722,7 @@
     OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC))
     OPERATIONS.append(GetInteriorFieldOperation(rop.GETINTERIORFIELD_GC))
     OPERATIONS.append(SetFieldOperation(rop.SETFIELD_GC))
+    OPERATIONS.append(ZeroPtrFieldOperation(rop.ZERO_PTR_FIELD))
     OPERATIONS.append(SetInteriorFieldOperation(rop.SETINTERIORFIELD_GC))
     OPERATIONS.append(NewOperation(rop.NEW))
     OPERATIONS.append(NewOperation(rop.NEW_WITH_VTABLE))
@@ -689,7 +730,7 @@
     OPERATIONS.append(GetArrayItemOperation(rop.GETARRAYITEM_GC))
     OPERATIONS.append(GetArrayItemOperation(rop.GETARRAYITEM_GC))
     OPERATIONS.append(SetArrayItemOperation(rop.SETARRAYITEM_GC))
-    OPERATIONS.append(NewArrayOperation(rop.NEW_ARRAY))
+    OPERATIONS.append(NewArrayOperation(rop.NEW_ARRAY_CLEAR))
     OPERATIONS.append(ArrayLenOperation(rop.ARRAYLEN_GC))
     OPERATIONS.append(NewStrOperation(rop.NEWSTR))
     OPERATIONS.append(NewUnicodeOperation(rop.NEWUNICODE))
diff --git a/rpython/jit/backend/test/test_random.py 
b/rpython/jit/backend/test/test_random.py
--- a/rpython/jit/backend/test/test_random.py
+++ b/rpython/jit/backend/test/test_random.py
@@ -52,10 +52,13 @@
 
     def do(self, opnum, argboxes, descr=None):
         self.fakemetainterp._got_exc = None
-        v_result = execute_nonspec(self.cpu, self.fakemetainterp,
-                                   opnum, argboxes, descr)
-        if isinstance(v_result, Const):
-            v_result = v_result.clonebox()
+        if opnum == rop.ZERO_PTR_FIELD:
+            v_result = None
+        else:
+            v_result = execute_nonspec(self.cpu, self.fakemetainterp,
+                                       opnum, argboxes, descr)
+            if isinstance(v_result, Const):
+                v_result = v_result.clonebox()
         self.loop.operations.append(ResOperation(opnum, argboxes, v_result,
                                                  descr))
         return v_result
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
@@ -1486,6 +1486,8 @@
         dest_addr = AddressLoc(base_loc, ofs_loc)
         self.save_into_mem(dest_addr, value_loc, size_loc)
 
+    genop_discard_zero_ptr_field = genop_discard_setfield_gc
+
     def genop_discard_setinteriorfield_gc(self, op, arglocs):
         (base_loc, ofs_loc, itemsize_loc, fieldsize_loc,
             index_loc, temp_loc, value_loc) = arglocs
@@ -2361,6 +2363,43 @@
             elif IS_X86_64:
                 mc.MOVSX32_rj(loc.value, addr)     # memory read, sign-extend
 
+    def genop_discard_zero_array(self, op, arglocs):
+        (base_loc, startindex_loc, bytes_loc,
+         itemsize_loc, baseofs_loc, null_loc) = arglocs
+        assert isinstance(bytes_loc, ImmedLoc)
+        assert isinstance(itemsize_loc, ImmedLoc)
+        assert isinstance(baseofs_loc, ImmedLoc)
+        assert isinstance(null_loc, RegLoc) and null_loc.is_xmm
+        baseofs = baseofs_loc.value
+        nbytes = bytes_loc.value
+        if valid_addressing_size(itemsize_loc.value):
+            scale = get_scale(itemsize_loc.value)
+        else:
+            assert isinstance(startindex_loc, ImmedLoc)
+            baseofs += startindex_loc.value * itemsize_loc.value
+            startindex_loc = imm0
+            scale = 0
+        null_reg_cleared = False
+        i = 0
+        while i < nbytes:
+            addr = addr_add(base_loc, startindex_loc, baseofs + i, scale)
+            current = nbytes - i
+            if current >= 16:
+                current = 16
+                if not null_reg_cleared:
+                    self.mc.XORPS_xx(null_loc.value, null_loc.value)
+                    null_reg_cleared = True
+                self.mc.MOVUPS(addr, null_loc)
+            else:
+                if current >= WORD:
+                    current = WORD
+                elif current >= 4:
+                    current = 4
+                elif current >= 2:
+                    current = 2
+                self.save_into_mem(addr, imm0, imm(current))
+            i += current
+
 
 genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST
 genop_list = [Assembler386.not_implemented_op] * rop._LAST
diff --git a/rpython/jit/backend/x86/regalloc.py 
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -8,7 +8,8 @@
     unpack_arraydescr, unpack_fielddescr, unpack_interiorfielddescr)
 from rpython.jit.backend.llsupport.gcmap import allocate_gcmap
 from rpython.jit.backend.llsupport.regalloc import (FrameManager, BaseRegalloc,
-     RegisterManager, TempBox, compute_vars_longevity, is_comparison_or_ovf_op)
+     RegisterManager, TempBox, compute_vars_longevity, is_comparison_or_ovf_op,
+     valid_addressing_size)
 from rpython.jit.backend.x86 import rx86
 from rpython.jit.backend.x86.arch import (WORD, JITFRAME_FIXED_SIZE, IS_X86_32,
     IS_X86_64)
@@ -958,6 +959,13 @@
                                               need_lower_byte=need_lower_byte)
         self.perform_discard(op, [base_loc, ofs_loc, size_loc, value_loc])
 
+    def consider_zero_ptr_field(self, op):
+        ofs_loc = imm(op.getarg(1).getint())
+        size_loc = imm(WORD)
+        base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), [])
+        value_loc = imm(0)
+        self.perform_discard(op, [base_loc, ofs_loc, size_loc, value_loc])
+
     consider_setfield_raw = consider_setfield_gc
 
     def consider_setinteriorfield_gc(self, op):
@@ -1376,6 +1384,72 @@
     def consider_keepalive(self, op):
         pass
 
+    def consider_zero_array(self, op):
+        itemsize, baseofs, _ = unpack_arraydescr(op.getdescr())
+        length_box = op.getarg(2)
+        if isinstance(length_box, ConstInt):
+            constbytes = length_box.getint() * itemsize
+            if constbytes == 0:
+                return    # nothing to do
+        else:
+            constbytes = -1
+        args = op.getarglist()
+        base_loc = self.rm.make_sure_var_in_reg(args[0], args)
+        startindex_loc = self.rm.make_sure_var_in_reg(args[1], args)
+        if 0 <= constbytes <= 16 * 8 and (
+                valid_addressing_size(itemsize) or
+-               isinstance(startindex_loc, ImmedLoc)):
+            if IS_X86_64:
+                null_loc = X86_64_XMM_SCRATCH_REG
+            else:
+                null_box = TempBox()
+                null_loc = self.xrm.force_allocate_reg(null_box)
+                self.xrm.possibly_free_var(null_box)
+            self.perform_discard(op, [base_loc, startindex_loc,
+                                      imm(constbytes), imm(itemsize),
+                                      imm(baseofs), null_loc])
+        else:
+            # base_loc and startindex_loc are in two regs here (or they are
+            # immediates).  Compute the dstaddr_loc, which is the raw
+            # address that we will pass as first argument to memset().
+            # It can be in the same register as either one, but not in
+            # args[2], because we're still needing the latter.
+            dstaddr_box = TempBox()
+            dstaddr_loc = self.rm.force_allocate_reg(dstaddr_box, [args[2]])
+            itemsize_loc = imm(itemsize)
+            dst_addr = self.assembler._get_interiorfield_addr(
+                dstaddr_loc, startindex_loc, itemsize_loc,
+                base_loc, imm(baseofs))
+            self.assembler.mc.LEA(dstaddr_loc, dst_addr)
+            #
+            if constbytes >= 0:
+                length_loc = imm(constbytes)
+            else:
+                # load length_loc in a register different than dstaddr_loc
+                length_loc = self.rm.make_sure_var_in_reg(length_box,
+                                                          [dstaddr_box])
+                if itemsize > 1:
+                    # we need a register that is different from dstaddr_loc,
+                    # but which can be identical to length_loc (as usual,
+                    # only if the length_box is not used by future operations)
+                    bytes_box = TempBox()
+                    bytes_loc = self.rm.force_allocate_reg(bytes_box,
+                                                           [dstaddr_box])
+                    b_adr = self.assembler._get_interiorfield_addr(
+                        bytes_loc, length_loc, itemsize_loc, imm0, imm0)
+                    self.assembler.mc.LEA(bytes_loc, b_adr)
+                    length_box = bytes_box
+                    length_loc = bytes_loc
+            #
+            # call memset()
+            self.rm.before_call()
+            self.xrm.before_call()
+            self.assembler.simple_call_no_collect(
+                imm(self.assembler.memset_addr),
+                [dstaddr_loc, imm0, length_loc])
+            self.rm.possibly_free_var(length_box)
+            self.rm.possibly_free_var(dstaddr_box)
+
     def not_implemented_op(self, op):
         not_implemented("not implemented operation: %s" % op.getopname())
 
diff --git a/rpython/jit/backend/x86/regloc.py 
b/rpython/jit/backend/x86/regloc.py
--- a/rpython/jit/backend/x86/regloc.py
+++ b/rpython/jit/backend/x86/regloc.py
@@ -664,6 +664,7 @@
 
     MOVDQ = _binaryop('MOVDQ')
     MOVD32 = _binaryop('MOVD32')
+    MOVUPS = _binaryop('MOVUPS')
 
     CALL = _relative_unaryop('CALL')
     JMP = _relative_unaryop('JMP')
diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py
--- a/rpython/jit/backend/x86/rx86.py
+++ b/rpython/jit/backend/x86/rx86.py
@@ -634,6 +634,9 @@
     MOVD32_xs = xmminsn('\x66', rex_nw, '\x0F\x6E', register(1, 8), 
stack_sp(2))
 
     PSRAD_xi = xmminsn('\x66', rex_nw, '\x0F\x72', register(1), '\xE0', 
immediate(2, 'b'))
+    MOVUPS_mx = xmminsn(rex_nw, '\x0F\x11', register(2, 8), 
mem_reg_plus_const(1))
+    MOVUPS_jx = xmminsn(rex_nw, '\x0F\x11', register(2, 8), abs_(1))
+    MOVUPS_ax = xmminsn(rex_nw, '\x0F\x11', register(2, 8), 
mem_reg_plus_scaled_reg_plus_const(1))
 
     # ------------------------------------------------------------
 
@@ -764,6 +767,7 @@
 define_modrm_modes('DIVSD_x*', ['\xF2', rex_nw, '\x0F\x5E', register(1, 8)], 
regtype='XMM')
 define_modrm_modes('UCOMISD_x*', ['\x66', rex_nw, '\x0F\x2E', register(1, 8)], 
regtype='XMM')
 define_modrm_modes('XORPD_x*', ['\x66', rex_nw, '\x0F\x57', register(1, 8)], 
regtype='XMM')
+define_modrm_modes('XORPS_x*', [rex_nw, '\x0F\x57', register(1, 8)], 
regtype='XMM')
 define_modrm_modes('ANDPD_x*', ['\x66', rex_nw, '\x0F\x54', register(1, 8)], 
regtype='XMM')
 
 def define_pxmm_insn(insnname_template, insn_char):
diff --git a/rpython/jit/codewriter/assembler.py 
b/rpython/jit/codewriter/assembler.py
--- a/rpython/jit/codewriter/assembler.py
+++ b/rpython/jit/codewriter/assembler.py
@@ -291,6 +291,7 @@
     'int_sub',
     'jit_merge_point',
     'new_array',
+    'new_array_clear',
     'newstr',
     'setarrayitem_gc_i',
     'setarrayitem_gc_r',
diff --git a/rpython/jit/codewriter/codewriter.py 
b/rpython/jit/codewriter/codewriter.py
--- a/rpython/jit/codewriter/codewriter.py
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to