[pypy-commit] pypy default: (antocuni) remerge the branch that was likely not at fault

fijal noreply at buildbot.pypy.org
Mon Apr 15 17:05:20 CEST 2013


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: 
Changeset: r63372:ea27bafd1cd3
Date: 2013-04-15 17:04 +0200
http://bitbucket.org/pypy/pypy/changeset/ea27bafd1cd3/

Log:	(antocuni) remerge the branch that was likely not at fault

diff too long, truncating to 2000 out of 2643 lines

diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py
--- a/pypy/module/_cffi_backend/ccallback.py
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -134,7 +134,7 @@
             # W_CTypePrimitiveSigned.convert_from_object() in order
             # to write a whole 'ffi_arg'.
             value = misc.as_long(space, w_res)
-            misc.write_raw_integer_data(ll_res, value, SIZE_OF_FFI_ARG)
+            misc.write_raw_signed_data(ll_res, value, SIZE_OF_FFI_ARG)
             return
         else:
             # zero extension: fill the '*result' with zeros, and (on big-
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -280,8 +280,13 @@
         return self.ctype.iter(self)
 
     @specialize.argtype(1)
-    def write_raw_integer_data(self, source):
-        misc.write_raw_integer_data(self._cdata, source, self.ctype.size)
+    def write_raw_signed_data(self, source):
+        misc.write_raw_signed_data(self._cdata, source, self.ctype.size)
+        keepalive_until_here(self)
+
+    @specialize.argtype(1)
+    def write_raw_unsigned_data(self, source):
+        misc.write_raw_unsigned_data(self._cdata, source, self.ctype.size)
         keepalive_until_here(self)
 
     def write_raw_float_data(self, source):
diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -63,7 +63,7 @@
         else:
             value = self._cast_generic(w_ob)
         w_cdata = cdataobj.W_CDataMem(space, self.size, self)
-        w_cdata.write_raw_integer_data(value)
+        self.write_raw_integer_data(w_cdata, value)
         return w_cdata
 
     def _cast_result(self, intvalue):
@@ -94,6 +94,9 @@
         from pypy.module._cffi_backend import newtype
         return newtype.new_primitive_type(self.space, "int")
 
+    def write_raw_integer_data(self, w_cdata, value):
+        w_cdata.write_raw_unsigned_data(value)
+
 
 class W_CTypePrimitiveChar(W_CTypePrimitiveCharOrUniChar):
     _attrs_ = []
@@ -185,10 +188,10 @@
             if self.size < rffi.sizeof(lltype.Signed):
                 if r_uint(value) - self.vmin > self.vrangemax:
                     self._overflow(w_ob)
-            misc.write_raw_integer_data(cdata, value, self.size)
+            misc.write_raw_signed_data(cdata, value, self.size)
         else:
             value = misc.as_long_long(self.space, w_ob)
-            misc.write_raw_integer_data(cdata, value, self.size)
+            misc.write_raw_signed_data(cdata, value, self.size)
 
     def get_vararg_type(self):
         if self.size < rffi.sizeof(rffi.INT):
@@ -196,6 +199,9 @@
             return newtype.new_primitive_type(self.space, "int")
         return self
 
+    def write_raw_integer_data(self, w_cdata, value):
+        w_cdata.write_raw_signed_data(value)
+
 
 class W_CTypePrimitiveUnsigned(W_CTypePrimitive):
     _attrs_            = ['value_fits_long', 'value_fits_ulong', 'vrangemax']
@@ -222,10 +228,10 @@
             if self.value_fits_long:
                 if value > self.vrangemax:
                     self._overflow(w_ob)
-            misc.write_raw_integer_data(cdata, value, self.size)
+            misc.write_raw_unsigned_data(cdata, value, self.size)
         else:
             value = misc.as_unsigned_long_long(self.space, w_ob, strict=True)
-            misc.write_raw_integer_data(cdata, value, self.size)
+            misc.write_raw_unsigned_data(cdata, value, self.size)
 
     def convert_to_object(self, cdata):
         if self.value_fits_ulong:
@@ -244,6 +250,9 @@
             return newtype.new_primitive_type(self.space, "int")
         return self
 
+    def write_raw_integer_data(self, w_cdata, value):
+        w_cdata.write_raw_unsigned_data(value)
+
 
 class W_CTypePrimitiveBool(W_CTypePrimitiveUnsigned):
     _attrs_ = []
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -242,11 +242,13 @@
         #
         value = misc.as_long_long(space, w_ob)
         if isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned):
+            is_signed = True
             fmin = -(r_longlong(1) << (self.bitsize - 1))
             fmax = (r_longlong(1) << (self.bitsize - 1)) - 1
             if fmax == 0:
                 fmax = 1      # special case to let "int x:1" receive "1"
         else:
+            is_signed = False
             fmin = r_longlong(0)
             fmax = r_longlong((r_ulonglong(1) << self.bitsize) - 1)
         if value < fmin or value > fmax:
@@ -258,7 +260,10 @@
         rawvalue = r_ulonglong(value) << self.bitshift
         rawfielddata = misc.read_raw_unsigned_data(cdata, ctype.size)
         rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask)
