[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