-        misc.write_raw_integer_data(cdata, rawfielddata, ctype.size)
+        if is_signed:
+            misc.write_raw_signed_data(cdata, rawfielddata, ctype.size)
+        else:
+            misc.write_raw_unsigned_data(cdata, rawfielddata, ctype.size)
 
 
 W_CField.typedef = TypeDef(
diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py
--- a/pypy/module/_cffi_backend/misc.py
+++ b/pypy/module/_cffi_backend/misc.py
@@ -9,6 +9,7 @@
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
 
+
 # ____________________________________________________________
 
 _prim_signed_types = unrolling_iterable([
@@ -65,19 +66,22 @@
     return rffi.cast(rffi.LONGDOUBLEP, target)[0]
 
 @specialize.argtype(1)
-def write_raw_integer_data(target, source, size):
-    if is_signed_integer_type(lltype.typeOf(source)):
-        for TP, TPP in _prim_signed_types:
-            if size == rffi.sizeof(TP):
-                rffi.cast(TPP, target)[0] = rffi.cast(TP, source)
-                return
-    else:
-        for TP, TPP in _prim_unsigned_types:
-            if size == rffi.sizeof(TP):
-                rffi.cast(TPP, target)[0] = rffi.cast(TP, source)
-                return
+def write_raw_unsigned_data(target, source, size):
+    for TP, TPP in _prim_unsigned_types:
+        if size == rffi.sizeof(TP):
+            rffi.cast(TPP, target)[0] = rffi.cast(TP, source)
+            return
     raise NotImplementedError("bad integer size")
 
+ at specialize.argtype(1)
+def write_raw_signed_data(target, source, size):
+    for TP, TPP in _prim_signed_types:
+        if size == rffi.sizeof(TP):
+            rffi.cast(TPP, target)[0] = rffi.cast(TP, source)
+            return
+    raise NotImplementedError("bad integer size")
+
+
 def write_raw_float_data(target, source, size):
     for TP, TPP in _prim_float_types:
         if size == rffi.sizeof(TP):
diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
deleted file mode 100644
--- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py
+++ /dev/null
@@ -1,272 +0,0 @@
-import sys, py
-from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
-
-class Test__ffi(BaseTestPyPyC):
-
-    def test__ffi_call(self):
-        from rpython.rlib.test.test_clibffi import get_libm_name
-        def main(libm_name):
-            try:
-                from _ffi import CDLL, types
-            except ImportError:
-                sys.stderr.write('SKIP: cannot import _ffi\n')
-                return 0
-
-            libm = CDLL(libm_name)
-            pow = libm.getfunc('pow', [types.double, types.double],
-                               types.double)
-            i = 0
-            res = 0
-            while i < 300:
-                tmp = pow(2, 3)   # ID: fficall
-                res += tmp
-                i += 1
-            return pow.getaddr(), res
-        #
-        libm_name = get_libm_name(sys.platform)
-        log = self.run(main, [libm_name])
-        pow_addr, res = log.result
-        assert res == 8.0 * 300
-        py.test.xfail()     # XXX re-optimize _ffi for the JIT?
-        loop, = log.loops_by_filename(self.filepath)
-        if 'ConstClass(pow)' in repr(loop):   # e.g. OS/X
-            pow_addr = 'ConstClass(pow)'
-        assert loop.match_by_id('fficall', """
-            guard_not_invalidated(descr=...)
-            i17 = force_token()
-            setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>)
-            f21 = call_release_gil(%s, 2.000000, 3.000000, descr=<Callf 8 ff EF=6>)
-            guard_not_forced(descr=...)
-            guard_no_exception(descr=...)
-        """ % pow_addr)
-
-
-    def test__ffi_call_frame_does_not_escape(self):
-        from rpython.rlib.test.test_clibffi import get_libm_name
-        def main(libm_name):
-            try:
-                from _ffi import CDLL, types
-            except ImportError:
-                sys.stderr.write('SKIP: cannot import _ffi\n')
-                return 0
-
-            libm = CDLL(libm_name)
-            pow = libm.getfunc('pow', [types.double, types.double],
-                               types.double)
-
-            def mypow(a, b):
-                return pow(a, b)
-
-            i = 0
-            res = 0
-            while i < 300:
-                tmp = mypow(2, 3)
-                res += tmp
-                i += 1
-            return pow.getaddr(), res
-        #
-        libm_name = get_libm_name(sys.platform)
-        log = self.run(main, [libm_name])
-        pow_addr, res = log.result
-        assert res == 8.0 * 300
-        loop, = log.loops_by_filename(self.filepath)
-        opnames = log.opnames(loop.allops())
-        # we only force the virtualref, not its content
-        assert opnames.count('new_with_vtable') == 1
-
-    def test__ffi_call_releases_gil(self):
-        from rpython.rlib.clibffi import get_libc_name
-        def main(libc_name, n):
-            import time
-            import os
-            from threading import Thread
-            #
-            if os.name == 'nt':
-                from _ffi import WinDLL, types
-                libc = WinDLL('Kernel32.dll')
-                sleep = libc.getfunc('Sleep', [types.uint], types.uint)
-                delays = [0]*n + [1000]
-            else:
-                from _ffi import CDLL, types
-                libc = CDLL(libc_name)
-                sleep = libc.getfunc('sleep', [types.uint], types.uint)
-                delays = [0]*n + [1]
-            #
-            def loop_of_sleeps(i, delays):
-                for delay in delays:
-                    sleep(delay)    # ID: sleep
-            #
-            threads = [Thread(target=loop_of_sleeps, args=[i, delays]) for i in range(5)]
-            start = time.time()
-            for i, thread in enumerate(threads):
-                thread.start()
-            for thread in threads:
-                thread.join()
-            end = time.time()
-            return end - start
-        log = self.run(main, [get_libc_name(), 200], threshold=150,
-                       import_site=True)
-        assert 1 <= log.result <= 1.5 # at most 0.5 seconds of overhead
-        loops = log.loops_by_id('sleep')
-        assert len(loops) == 1 # make sure that we actually JITted the loop
-
-    def test_ctypes_call(self):
-        from rpython.rlib.test.test_clibffi import get_libm_name
-        def main(libm_name):
-            import ctypes
-            libm = ctypes.CDLL(libm_name)
-            fabs = libm.fabs
-            fabs.argtypes = [ctypes.c_double]
-            fabs.restype = ctypes.c_double
-            x = -4
-            i = 0
-            while i < 300:
-                x = fabs(x)
-                x = x - 100
-                i += 1
-            return fabs._ptr.getaddr(), x
-
-        libm_name = get_libm_name(sys.platform)
-        log = self.run(main, [libm_name], import_site=True)
-        fabs_addr, res = log.result
-        assert res == -4.0
-        loop, = log.loops_by_filename(self.filepath)
-        ops = loop.allops()
-        opnames = log.opnames(ops)
-        assert opnames.count('new_with_vtable') == 1 # only the virtualref
-        py.test.xfail()     # XXX re-optimize _ffi for the JIT?
-        assert opnames.count('call_release_gil') == 1
-        idx = opnames.index('call_release_gil')
-        call = ops[idx]
-        assert (call.args[0] == 'ConstClass(fabs)' or    # e.g. OS/X
-                int(call.args[0]) == fabs_addr)
-
-
-    def test__ffi_struct(self):
-        def main():
-            from _ffi import _StructDescr, Field, types
-            fields = [
-                Field('x', types.slong),
-                ]
-            descr = _StructDescr('foo', fields)
-            struct = descr.allocate()
-            i = 0
-            while i < 300:
-                x = struct.getfield('x')   # ID: getfield
-                x = x+1
-                struct.setfield('x', x)    # ID: setfield
-                i += 1
-            return struct.getfield('x')
-        #
-        log = self.run(main, [])
-        py.test.xfail()     # XXX re-optimize _ffi for the JIT?
-        loop, = log.loops_by_filename(self.filepath)
-        assert loop.match_by_id('getfield', """
-            guard_not_invalidated(descr=...)
-            i57 = getfield_raw(i46, descr=<FieldS dynamic 0>)
-        """)
-        assert loop.match_by_id('setfield', """
-            setfield_raw(i44, i57, descr=<FieldS dynamic 0>)
-        """)
-
-
-    def test__cffi_call(self):
-        from rpython.rlib.test.test_clibffi import get_libm_name
-        def main(libm_name):
-            try:
-                import _cffi_backend
-            except ImportError:
-                sys.stderr.write('SKIP: cannot import _cffi_backend\n')
-                return 0
-
-            libm = _cffi_backend.load_library(libm_name)
-            BDouble = _cffi_backend.new_primitive_type("double")
-            BPow = _cffi_backend.new_function_type([BDouble, BDouble], BDouble)
-            pow = libm.load_function(BPow, 'pow')
-            i = 0
-            res = 0
-            while i < 300:
-                tmp = pow(2, 3)   # ID: cfficall
-                res += tmp
-                i += 1
-            BLong = _cffi_backend.new_primitive_type("long")
-            pow_addr = int(_cffi_backend.cast(BLong, pow))
-            return pow_addr, res
-        #
-        libm_name = get_libm_name(sys.platform)
-        log = self.run(main, [libm_name])
-        pow_addr, res = log.result
-        assert res == 8.0 * 300
-        loop, = log.loops_by_filename(self.filepath)
-        if 'ConstClass(pow)' in repr(loop):   # e.g. OS/X
-            pow_addr = 'ConstClass(pow)'
-        assert loop.match_by_id('cfficall', """
-            ...
-            f1 = call_release_gil(..., descr=<Callf 8 ff EF=6 OS=62>)
-            ...
-        """)
-        # so far just check that call_release_gil() is produced.
-        # later, also check that the arguments to call_release_gil()
-        # are constants, and that the numerous raw_mallocs are removed
-
-    def test_cffi_call_guard_not_forced_fails(self):
-        # this is the test_pypy_c equivalent of
-        # rpython/jit/metainterp/test/test_fficall::test_guard_not_forced_fails
-        #
-        # it requires cffi to be installed for pypy in order to run
-        def main():
-            import sys
-            try:
-                import cffi
-            except ImportError:
-                sys.stderr.write('SKIP: cannot import cffi\n')
-                return 0
-                
-            ffi = cffi.FFI()
-
-            ffi.cdef("""
-            typedef void (*functype)(int);
-            int foo(int n, functype func);
-            """)
-
-            lib = ffi.verify("""
-            #include <signal.h>
-            typedef void (*functype)(int);
-
-            int foo(int n, functype func) {
-                if (n >= 2000) {
-                    func(n);
-                }
-                return n*2;
-            }
-            """)
-
-            @ffi.callback("functype")
-            def mycallback(n):
-                if n < 5000:
-                    return
-                # make sure that guard_not_forced fails
-                d = {}
-                f = sys._getframe()
-                while f:
-                    d.update(f.f_locals)
-                    f = f.f_back
-
-            n = 0
-            while n < 10000:
-                res = lib.foo(n, mycallback)  # ID: cfficall
-                # this is the real point of the test: before the
-                # refactor-call_release_gil branch, the assert failed when
-                # res == 5000
-                assert res == n*2
-                n += 1
-            return n
-
-        log = self.run(main, [], import_site=True)
-        assert log.result == 10000
-        loop, = log.loops_by_id('cfficall')
-        assert loop.match_by_id('cfficall', """
-            ...
-            f1 = call_release_gil(..., descr=<Calli 4 ii EF=6 OS=62>)
-            ...
-        """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -0,0 +1,279 @@
+import sys, py
+from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
+
+class Test__ffi(BaseTestPyPyC):
+
+    def test__ffi_call(self):
+        from rpython.rlib.test.test_clibffi import get_libm_name
+        def main(libm_name):
+            try:
+                from _ffi import CDLL, types
+            except ImportError:
+                sys.stderr.write('SKIP: cannot import _ffi\n')
+                return 0
+
+            libm = CDLL(libm_name)
+            pow = libm.getfunc('pow', [types.double, types.double],
+                               types.double)
+            i = 0
+            res = 0
+            while i < 300:
+                tmp = pow(2, 3)   # ID: fficall
+                res += tmp
+                i += 1
+            return pow.getaddr(), res
+        #
+        libm_name = get_libm_name(sys.platform)
+        log = self.run(main, [libm_name])
+        pow_addr, res = log.result
+        assert res == 8.0 * 300
+        py.test.xfail()     # XXX re-optimize _ffi for the JIT?
+        loop, = log.loops_by_filename(self.filepath)
+        if 'ConstClass(pow)' in repr(loop):   # e.g. OS/X
+            pow_addr = 'ConstClass(pow)'
+        assert loop.match_by_id('fficall', """
+            guard_not_invalidated(descr=...)
+            i17 = force_token()
+            setfield_gc(p0, i17, descr=<.* .*PyFrame.vable_token .*>)
+            f21 = call_release_gil(%s, 2.000000, 3.000000, descr=<Callf 8 ff EF=6>)
+            guard_not_forced(descr=...)
+            guard_no_exception(descr=...)
+        """ % pow_addr)
+
+
+    def test__ffi_call_frame_does_not_escape(self):
+        from rpython.rlib.test.test_clibffi import get_libm_name
+        def main(libm_name):
+            try:
+                from _ffi import CDLL, types
+            except ImportError:
+                sys.stderr.write('SKIP: cannot import _ffi\n')
+                return 0
+
+            libm = CDLL(libm_name)
+            pow = libm.getfunc('pow', [types.double, types.double],
+                               types.double)
+
+            def mypow(a, b):
+                return pow(a, b)
+
+            i = 0
+            res = 0
+            while i < 300:
+                tmp = mypow(2, 3)
+                res += tmp
+                i += 1
+            return pow.getaddr(), res
+        #
+        libm_name = get_libm_name(sys.platform)
+        log = self.run(main, [libm_name])
+        pow_addr, res = log.result
+        assert res == 8.0 * 300
+        loop, = log.loops_by_filename(self.filepath)
+        opnames = log.opnames(loop.allops())
+        # we only force the virtualref, not its content
+        assert opnames.count('new_with_vtable') == 1
+
+    def test__ffi_call_releases_gil(self):
+        from rpython.rlib.clibffi import get_libc_name
+        def main(libc_name, n):
+            import time
+            import os
+            from threading import Thread
+            #
+            if os.name == 'nt':
+                from _ffi import WinDLL, types
+                libc = WinDLL('Kernel32.dll')
+                sleep = libc.getfunc('Sleep', [types.uint], types.uint)
+                delays = [0]*n + [1000]
+            else:
+                from _ffi import CDLL, types
+                libc = CDLL(libc_name)
+                sleep = libc.getfunc('sleep', [types.uint], types.uint)
+                delays = [0]*n + [1]
+            #
+            def loop_of_sleeps(i, delays):
+                for delay in delays:
+                    sleep(delay)    # ID: sleep
+            #
+            threads = [Thread(target=loop_of_sleeps, args=[i, delays]) for i in range(5)]
+            start = time.time()
+            for i, thread in enumerate(threads):
+                thread.start()
+            for thread in threads:
+                thread.join()
+            end = time.time()
+            return end - start
+        log = self.run(main, [get_libc_name(), 200], threshold=150,
+                       import_site=True)
+        assert 1 <= log.result <= 1.5 # at most 0.5 seconds of overhead
+        loops = log.loops_by_id('sleep')
+        assert len(loops) == 1 # make sure that we actually JITted the loop
+
+    def test_ctypes_call(self):
+        from rpython.rlib.test.test_clibffi import get_libm_name
+        def main(libm_name):
+            import ctypes
+            libm = ctypes.CDLL(libm_name)
+            fabs = libm.fabs
+            fabs.argtypes = [ctypes.c_double]
+            fabs.restype = ctypes.c_double
+            x = -4
+            i = 0
+            while i < 300:
+                x = fabs(x)
+                x = x - 100
+                i += 1
+            return fabs._ptr.getaddr(), x
+
+        libm_name = get_libm_name(sys.platform)
+        log = self.run(main, [libm_name], import_site=True)
+        fabs_addr, res = log.result
+        assert res == -4.0
+        loop, = log.loops_by_filename(self.filepath)
+        ops = loop.allops()
+        opnames = log.opnames(ops)
+        assert opnames.count('new_with_vtable') == 1 # only the virtualref
+        py.test.xfail()     # XXX re-optimize _ffi for the JIT?
+        assert opnames.count('call_release_gil') == 1
+        idx = opnames.index('call_release_gil')
+        call = ops[idx]
+        assert (call.args[0] == 'ConstClass(fabs)' or    # e.g. OS/X
+                int(call.args[0]) == fabs_addr)
+
+
+    def test__ffi_struct(self):
+        def main():
+            from _ffi import _StructDescr, Field, types
+            fields = [
+                Field('x', types.slong),
+                ]
+            descr = _StructDescr('foo', fields)
+            struct = descr.allocate()
+            i = 0
+            while i < 300:
+                x = struct.getfield('x')   # ID: getfield
+                x = x+1
+                struct.setfield('x', x)    # ID: setfield
+                i += 1
+            return struct.getfield('x')
+        #
+        log = self.run(main, [])
+        py.test.xfail()     # XXX re-optimize _ffi for the JIT?
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match_by_id('getfield', """
+            guard_not_invalidated(descr=...)
+            i57 = getfield_raw(i46, descr=<FieldS dynamic 0>)
+        """)
+        assert loop.match_by_id('setfield', """
+            setfield_raw(i44, i57, descr=<FieldS dynamic 0>)
+        """)
+
+
+    def test__cffi_call(self):
+        from rpython.rlib.test.test_clibffi import get_libm_name
+        def main(libm_name):
+            try:
+                import _cffi_backend
+            except ImportError:
+                sys.stderr.write('SKIP: cannot import _cffi_backend\n')
+                return 0
+
+            libm = _cffi_backend.load_library(libm_name)
+            BDouble = _cffi_backend.new_primitive_type("double")
+            BInt = _cffi_backend.new_primitive_type("int")
+            BPow = _cffi_backend.new_function_type([BDouble, BInt], BDouble)
+            ldexp = libm.load_function(BPow, 'ldexp')
+            i = 0
+            res = 0
+            while i < 300:
+                tmp = ldexp(1, 3)   # ID: cfficall
+                res += tmp
+                i += 1
+            BLong = _cffi_backend.new_primitive_type("long")
+            ldexp_addr = int(_cffi_backend.cast(BLong, ldexp))
+            return ldexp_addr, res
+        #
+        libm_name = get_libm_name(sys.platform)
+        log = self.run(main, [libm_name])
+        ldexp_addr, res = log.result
+        assert res == 8.0 * 300
+        loop, = log.loops_by_filename(self.filepath)
+        if 'ConstClass(ldexp)' in repr(loop):   # e.g. OS/X
+            ldexp_addr = 'ConstClass(ldexp)'
+        assert loop.match_by_id('cfficall', """
+            ...
+            f1 = call_release_gil(..., descr=<Callf 8 fi EF=6 OS=62>)
+            ...
+        """)
+        ops = loop.ops_by_id('cfficall')
+        assert 'raw_malloc' not in str(ops)
+        assert 'raw_free' not in str(ops)
+        assert 'getarrayitem_raw' not in log.opnames(ops)
+        assert 'setarrayitem_raw' not in log.opnames(ops)
+        # so far just check that call_release_gil() is produced.
+        # later, also check that the arguments to call_release_gil()
+        # are constants
+        # are constants, and that the numerous raw_mallocs are removed
+
+    def test_cffi_call_guard_not_forced_fails(self):
+        # this is the test_pypy_c equivalent of
+        # rpython/jit/metainterp/test/test_fficall::test_guard_not_forced_fails
+        #
+        # it requires cffi to be installed for pypy in order to run
+        def main():
+            import sys
+            try:
+                import cffi
+            except ImportError:
+                sys.stderr.write('SKIP: cannot import cffi\n')
+                return 0
+                
+            ffi = cffi.FFI()
+
+            ffi.cdef("""
+            typedef void (*functype)(int);
+            int foo(int n, functype func);
+            """)
+
+            lib = ffi.verify("""
+            #include <signal.h>
+            typedef void (*functype)(int);
+
+            int foo(int n, functype func) {
+                if (n >= 2000) {
+                    func(n);
+                }
+                return n*2;
+            }
+            """)
+
+            @ffi.callback("functype")
+            def mycallback(n):
+                if n < 5000:
+                    return
+                # make sure that guard_not_forced fails
+                d = {}
+                f = sys._getframe()
+                while f:
+                    d.update(f.f_locals)
+                    f = f.f_back
+
+            n = 0
+            while n < 10000:
+                res = lib.foo(n, mycallback)  # ID: cfficall
+                # this is the real point of the test: before the
+                # refactor-call_release_gil branch, the assert failed when
+                # res == 5000
+                assert res == n*2
+                n += 1
+            return n
+
+        log = self.run(main, [], import_site=True)
+        assert log.result == 10000
+        loop, = log.loops_by_id('cfficall')
+        assert loop.match_by_id('cfficall', """
+            ...
+            f1 = call_release_gil(..., descr=<Calli 4 ii EF=6 OS=62>)
+            ...
+        """)
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
@@ -484,6 +484,15 @@
         else:
             return self.bh_raw_load_i(struct, offset, descr)
 
+    def unpack_arraydescr_size(self, arraydescr):
+        from rpython.jit.backend.llsupport.symbolic import get_array_token
+        from rpython.jit.backend.llsupport.descr import get_type_flag, FLAG_SIGNED
+        assert isinstance(arraydescr, ArrayDescr)
+        basesize, itemsize, _ = get_array_token(arraydescr.A, False)
+        flag = get_type_flag(arraydescr.A.OF)
+        is_signed = (flag == FLAG_SIGNED)
+        return basesize, itemsize, is_signed
+
     def bh_raw_store_i(self, struct, offset, newvalue, descr):
         ll_p = rffi.cast(rffi.CCHARP, struct)
         ll_p = rffi.cast(lltype.Ptr(descr.A), rffi.ptradd(ll_p, offset))
@@ -566,10 +575,14 @@
     def bh_read_timestamp(self):
         return read_timestamp()
 
+    def bh_new_raw_buffer(self, size):
+        return lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
+
     def store_fail_descr(self, deadframe, descr):
         pass # I *think*
 
 
+
 class LLDeadFrame(object):
     _TYPE = llmemory.GCREF
 
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
@@ -742,6 +742,9 @@
             as_array[self.vtable_offset/WORD] = vtable
         return res
 
+    def bh_new_raw_buffer(self, size):
+        return lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
+
     def bh_classof(self, struct):
         struct = lltype.cast_opaque_ptr(rclass.OBJECTPTR, struct)
         result_adr = llmemory.cast_ptr_to_adr(struct.typeptr)
diff --git a/rpython/jit/backend/llsupport/test/zrpy_gc_boehm_test.py b/rpython/jit/backend/llsupport/test/zrpy_gc_boehm_test.py
--- a/rpython/jit/backend/llsupport/test/zrpy_gc_boehm_test.py
+++ b/rpython/jit/backend/llsupport/test/zrpy_gc_boehm_test.py
@@ -2,6 +2,7 @@
 import weakref
 from rpython.rlib.jit import JitDriver, dont_look_inside
 from rpython.jit.backend.llsupport.test.zrpy_gc_test import run, get_entry, compile
+from rpython.jit.backend.llsupport.test.ztranslation_test import fix_annotator_for_vrawbuffer
 
 class X(object):
     def __init__(self, x=0):
@@ -31,7 +32,8 @@
     g._dont_inline_ = True
     return g
 
-def compile_boehm_test():
+def compile_boehm_test(monkeypatch):
+    fix_annotator_for_vrawbuffer(monkeypatch)
     myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
     @dont_look_inside
     def see(lst, n):
diff --git a/rpython/jit/backend/llsupport/test/ztranslation_test.py b/rpython/jit/backend/llsupport/test/ztranslation_test.py
--- a/rpython/jit/backend/llsupport/test/ztranslation_test.py
+++ b/rpython/jit/backend/llsupport/test/ztranslation_test.py
@@ -9,10 +9,23 @@
 from rpython.jit.codewriter.policy import StopAtXPolicy
 
 
+def fix_annotator_for_vrawbuffer(monkeypatch):
+    from rpython.rlib.nonconst import NonConstant
+    from rpython.jit.metainterp.optimizeopt.virtualize import VRawBufferValue
+    from rpython.jit.metainterp import warmspot
+
+    def my_hook_for_tests(cpu):
+        # this is needed so that the annotator can see it
+        if NonConstant(False):
+            v = VRawBufferValue(cpu, None, -1, None, None)
+    monkeypatch.setattr(warmspot, 'hook_for_tests', my_hook_for_tests)
+
+
 class TranslationTest(CCompiledMixin):
     CPUClass = getcpuclass()
 
-    def test_stuff_translates(self):
+    def test_stuff_translates(self, monkeypatch):
+        fix_annotator_for_vrawbuffer(monkeypatch)
         # this is a basic test that tries to hit a number of features and their
         # translation:
         # - jitting of loops and bridges
@@ -89,9 +102,10 @@
 class TranslationTestCallAssembler(CCompiledMixin):
     CPUClass = getcpuclass()
 
-    def test_direct_assembler_call_translates(self):
+    def test_direct_assembler_call_translates(self, monkeypatch):
         """Test CALL_ASSEMBLER and the recursion limit"""
         from rpython.rlib.rstackovf import StackOverflow
+        fix_annotator_for_vrawbuffer(monkeypatch)
 
         class Thing(object):
             def __init__(self, val):
@@ -169,7 +183,8 @@
 class TranslationTestJITStats(CCompiledMixin):
     CPUClass = getcpuclass()
 
-    def test_jit_get_stats(self):
+    def test_jit_get_stats(self, monkeypatch):
+        fix_annotator_for_vrawbuffer(monkeypatch)
         driver = JitDriver(greens = [], reds = ['i'])
 
         def f():
@@ -192,7 +207,8 @@
 class TranslationRemoveTypePtrTest(CCompiledMixin):
     CPUClass = getcpuclass()
 
-    def test_external_exception_handling_translates(self):
+    def test_external_exception_handling_translates(self, monkeypatch):
+        fix_annotator_for_vrawbuffer(monkeypatch)
         jitdriver = JitDriver(greens = [], reds = ['n', 'total'])
 
         class ImDone(Exception):
diff --git a/rpython/jit/backend/model.py b/rpython/jit/backend/model.py
--- a/rpython/jit/backend/model.py
+++ b/rpython/jit/backend/model.py
@@ -194,11 +194,18 @@
     def typedescrof(self, TYPE):
         raise NotImplementedError
 
+    def unpack_arraydescr_size(self, arraydescr):
+        """
+        Return basesize, itemsize, is_signed
+        """
+        raise NotImplementedError
+
     @staticmethod
     def cast_int_to_ptr(x, TYPE):
         x = llmemory.cast_int_to_adr(x)
         return llmemory.cast_adr_to_ptr(x, TYPE)
 
+
     # ---------- the backend-dependent operations ----------
 
     # lltype specific operations
@@ -235,6 +242,8 @@
         raise NotImplementedError
     def bh_newunicode(self, length):
         raise NotImplementedError
+    def bh_new_raw_buffer(self, size):
+        raise NotImplementedError
 
     def bh_arraylen_gc(self, array, arraydescr):
         raise NotImplementedError
diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -76,14 +76,14 @@
     #
     OS_MATH_SQRT                = 100
     #
-    OS_RAW_MALLOC_VARSIZE       = 110
+    OS_RAW_MALLOC_VARSIZE_CHAR  = 110
     OS_RAW_FREE                 = 111
 
     OS_JIT_FORCE_VIRTUAL        = 120
 
     # for debugging:
     _OS_CANRAISE = set([OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL,
-                        OS_RAW_MALLOC_VARSIZE, OS_JIT_FORCE_VIRTUAL])
+                        OS_RAW_MALLOC_VARSIZE_CHAR, OS_JIT_FORCE_VIRTUAL])
 
     def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays,
                 write_descrs_fields, write_descrs_arrays,
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -539,9 +539,11 @@
             name += '_no_track_allocation'
         op1 = self.prepare_builtin_call(op, name, args, (TYPE,), TYPE)
         if name == 'raw_malloc_varsize':
-            return self._handle_oopspec_call(op1, args,
-                                             EffectInfo.OS_RAW_MALLOC_VARSIZE,
-                                             EffectInfo.EF_CAN_RAISE)
+            ITEMTYPE = op.args[0].value.OF
+            if ITEMTYPE == lltype.Char:
+                return self._handle_oopspec_call(op1, args,
+                                                 EffectInfo.OS_RAW_MALLOC_VARSIZE_CHAR,
+                                                 EffectInfo.EF_CAN_RAISE)
         return self.rewrite_op_direct_call(op1)
 
     def rewrite_op_malloc_varsize(self, op):
diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -126,7 +126,7 @@
             INT = lltype.Signed
             UNICHAR = lltype.UniChar
             FLOAT = lltype.Float
-            ARRAYPTR = rffi.CArrayPtr(lltype.Signed)
+            ARRAYPTR = rffi.CArrayPtr(lltype.Char)
             argtypes = {
              EI.OS_MATH_SQRT:  ([FLOAT], FLOAT),
              EI.OS_STR2UNICODE:([PSTR], PUNICODE),
@@ -143,7 +143,7 @@
              EI.OS_UNIEQ_NONNULL_CHAR:   ([PUNICODE, UNICHAR], INT),
              EI.OS_UNIEQ_CHECKNULL_CHAR: ([PUNICODE, UNICHAR], INT),
              EI.OS_UNIEQ_LENGTHOK:       ([PUNICODE, PUNICODE], INT),
-             EI.OS_RAW_MALLOC_VARSIZE:   ([INT], ARRAYPTR),
+             EI.OS_RAW_MALLOC_VARSIZE_CHAR: ([INT], ARRAYPTR),
              EI.OS_RAW_FREE:             ([ARRAYPTR], lltype.Void),
             }
             argtypes = argtypes[oopspecindex]
@@ -151,7 +151,7 @@
             assert argtypes[1] == op.result.concretetype
             if oopspecindex == EI.OS_STR2UNICODE:
                 assert extraeffect == EI.EF_ELIDABLE_CAN_RAISE
-            elif oopspecindex == EI.OS_RAW_MALLOC_VARSIZE:
+            elif oopspecindex == EI.OS_RAW_MALLOC_VARSIZE_CHAR:
                 assert extraeffect == EI.EF_CAN_RAISE
             elif oopspecindex == EI.OS_RAW_FREE:
                 assert extraeffect == EI.EF_CANNOT_RAISE
@@ -161,7 +161,7 @@
 
     def calldescr_canraise(self, calldescr):
         EI = effectinfo.EffectInfo
-        if calldescr == 'calldescr-%d' % EI.OS_RAW_MALLOC_VARSIZE:
+        if calldescr == 'calldescr-%d' % EI.OS_RAW_MALLOC_VARSIZE_CHAR:
             return True
         return False
 
@@ -555,7 +555,7 @@
     assert op1.args == []
 
 def test_raw_malloc():
-    S = rffi.CArray(lltype.Signed)
+    S = rffi.CArray(lltype.Char)
     v1 = varoftype(lltype.Signed)
     v = varoftype(lltype.Ptr(S))
     flags = Constant({'flavor': 'raw'}, lltype.Void)
@@ -566,7 +566,7 @@
     assert op0.opname == 'residual_call_ir_i'
     assert op0.args[0].value == 'raw_malloc_varsize' # pseudo-function as a str
     assert (op0.args[-1] == 'calldescr-%d' %
-            effectinfo.EffectInfo.OS_RAW_MALLOC_VARSIZE)
+            effectinfo.EffectInfo.OS_RAW_MALLOC_VARSIZE_CHAR)
 
     assert op1.opname == '-live-'
     assert op1.args == []
@@ -608,7 +608,7 @@
     assert op1.args == []
 
 def test_raw_free():
-    S = rffi.CArray(lltype.Signed)
+    S = rffi.CArray(lltype.Char)
     flags = Constant({'flavor': 'raw', 'track_allocation': True},
                      lltype.Void)
     op = SpaceOperation('free', [varoftype(lltype.Ptr(S)), flags],
diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -15,7 +15,7 @@
 from rpython.jit.metainterp import history, resume
 from rpython.jit.metainterp.optimize import InvalidLoop
 from rpython.jit.metainterp.inliner import Inliner
-from rpython.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP
+from rpython.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP, ResumeDataDirectReader
 from rpython.jit.codewriter import heaptracker, longlong
 
 def giveup():
@@ -656,9 +656,9 @@
 
 class AllVirtuals:
     llopaque = True
-    list = [resume.ResumeDataDirectReader.virtual_default]   # annotation hack
-    def __init__(self, list):
-        self.list = list
+    cache = None
+    def __init__(self, cache):
+        self.cache = cache
     def hide(self, cpu):
         ptr = cpu.ts.cast_instance_to_base_ref(self)
         return cpu.ts.cast_to_ref(ptr)
@@ -682,9 +682,9 @@
         from rpython.jit.metainterp.blackhole import resume_in_blackhole
         hidden_all_virtuals = metainterp_sd.cpu.get_savedata_ref(deadframe)
         obj = AllVirtuals.show(metainterp_sd.cpu, hidden_all_virtuals)
-        all_virtuals = obj.list
+        all_virtuals = obj.cache
         if all_virtuals is None:
-            all_virtuals = []
+            all_virtuals = ResumeDataDirectReader.VirtualCache([], [])
         assert jitdriver_sd is self.jitdriver_sd
         resume_in_blackhole(metainterp_sd, jitdriver_sd, self, deadframe,
                             all_virtuals)
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
@@ -191,7 +191,6 @@
     def get_jitcode_for_class(self, oocls):
         return self.jitcodes[oocls]
 
-
 class Const(AbstractValue):
     __slots__ = ()
 
diff --git a/rpython/jit/metainterp/optimizeopt/earlyforce.py b/rpython/jit/metainterp/optimizeopt/earlyforce.py
--- a/rpython/jit/metainterp/optimizeopt/earlyforce.py
+++ b/rpython/jit/metainterp/optimizeopt/earlyforce.py
@@ -1,15 +1,26 @@
+from rpython.jit.codewriter.effectinfo import EffectInfo
 from rpython.jit.metainterp.optimizeopt.optimizer import Optimization
 from rpython.jit.metainterp.optimizeopt.vstring import VAbstractStringValue
 from rpython.jit.metainterp.resoperation import rop, ResOperation
 
+def is_raw_free(op, opnum):
+    if opnum != rop.CALL:
+        return False
+    einfo = op.getdescr().get_extra_info()
+    return einfo.oopspecindex == EffectInfo.OS_RAW_FREE
+
+
 class OptEarlyForce(Optimization):
     def propagate_forward(self, op):
         opnum = op.getopnum()
+
         if (opnum != rop.SETFIELD_GC and 
             opnum != rop.SETARRAYITEM_GC and
+            opnum != rop.SETARRAYITEM_RAW and
             opnum != rop.QUASIIMMUT_FIELD and
             opnum != rop.SAME_AS and
-            opnum != rop.MARK_OPAQUE_PTR):
+            opnum != rop.MARK_OPAQUE_PTR and
+            not is_raw_free(op, opnum)):
                
             for arg in op.getarglist():
                 if arg in self.optimizer.values:
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
@@ -231,6 +231,12 @@
     def setitem(self, index, value):
         raise NotImplementedError
 
+    def getitem_raw(self, offset, length, descr):
+        raise NotImplementedError
+
+    def setitem_raw(self, offset, length, descr, value):
+        raise NotImplementedError
+
     def getinteriorfield(self, index, ofs, default):
         raise NotImplementedError
 
diff --git a/rpython/jit/metainterp/optimizeopt/rawbuffer.py b/rpython/jit/metainterp/optimizeopt/rawbuffer.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/metainterp/optimizeopt/rawbuffer.py
@@ -0,0 +1,134 @@
+from rpython.rlib.debug import debug_start, debug_stop, debug_print
+from rpython.rlib.objectmodel import compute_unique_id, we_are_translated
+
+class InvalidRawOperation(Exception):
+    pass
+
+class InvalidRawWrite(InvalidRawOperation):
+    pass
+
+class InvalidRawRead(InvalidRawOperation):
+    pass
+
+class RawBuffer(object):
+    def __init__(self, cpu, logops=None):
+        # the following lists represents the writes in the buffer: values[i]
+        # is the value of length lengths[i] stored at offset[i].
+        #
+        # the invariant is that they are ordered by offset, and that
+        # offset[i]+length[i] <= offset[i+1], i.e. that the writes never
+        # overlaps
+        self.cpu = cpu
+        self.logops = logops
+        self.offsets = []
+        self.lengths = []
+        self.descrs = []
+        self.values = []
+
+    def _get_memory(self):
+        """
+        NOT_RPYTHON
+        for testing only
+        """
+        return zip(self.offsets, self.lengths, self.descrs, self.values)
+
+    def _repr_of_descr(self, descr):
+        if self.logops:
+            s = self.logops.repr_of_descr(descr)
+        else:
+            s = str(descr)
+        s += " at %d" % compute_unique_id(descr)
+        return s
+
+    def _repr_of_value(self, value):
+        if not we_are_translated() and isinstance(value, str):
+            return value # for tests
+        if self.logops:
+            s = self.logops.repr_of_arg(value.box)
+        else:
+            s = str(value.box)
+        s += " at %d" % compute_unique_id(value.box)
+        return s
+
+    def _dump_to_log(self):
+        debug_print("RawBuffer state")
+        debug_print("offset, length, descr, box")
+        debug_print("(box == None means that the value is still virtual)")
+        for i in range(len(self.offsets)):
+            descr = self._repr_of_descr(self.descrs[i])
+            box = self._repr_of_value(self.values[i])
+            debug_print("%d, %d, %s, %s" % (self.offsets[i], self.lengths[i], descr, box))
+
+    def _invalid_write(self, message, offset, length, descr, value):
+        debug_start('jit-log-rawbuffer')
+        debug_print('Invalid write: %s' % message)
+        debug_print("  offset: %d" % offset)
+        debug_print("  length: %d" % length)
+        debug_print("  descr:  %s" % self._repr_of_descr(descr))
+        debug_print("  value:  %s" % self._repr_of_value(value))
+        self._dump_to_log()
+        debug_stop('jit-log-rawbuffer')
+        raise InvalidRawWrite
+
+    def _invalid_read(self, message, offset, length, descr):
+        debug_start('jit-log-rawbuffer')
+        debug_print('Invalid read: %s' % message)
+        debug_print("  offset: %d" % offset)
+        debug_print("  length: %d" % length)
+        debug_print("  descr:  %s" % self._repr_of_descr(descr))
+        self._dump_to_log()
+        debug_stop('jit-log-rawbuffer')
+        raise InvalidRawRead
+
+    def _descrs_are_compatible(self, d1, d2):
+        # two arraydescrs are compatible if they have the same basesize,
+        # itemsize and sign, even if they are not identical
+        unpack = self.cpu.unpack_arraydescr_size
+        return unpack(d1) == unpack(d2)
+
+    def write_value(self, offset, length, descr, value):
+        i = 0
+        N = len(self.offsets)
+        while i < N:
+            if self.offsets[i] == offset:
+                if (length != self.lengths[i] or not
+                    self._descrs_are_compatible(descr, self.descrs[i])):
+                    # in theory we could add support for the cases in which
+                    # the length or descr is different, but I don't think we
+                    # need it in practice
+                    self._invalid_write('length or descr not compatible',
+                                        offset, length, descr, value)
+                # update the value at this offset
+                self.values[i] = value
+                return
+            elif self.offsets[i] > offset:
+                break
+            i += 1
+        #
+        if i < len(self.offsets) and offset+length > self.offsets[i]:
+            self._invalid_write("overlap with next bytes",
+                                offset, length, descr, value)
+        if i > 0 and self.offsets[i-1]+self.lengths[i-1] > offset:
+            self._invalid_write("overlap with previous bytes",
+                                offset, length, descr, value)
+        # insert a new value at offset
+        self.offsets.insert(i, offset)
+        self.lengths.insert(i, length)
+        self.descrs.insert(i, descr)
+        self.values.insert(i, value)
+
+    def read_value(self, offset, length, descr):
+        i = 0
+        N = len(self.offsets)
+        while i < N:
+            if self.offsets[i] == offset:
+                if (length != self.lengths[i] or
+                    not self._descrs_are_compatible(descr, self.descrs[i])):
+                    self._invalid_read('length or descr not compatible',
+                                       offset, length, descr)
+                return self.values[i]
+            i += 1
+        # memory location not found: this means we are reading from
+        # uninitialized memory, give up the optimization
+        self._invalid_read('uninitialized memory',
+                           offset, length, descr)
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
@@ -770,8 +770,6 @@
         """
         self.optimize_loop(ops, expected)
 
-
-
     def test_p123_simple(self):
         ops = """
         [i1, p2, p3]
@@ -1730,6 +1728,175 @@
         # We cannot track virtuals that survive for more than two iterations.
         self.optimize_loop(ops, expected, preamble)
 
+    def test_virtual_raw_malloc(self):
+        ops = """
+        [i1]
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr)
+        i3 = getarrayitem_raw(i2, 0, descr=rawarraydescr)
+        call('free', i2, descr=raw_free_descr)
+        jump(i3)
+        """
+        expected = """
+        [i1]
+        jump(i1)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_virtual_raw_malloc_force(self):
+        ops = """
+        [i1]
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr_char)
+        setarrayitem_raw(i2, 2, 456, descr=rawarraydescr_char)
+        setarrayitem_raw(i2, 1, 123, descr=rawarraydescr_char)
+        label('foo') # we expect the buffer to be forced *after* the label
+        escape(i2)
+        call('free', i2, descr=raw_free_descr)
+        jump(i1)
+        """
+        expected = """
+        [i1]
+        label('foo')
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr_char)
+        i3 = int_add(i2, 1)
+        setarrayitem_raw(i3, 0, 123, descr=rawarraydescr_char)
+        i4 = int_add(i2, 2)
+        setarrayitem_raw(i4, 0, 456, descr=rawarraydescr_char)
+        escape(i2)
+        call('free', i2, descr=raw_free_descr)
+        jump(i1)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_virtual_raw_malloc_invalid_write_force(self):
+        ops = """
+        [i1]
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr)
+        label('foo') # we expect the buffer to be forced *after* the label
+        setarrayitem_raw(i2, 2, 456, descr=rawarraydescr_char) # overlap!
+        call('free', i2, descr=raw_free_descr)
+        jump(i1)
+        """
+        expected = """
+        [i1]
+        label('foo')
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr)
+        setarrayitem_raw(i2, 2, 456, descr=rawarraydescr_char)
+        call('free', i2, descr=raw_free_descr)
+        jump(i1)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_virtual_raw_malloc_invalid_read_force(self):
+        ops = """
+        [i1]
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr)
+        label('foo') # we expect the buffer to be forced *after* the label
+        i3 = getarrayitem_raw(i2, 0, descr=rawarraydescr_char)
+        call('free', i2, descr=raw_free_descr)
+        jump(i1)
+        """
+        expected = """
+        [i1]
+        label('foo')
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr)
+        i3 = getarrayitem_raw(i2, 0, descr=rawarraydescr_char)
+        call('free', i2, descr=raw_free_descr)
+        jump(i1)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_virtual_raw_slice(self):
+        ops = """
+        [i0, i1]
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i2, 0, 42, descr=rawarraydescr_char)
+        i3 = int_add(i2, 1) # get a slice of the original buffer
+        setarrayitem_raw(i3, 0, 4242, descr=rawarraydescr) # write to the slice
+        i4 = getarrayitem_raw(i2, 0, descr=rawarraydescr_char)
+        i5 = int_add(i2, 1)
+        i6 = getarrayitem_raw(i5, 0, descr=rawarraydescr)
+        call('free', i2, descr=raw_free_descr)
+        jump(i0, i1)
+        """
+        expected = """
+        [i0, i1]
+        jump(i0, i1)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_virtual_raw_slice_of_a_raw_slice(self):
+        ops = """
+        [i0, i1]
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        i3 = int_add(i2, 1) # get a slice of the original buffer
+        i4 = int_add(i3, 1) # get a slice of a slice
+        setarrayitem_raw(i4, 0, i1, descr=rawarraydescr_char) # write to the slice
+        i5 = getarrayitem_raw(i2, 2, descr=rawarraydescr_char)
+        call('free', i2, descr=raw_free_descr)
+        jump(i0, i5)
+        """
+        expected = """
+        [i0, i1]
+        jump(i0, i1)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_virtual_raw_slice_force(self):
+        ops = """
+        [i0, i1]
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i2, 0, 42, descr=rawarraydescr_char)
+        i3 = int_add(i2, 1) # get a slice of the original buffer
+        setarrayitem_raw(i3, 4, 4242, descr=rawarraydescr_char) # write to the slice
+        label('foo')
+        escape(i3)
+        jump(i0, i1)
+        """
+        expected = """
+        [i0, i1]
+        label('foo')
+        # these ops are generated by VirtualRawBufferValue._really_force
+        i2 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i2, 0, 42, descr=rawarraydescr_char)
+        i3 = int_add(i2, 5) # 1+4*sizeof(char)
+        setarrayitem_raw(i3, 0, 4242, descr=rawarraydescr_char)
+        # this is generated by VirtualRawSliceValue._really_force
+        i4 = int_add(i2, 1)
+        escape(i4)
+        jump(i0, i1)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_virtual_raw_malloc_virtualstate(self):
+        ops = """
+        [i0]
+        i1 = getarrayitem_raw(i0, 0, descr=rawarraydescr)
+        i2 = int_add(i1, 1)
+        call('free', i0, descr=raw_free_descr)
+        i3 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i3, 0, i2, descr=rawarraydescr)
+        label('foo')
+        jump(i3)
+        """
+        expected = """
+        [i0]
+        i1 = getarrayitem_raw(i0, 0, descr=rawarraydescr)
+        i2 = int_add(i1, 1)
+        call('free', i0, descr=raw_free_descr)
+        label('foo')
+        i3 = call('malloc', 10, descr=raw_malloc_descr)
+        setarrayitem_raw(i3, 0, i2, descr=rawarraydescr)
+        jump(i3)
+        """
+        self.optimize_loop(ops, expected)
+
     def test_duplicate_getfield_1(self):
         ops = """
         [p1, p2]
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_rawbuffer.py b/rpython/jit/metainterp/optimizeopt/test/test_rawbuffer.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/metainterp/optimizeopt/test/test_rawbuffer.py
@@ -0,0 +1,90 @@
+import py
+from rpython.jit.metainterp.optimizeopt.rawbuffer import (InvalidRawWrite,
+                                                          InvalidRawRead, RawBuffer)
+
+class FakeCPU(object):
+    def unpack_arraydescr_size(self, descr):
+        return descr, 'foo', 'bar'
+
+def test_write_value():
+    buf = RawBuffer(FakeCPU())
+    buf.write_value(8, 4, 'descr3', 'three')
+    buf.write_value(0, 4, 'descr1', 'one')
+    buf.write_value(4, 2, 'descr2', 'two')
+    buf.write_value(12, 2, 'descr4', 'four')
+    assert buf._get_memory() == [
+        ( 0, 4, 'descr1', 'one'),
+        ( 4, 2, 'descr2', 'two'),
+        ( 8, 4, 'descr3', 'three'),
+        (12, 2, 'descr4', 'four'),
+        ]
+    #
+
+def test_write_value_update():
+    buf = RawBuffer(FakeCPU())
+    buf.write_value(0, 4, 'descr', 'one')
+    buf.write_value(4, 2, 'descr', 'two')
+    buf.write_value(0, 4, 'descr', 'ONE')
+    assert buf._get_memory() == [
+        ( 0, 4, 'descr', 'ONE'),
+        ( 4, 2, 'descr', 'two'),
+        ]
+
+def test_write_value_invalid_length():
+    buf = RawBuffer(FakeCPU())
+    buf.write_value(0, 4, 'descr1', 'one')
+    with py.test.raises(InvalidRawWrite):
+        buf.write_value(0, 5, 'descr1', 'two')
+    with py.test.raises(InvalidRawWrite):
+        buf.write_value(0, 4, 'descr2', 'two')
+
+    
+def test_write_value_overlapping_next():
+    buf = RawBuffer(FakeCPU())
+    buf.write_value(0, 4, 'descr', 'one')
+    buf.write_value(6, 4, 'descr', 'two')
+    with py.test.raises(InvalidRawWrite):
+        buf.write_value(4, 4, 'descr', 'three')
+
+def test_write_value_overlapping_prev():
+    buf = RawBuffer(FakeCPU())
+    buf.write_value(0, 4, 'descr', 'one')
+    with py.test.raises(InvalidRawWrite):
+        buf.write_value(2, 1, 'descr', 'two')
+
+def test_read_value():
+    buf = RawBuffer(FakeCPU())
+    buf.write_value(0, 4, 'descr', 'one')
+    buf.write_value(4, 4, 'descr', 'two')
+    assert buf.read_value(0, 4, 'descr') == 'one'
+    assert buf.read_value(4, 4, 'descr') == 'two'
+    with py.test.raises(InvalidRawRead):
+        buf.read_value(0, 2, 'descr')
+    with py.test.raises(InvalidRawRead):
+        buf.read_value(8, 2, 'descr')
+    with py.test.raises(InvalidRawRead):
+        buf.read_value(0, 4, 'another descr')
+
+def test_unpack_descrs():
+    ArrayS_8_1 = object()
+    ArrayS_8_2 = object()
+    ArrayU_8 = object()
+
+    class FakeCPU(object):
+        def unpack_arraydescr_size(self, descr):
+            if descr in (ArrayS_8_1, ArrayS_8_2):
+                return 0, 8, True
+            return 0, 8, False
+
+    buf = RawBuffer(FakeCPU())
+    buf.write_value(0, 4, ArrayS_8_1, 'one')
+    assert buf.read_value(0, 4, ArrayS_8_1) == 'one'
+    assert buf.read_value(0, 4, ArrayS_8_2) == 'one' # with a non-identical descr
+    #
+    buf.write_value(0, 4, ArrayS_8_2, 'two') # with a non-identical descr
+    assert buf.read_value(0, 4, ArrayS_8_1) == 'two'
+    #
+    with py.test.raises(InvalidRawRead):
+        buf.read_value(0, 4, ArrayU_8)
+    with py.test.raises(InvalidRawWrite):
+        buf.write_value(0, 4, ArrayU_8, 'three')
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
@@ -196,6 +196,15 @@
                         EffectInfo.EF_CANNOT_RAISE,
                         oopspecindex=EffectInfo.OS_ARRAYCOPY))
 
+    raw_malloc_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+             EffectInfo([], [], [], [],
+                        EffectInfo.EF_CAN_RAISE,
+                        oopspecindex=EffectInfo.OS_RAW_MALLOC_VARSIZE_CHAR))
+    raw_free_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+             EffectInfo([], [], [], [],
+                        EffectInfo.EF_CANNOT_RAISE,
+                        oopspecindex=EffectInfo.OS_RAW_FREE))
+
 
     # array of structs (complex data)
     complexarray = lltype.GcArray(
@@ -208,6 +217,12 @@
     complexrealdescr = cpu.interiorfielddescrof(complexarray, "real")
     compleximagdescr = cpu.interiorfielddescrof(complexarray, "imag")
 
+    rawarraydescr = cpu.arraydescrof(lltype.Array(lltype.Signed,
+                                                  hints={'nolength': True}))
+    rawarraydescr_char = cpu.arraydescrof(lltype.Array(lltype.Char,
+                                                       hints={'nolength': True}))
+
+
     for _name, _os in [
         ('strconcatdescr',               'OS_STR_CONCAT'),
         ('strslicedescr',                'OS_STR_SLICE'),
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
@@ -6,7 +6,9 @@
 from rpython.jit.metainterp.optimizeopt import optimizer
 from rpython.jit.metainterp.optimizeopt.optimizer import OptValue, REMOVED
 from rpython.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
-    descrlist_dict, sort_descrs)
+                                                     descrlist_dict, sort_descrs)
+
+from rpython.jit.metainterp.optimizeopt.rawbuffer import RawBuffer, InvalidRawOperation
 from rpython.jit.metainterp.resoperation import rop, ResOperation
 from rpython.rlib.objectmodel import we_are_translated
 
@@ -236,8 +238,36 @@
     def _get_descr(self):
         return self.structdescr
 
+class AbstractVArrayValue(AbstractVirtualValue):
+    """
+    Base class for VArrayValue (for normal GC arrays) and VRawBufferValue (for
+    malloc()ed memory)
+    """
 
-class VArrayValue(AbstractVirtualValue):
+    def getlength(self):
+        return len(self._items)
+
+    def get_item_value(self, i):
+        raise NotImplementedError
+
+    def set_item_value(self, i, newval):
+        raise NotImplementedError
+
+    def get_args_for_fail(self, modifier):
+        if self.box is None and not modifier.already_seen_virtual(self.keybox):
+            # checks for recursion: it is False unless
+            # we have already seen the very same keybox
+            itemboxes = []
+            for i in range(self.getlength()):
+                itemvalue = self.get_item_value(i)
+                itemboxes.append(itemvalue.get_key_box())
+            modifier.register_virtual_fields(self.keybox, itemboxes)
+            for i in range(self.getlength()):
+                itemvalue = self.get_item_value(i)
+                itemvalue.get_args_for_fail(modifier)
+
+
+class VArrayValue(AbstractVArrayValue):
 
     def __init__(self, arraydescr, constvalue, size, keybox, source_op=None):
         AbstractVirtualValue.__init__(self, keybox, source_op)
@@ -248,6 +278,12 @@
     def getlength(self):
         return len(self._items)
 
+    def get_item_value(self, i):
+        return self._items[i]
+
+    def set_item_value(self, i, newval):
+        self._items[i] = newval
+
     def getitem(self, index):
         res = self._items[index]
         return res
@@ -257,11 +293,16 @@
         self._items[index] = itemvalue
 
     def force_at_end_of_preamble(self, already_forced, optforce):
+        # note that this method is on VArrayValue instead of
+        # AbstractVArrayValue because we do not want to support virtualstate
+        # for rawbuffers for now
         if self in already_forced:
             return self
         already_forced[self] = self
-        for index in range(len(self._items)):
-            self._items[index] = self._items[index].force_at_end_of_preamble(already_forced, optforce)
+        for index in range(self.getlength()):
+            itemval = self.get_item_value(index)
+            itemval = itemval.force_at_end_of_preamble(already_forced, optforce)
+            self.set_item_value(index, itemval)
         return self
 
     def _really_force(self, optforce):
@@ -281,29 +322,16 @@
                                   descr=self.arraydescr)
                 optforce.emit_operation(op)
 
-    def get_args_for_fail(self, modifier):
-        if self.box is None and not modifier.already_seen_virtual(self.keybox):
-            # checks for recursion: it is False unless
-            # we have already seen the very same keybox
-            itemboxes = []
-            for itemvalue in self._items:
-                itemboxes.append(itemvalue.get_key_box())
-            modifier.register_virtual_fields(self.keybox, itemboxes)
-            for itemvalue in self._items:
-                itemvalue.get_args_for_fail(modifier)
-
     def _make_virtual(self, modifier):
         return modifier.make_varray(self.arraydescr)
 
+
 class VArrayStructValue(AbstractVirtualValue):
     def __init__(self, arraydescr, size, keybox, source_op=None):
         AbstractVirtualValue.__init__(self, keybox, source_op)
         self.arraydescr = arraydescr
         self._items = [{} for _ in xrange(size)]
 
-    def getlength(self):
-        return len(self._items)
-
     def getinteriorfield(self, index, ofs, default):
         return self._items[index].get(ofs, default)
 
@@ -363,6 +391,90 @@
         return modifier.make_varraystruct(self.arraydescr, self._get_list_of_descrs())
 
 
+class VRawBufferValue(AbstractVArrayValue):
+
+    def __init__(self, cpu, logops, size, keybox, source_op):
+        AbstractVirtualValue.__init__(self, keybox, source_op)
+        # note that size is unused, because we assume that the buffer is big
+        # enough to write/read everything we need. If it's not, it's undefined
+        # behavior anyway, although in theory we could probably detect such
+        # cases here
+        self.size = size
+        self.buffer = RawBuffer(cpu, logops)
+
+    def getlength(self):
+        return len(self.buffer.values)
+
+    def get_item_value(self, i):
+        return self.buffer.values[i]
+
+    def set_item_value(self, i, newval):
+        self.buffer.values[i] = newval
+
+    def getitem_raw(self, offset, length, descr):
+        return self.buffer.read_value(offset, length, descr)
+
+    def setitem_raw(self, offset, length, descr, value):
+        self.buffer.write_value(offset, length, descr, value)
+
+    def _really_force(self, optforce):
+        op = self.source_op
+        assert op is not None
+        if not we_are_translated():
+            op.name = 'FORCE ' + self.source_op.name
+        optforce.emit_operation(self.source_op)
+        self.box = box = self.source_op.result
+        for i in range(len(self.buffer.offsets)):
+            # get a pointer to self.box+offset
+            offset = self.buffer.offsets[i]
+            if offset == 0:
+                arraybox = self.box
+            else:
+                arraybox = BoxInt()
+                op = ResOperation(rop.INT_ADD,
+                                  [self.box, ConstInt(offset)], arraybox)
+                optforce.emit_operation(op)
+            #
+            # write the value
+            descr = self.buffer.descrs[i]
+            itemvalue = self.buffer.values[i]
+            itembox = itemvalue.force_box(optforce)
+            op = ResOperation(rop.SETARRAYITEM_RAW,
+                              [arraybox, ConstInt(0), itembox], None,
+                              descr=descr)
+            optforce.emit_operation(op)
+
+    def _make_virtual(self, modifier):
+        # I *think* we need to make a copy of offsets and descrs because we
+        # want a snapshot of the virtual state right now: if we grow more
+        # elements later, we don't want them to go in this virtual state
+        return modifier.make_vrawbuffer(self.size,
+                                        self.buffer.offsets[:],
+                                        self.buffer.descrs[:])
+
+
+class VRawSliceValue(AbstractVirtualValue):
+
+    def __init__(self, rawbuffer_value, offset, keybox, source_op):
+        AbstractVirtualValue.__init__(self, keybox, source_op)
+        self.rawbuffer_value = rawbuffer_value
+        self.offset = offset
+
+    def _really_force(self, optforce):
+        op = self.source_op
+        assert op is not None
+        if not we_are_translated():
+            op.name = 'FORCE ' + self.source_op.name
+        self.box = self.source_op.result
+        self.rawbuffer_value.force_box(optforce)
+        optforce.emit_operation(op)
+
+    def setitem_raw(self, offset, length, descr, value):
+        self.rawbuffer_value.setitem_raw(self.offset+offset, length, descr, value)
+
+    def getitem_raw(self, offset, length, descr):
+        return self.rawbuffer_value.getitem_raw(self.offset+offset, length, descr)
+
 class OptVirtualize(optimizer.Optimization):
     "Virtualize objects until they escape."
 
@@ -388,6 +500,17 @@
         self.make_equal_to(box, vvalue)
         return vvalue
 
+    def make_virtual_raw_memory(self, size, box, source_op):
+        logops = self.optimizer.loop.logops
+        vvalue = VRawBufferValue(self.optimizer.cpu, logops, size, box, source_op)
+        self.make_equal_to(box, vvalue)
+        return vvalue
+
+    def make_virtual_raw_slice(self, rawbuffer_value, offset, box, source_op):
+        vvalue = VRawSliceValue(rawbuffer_value, offset, box, source_op)
+        self.make_equal_to(box, vvalue)
+        return vvalue
+
     def optimize_GUARD_NO_EXCEPTION(self, op):
         if self.last_emitted_operation is REMOVED:
             return
@@ -524,6 +647,43 @@
             self.getvalue(op.result).ensure_nonnull()
             self.emit_operation(op)
 
+    def optimize_CALL(self, op):
+        effectinfo = op.getdescr().get_extra_info()
+        if effectinfo.oopspecindex == EffectInfo.OS_RAW_MALLOC_VARSIZE_CHAR:
+            self.do_RAW_MALLOC_VARSIZE_CHAR(op)
+        elif effectinfo.oopspecindex == EffectInfo.OS_RAW_FREE:
+            self.do_RAW_FREE(op)
+        else:
+            self.emit_operation(op)
+
+    def do_RAW_MALLOC_VARSIZE_CHAR(self, op):
+        sizebox = op.getarg(1)
+        if not isinstance(sizebox, ConstInt):
+            self.emit_operation(op)
+            return
+        size = sizebox.value
+        self.make_virtual_raw_memory(size, op.result, op)
+
+    def do_RAW_FREE(self, op):
+        value = self.getvalue(op.getarg(1))
+        if value.is_virtual():
+            return
+        self.emit_operation(op)
+
+    def optimize_INT_ADD(self, op):
+        value = self.getvalue(op.getarg(0))
+        offsetbox = self.get_constant_box(op.getarg(1))
+        if value.is_virtual() and offsetbox is not None:
+            offset = offsetbox.getint()
+            if isinstance(value, VRawBufferValue):
+                self.make_virtual_raw_slice(value, offset, op.result, op)
+                return
+            elif isinstance(value, VRawSliceValue):
+                offset = offset + value.offset
+                self.make_virtual_raw_slice(value.rawbuffer_value, offset, op.result, op)
+                return
+        self.emit_operation(op)
+
     def optimize_ARRAYLEN_GC(self, op):
         value = self.getvalue(op.getarg(0))
         if value.is_virtual():
@@ -558,6 +718,48 @@
         value.ensure_nonnull()
         self.emit_operation(op)
 
+    def _unpack_arrayitem_raw_op(self, op, indexbox):
+        index = indexbox.getint()
+        cpu = self.optimizer.cpu
+        descr = op.getdescr()
+        basesize, itemsize, _ = cpu.unpack_arraydescr_size(descr)
+        offset = basesize + (itemsize*index)
+        return offset, itemsize, descr
+
+    def optimize_GETARRAYITEM_RAW(self, op):
+        value = self.getvalue(op.getarg(0))
+        if value.is_virtual():
+            indexbox = self.get_constant_box(op.getarg(1))
+            if indexbox is not None:
+                offset, itemsize, descr = self._unpack_arrayitem_raw_op(op, indexbox)
+                try:
+                    itemvalue = value.getitem_raw(offset, itemsize, descr)
+                    self.make_equal_to(op.result, itemvalue)
+                except InvalidRawOperation:
+                    box = value.force_box(self)
+                    op.setarg(0, box)
+                    self.emit_operation(op)
+                return
+        value.ensure_nonnull()
+        self.emit_operation(op)
+
+    def optimize_SETARRAYITEM_RAW(self, op):
+        value = self.getvalue(op.getarg(0))
+        if value.is_virtual():
+            indexbox = self.get_constant_box(op.getarg(1))
+            if indexbox is not None:
+                offset, itemsize, descr = self._unpack_arrayitem_raw_op(op, indexbox)
+                itemvalue = self.getvalue(op.getarg(2))
+                try:
+                    value.setitem_raw(offset, itemsize, descr, itemvalue)
+                except InvalidRawOperation:
+                    box = value.force_box(self)
+                    op.setarg(0, box)
+                    self.emit_operation(op)
+                return
+        value.ensure_nonnull()
+        self.emit_operation(op)
+
     def optimize_GETINTERIORFIELD_GC(self, op):
         value = self.getvalue(op.getarg(0))
         if value.is_virtual():
diff --git a/rpython/jit/metainterp/optimizeopt/virtualstate.py b/rpython/jit/metainterp/optimizeopt/virtualstate.py
--- a/rpython/jit/metainterp/optimizeopt/virtualstate.py
+++ b/rpython/jit/metainterp/optimizeopt/virtualstate.py
@@ -158,10 +158,16 @@
     def debug_header(self, indent):
         debug_print(indent + 'VStructStateInfo(%d):' % self.position)
 
+
 class VArrayStateInfo(AbstractVirtualStateInfo):
+
     def __init__(self, arraydescr):
         self.arraydescr = arraydescr
 
+    def _generalization_of(self, other):
+        return (isinstance(other, VArrayStateInfo) and
+            self.arraydescr is other.arraydescr)
+
     def generalization_of(self, other, renum, bad):
         assert self.position != -1
         if self.position in renum:
@@ -187,10 +193,6 @@
                 return False
         return True
 
-    def _generalization_of(self, other):
-        return (isinstance(other, VArrayStateInfo) and
-            self.arraydescr is other.arraydescr)
-
     def enum_forced_boxes(self, boxes, value, optimizer):
         if not isinstance(value, virtualize.VArrayValue):
             raise BadVirtualState
@@ -198,7 +200,7 @@
             raise BadVirtualState
         for i in range(len(self.fieldstate)):
             try:
-                v = value._items[i]
+                v = value.get_item_value(i)
             except IndexError:
                 raise BadVirtualState
             s = self.fieldstate[i]
@@ -212,6 +214,8 @@
     def debug_header(self, indent):
         debug_print(indent + 'VArrayStateInfo(%d):' % self.position)
 
+
+
 class VArrayStructStateInfo(AbstractVirtualStateInfo):
     def __init__(self, arraydescr, fielddescrs):
         self.arraydescr = arraydescr
@@ -287,6 +291,7 @@
         debug_print(indent + 'VArrayStructStateInfo(%d):' % self.position)
 
 
+
 class NotVirtualStateInfo(AbstractVirtualStateInfo):
     def __init__(self, value, is_opaque=False):
         self.is_opaque = is_opaque
@@ -579,6 +584,9 @@
     def make_varraystruct(self, arraydescr, fielddescrs):
         return VArrayStructStateInfo(arraydescr, fielddescrs)
 
+    def make_vrawbuffer(self, size, offsets, descrs):
+        raise NotImplementedError
+
 class BoxNotProducable(Exception):
     pass
 
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
@@ -2623,6 +2623,7 @@
         box_exchange_buffer = op.getarg(3)
         self.history.operations.pop()
         arg_boxes = []
+
         for i in range(cif_description.nargs):
             kind, descr, itemsize = get_arg_descr(self.cpu,
                                                   cif_description.atypes[i])
diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py
--- a/rpython/jit/metainterp/resume.py
+++ b/rpython/jit/metainterp/resume.py
@@ -275,6 +275,9 @@
     def make_varraystruct(self, arraydescr, fielddescrs):
         return VArrayStructInfo(arraydescr, fielddescrs)
 
+    def make_vrawbuffer(self, size, offsets, descrs):
+        return VRawBufferStateInfo(size, offsets, descrs)
+
     def make_vstrplain(self, is_unicode=False):
         if is_unicode:
             return VUniPlainInfo()
@@ -446,8 +449,8 @@
                 return self.liveboxes_from_env[box]
             return self.liveboxes[box]
 
-
 class AbstractVirtualInfo(object):
+    kind = REF
     #def allocate(self, decoder, index):
     #    raise NotImplementedError
     def equals(self, fieldnums):
@@ -458,6 +461,7 @@
 
     def debug_prints(self):
         raise NotImplementedError
+        
 
 class AbstractVirtualStructInfo(AbstractVirtualInfo):
     def __init__(self, fielddescrs):
@@ -486,7 +490,7 @@
     @specialize.argtype(1)
     def allocate(self, decoder, index):
         struct = decoder.allocate_with_vtable(self.known_class)
-        decoder.virtuals_cache[index] = struct
+        decoder.virtuals_cache.set_ptr(index, struct)
         return self.setfields(decoder, struct)
 
     def debug_prints(self):
@@ -502,7 +506,7 @@
     @specialize.argtype(1)
     def allocate(self, decoder, index):
         struct = decoder.allocate_struct(self.typedescr)
-        decoder.virtuals_cache[index] = struct
+        decoder.virtuals_cache.set_ptr(index, struct)
         return self.setfields(decoder, struct)
 
     def debug_prints(self):
@@ -519,7 +523,7 @@
         length = len(self.fieldnums)
         arraydescr = self.arraydescr
         array = decoder.allocate_array(length, arraydescr)
-        decoder.virtuals_cache[index] = array
+        decoder.virtuals_cache.set_ptr(index, array)
         # NB. the check for the kind of array elements is moved out of the loop
         if arraydescr.is_array_of_pointers():
             for i in range(length):
@@ -541,6 +545,31 @@


More information about the pypy-commit mailing list