Author: Maciej Fijalkowski <[email protected]>
Branch:
Changeset: r74882:db19352f7582
Date: 2014-12-10 17:46 +0200
http://bitbucket.org/pypy/pypy/changeset/db19352f7582/
Log: merge
diff --git a/pypy/module/_rawffi/alt/interp_funcptr.py
b/pypy/module/_rawffi/alt/interp_funcptr.py
--- a/pypy/module/_rawffi/alt/interp_funcptr.py
+++ b/pypy/module/_rawffi/alt/interp_funcptr.py
@@ -14,6 +14,7 @@
from rpython.rlib.objectmodel import we_are_translated
from pypy.module._rawffi.alt.type_converter import FromAppLevelConverter,
ToAppLevelConverter
from pypy.module._rawffi.interp_rawffi import got_libffi_error,
wrap_dlopenerror
+from pypy.module._rawffi import lasterror
import os
if os.name == 'nt':
@@ -201,11 +202,23 @@
self.func = func
self.argchain = argchain
+ def before(self):
+ lasterror.restore_last_error(self.space)
+
+ def after(self):
+ lasterror.save_last_error(self.space)
+
def get_longlong(self, w_ffitype):
- return self.func.call(self.argchain, rffi.LONGLONG)
+ self.before()
+ x = self.func.call(self.argchain, rffi.LONGLONG)
+ self.after()
+ return x
def get_ulonglong(self, w_ffitype):
- return self.func.call(self.argchain, rffi.ULONGLONG)
+ self.before()
+ x = self.func.call(self.argchain, rffi.ULONGLONG)
+ self.after()
+ return x
def get_signed(self, w_ffitype):
# if the declared return type of the function is smaller than LONG,
@@ -216,64 +229,94 @@
# to space.wrap in order to get a nice applevel <int>.
#
restype = w_ffitype.get_ffitype()
+ self.before()
call = self.func.call
if restype is libffi.types.slong:
- return call(self.argchain, rffi.LONG)
+ x = call(self.argchain, rffi.LONG)
elif restype is libffi.types.sint:
- return rffi.cast(rffi.LONG, call(self.argchain, rffi.INT))
+ x = rffi.cast(rffi.LONG, call(self.argchain, rffi.INT))
elif restype is libffi.types.sshort:
- return rffi.cast(rffi.LONG, call(self.argchain, rffi.SHORT))
+ x = rffi.cast(rffi.LONG, call(self.argchain, rffi.SHORT))
elif restype is libffi.types.schar:
- return rffi.cast(rffi.LONG, call(self.argchain, rffi.SIGNEDCHAR))
+ x = rffi.cast(rffi.LONG, call(self.argchain, rffi.SIGNEDCHAR))
else:
- self.error(w_ffitype)
+ raise self.error(w_ffitype)
+ self.after()
+ return x
def get_unsigned(self, w_ffitype):
- return self.func.call(self.argchain, rffi.ULONG)
+ self.before()
+ x = self.func.call(self.argchain, rffi.ULONG)
+ self.after()
+ return x
def get_unsigned_which_fits_into_a_signed(self, w_ffitype):
# the same comment as get_signed apply
restype = w_ffitype.get_ffitype()
+ self.before()
call = self.func.call
if restype is libffi.types.uint:
assert not libffi.IS_32_BIT
# on 32bit machines, we should never get here, because it's a case
# which has already been handled by get_unsigned above.
- return rffi.cast(rffi.LONG, call(self.argchain, rffi.UINT))
+ x = rffi.cast(rffi.LONG, call(self.argchain, rffi.UINT))
elif restype is libffi.types.ushort:
- return rffi.cast(rffi.LONG, call(self.argchain, rffi.USHORT))
+ x = rffi.cast(rffi.LONG, call(self.argchain, rffi.USHORT))
elif restype is libffi.types.uchar:
- return rffi.cast(rffi.LONG, call(self.argchain, rffi.UCHAR))
+ x = rffi.cast(rffi.LONG, call(self.argchain, rffi.UCHAR))
else:
- self.error(w_ffitype)
+ raise self.error(w_ffitype)
+ self.after()
+ return x
def get_pointer(self, w_ffitype):
+ self.before()
ptrres = self.func.call(self.argchain, rffi.VOIDP)
+ self.after()
return rffi.cast(rffi.ULONG, ptrres)
def get_char(self, w_ffitype):
- return self.func.call(self.argchain, rffi.UCHAR)
+ self.before()
+ x = self.func.call(self.argchain, rffi.UCHAR)
+ self.after()
+ return x
def get_unichar(self, w_ffitype):
- return self.func.call(self.argchain, rffi.WCHAR_T)
+ self.before()
+ x = self.func.call(self.argchain, rffi.WCHAR_T)
+ self.after()
+ return x
def get_float(self, w_ffitype):
- return self.func.call(self.argchain, rffi.DOUBLE)
+ self.before()
+ x = self.func.call(self.argchain, rffi.DOUBLE)
+ self.after()
+ return x
def get_singlefloat(self, w_ffitype):
- return self.func.call(self.argchain, rffi.FLOAT)
+ self.before()
+ x = self.func.call(self.argchain, rffi.FLOAT)
+ self.after()
+ return x
def get_struct(self, w_ffitype, w_structdescr):
+ self.before()
addr = self.func.call(self.argchain, rffi.LONG, is_struct=True)
+ self.after()
return w_structdescr.fromaddress(self.space, addr)
def get_struct_rawffi(self, w_ffitype, w_structdescr):
+ self.before()
uintval = self.func.call(self.argchain, rffi.ULONG, is_struct=True)
+ self.after()
return w_structdescr.fromaddress(self.space, uintval)
def get_void(self, w_ffitype):
- return self.func.call(self.argchain, lltype.Void)
+ self.before()
+ x = self.func.call(self.argchain, lltype.Void)
+ self.after()
+ return x
def unpack_argtypes(space, w_argtypes, w_restype):
diff --git a/pypy/module/_rawffi/interp_rawffi.py
b/pypy/module/_rawffi/interp_rawffi.py
--- a/pypy/module/_rawffi/interp_rawffi.py
+++ b/pypy/module/_rawffi/interp_rawffi.py
@@ -18,6 +18,7 @@
from rpython.rlib.rarithmetic import intmask, r_uint
from pypy.module._rawffi.buffer import RawFFIBuffer
from pypy.module._rawffi.tracker import tracker
+from pypy.module._rawffi import lasterror
TYPEMAP = {
# XXX A mess with unsigned/signed/normal chars :-/
@@ -495,10 +496,14 @@
try:
if self.resshape is not None:
result = self.resshape.allocate(space, 1, autofree=True)
+ lasterror.restore_last_error(space)
self.ptr.call(args_ll, result.ll_buffer)
+ lasterror.save_last_error(space)
return space.wrap(result)
else:
+ lasterror.restore_last_error(space)
self.ptr.call(args_ll, lltype.nullptr(rffi.VOIDP.TO))
+ lasterror.save_last_error(space)
return space.w_None
except StackCheckError, e:
raise OperationError(space.w_ValueError, space.wrap(e.message))
@@ -615,12 +620,10 @@
if sys.platform == 'win32':
def get_last_error(space):
- from rpython.rlib.rwin32 import GetLastError
- return space.wrap(GetLastError())
+ return space.wrap(lasterror.fetch_last_error(space))
@unwrap_spec(error=int)
def set_last_error(space, error):
- from rpython.rlib.rwin32 import SetLastError
- SetLastError(error)
+ lasterror.store_last_error(space, error)
else:
# always have at least a dummy version of these functions
# (https://bugs.pypy.org/issue1242)
diff --git a/pypy/module/_rawffi/lasterror.py b/pypy/module/_rawffi/lasterror.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_rawffi/lasterror.py
@@ -0,0 +1,40 @@
+# For Windows only.
+# https://bitbucket.org/pypy/pypy/issue/1944/ctypes-on-windows-getlasterror
+
+import os
+
+_MS_WINDOWS = os.name == "nt"
+
+
+if _MS_WINDOWS:
+ from rpython.rlib import rwin32
+ from pypy.interpreter.executioncontext import ExecutionContext
+
+
+ ExecutionContext._rawffi_last_error = 0
+
+ def fetch_last_error(space):
+ ec = space.getexecutioncontext()
+ return ec._rawffi_last_error
+
+ def store_last_error(space, last_error):
+ ec = space.getexecutioncontext()
+ ec._rawffi_last_error = last_error
+
+ def restore_last_error(space):
+ ec = space.getexecutioncontext()
+ lasterror = ec._rawffi_last_error
+ rwin32.SetLastError(lasterror)
+
+ def save_last_error(space):
+ lasterror = rwin32.GetLastError()
+ ec = space.getexecutioncontext()
+ ec._rawffi_last_error = lasterror
+
+else:
+
+ def restore_last_error(space):
+ pass
+
+ def save_last_error(space):
+ pass
diff --git a/pypy/module/_rawffi/test/test__rawffi.py
b/pypy/module/_rawffi/test/test__rawffi.py
--- a/pypy/module/_rawffi/test/test__rawffi.py
+++ b/pypy/module/_rawffi/test/test__rawffi.py
@@ -16,6 +16,7 @@
#include "src/precommondefs.h"
#include <stdlib.h>
#include <stdio.h>
+ #include <errno.h>
struct x
{
@@ -204,6 +205,24 @@
return inp;
}
+ RPY_EXPORTED
+ int check_errno(int incoming)
+ {
+ int old_errno = errno;
+ errno = incoming;
+ return old_errno;
+ }
+
+ #ifdef _WIN32
+ #include <Windows.h>
+ RPY_EXPORTED
+ int check_last_error(int incoming)
+ {
+ int old_errno = GetLastError();
+ SetLastError(incoming);
+ return old_errno;
+ }
+ #endif
'''))
eci = ExternalCompilationInfo(include_dirs=[cdir])
return str(platform.compile([c_file], eci, 'x', standalone=False))
@@ -1150,6 +1169,37 @@
raises(OverflowError, "arg1[0] = 10**900")
arg1.free()
+ def test_errno(self):
+ import _rawffi
+ lib = _rawffi.CDLL(self.lib_name)
+ A = _rawffi.Array('i')
+ f = lib.ptr('check_errno', ['i'], 'i')
+ _rawffi.set_errno(42)
+ arg = A(1)
+ arg[0] = 43
+ res = f(arg)
+ assert res[0] == 42
+ z = _rawffi.get_errno()
+ assert z == 43
+ arg.free()
+
+ def test_last_error(self):
+ import sys
+ if sys.platform != 'win32':
+ skip("Windows test")
+ import _rawffi
+ lib = _rawffi.CDLL(self.lib_name)
+ A = _rawffi.Array('i')
+ f = lib.ptr('check_last_error', ['i'], 'i')
+ _rawffi.set_last_error(42)
+ arg = A(1)
+ arg[0] = 43
+ res = f(arg)
+ assert res[0] == 42
+ z = _rawffi.get_last_error()
+ assert z == 43
+ arg.free()
+
class AppTestAutoFree:
spaceconfig = dict(usemodules=['_rawffi', 'struct'])
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -17,9 +17,13 @@
self.w_value = w_value
+def needs_to_unwrap_cell(space, w_value):
+ return (space.config.objspace.std.withtypeversion and
+ isinstance(w_value, TypeCell))
+
+
def unwrap_cell(space, w_value):
- if (space.config.objspace.std.withtypeversion and
- isinstance(w_value, TypeCell)):
+ if needs_to_unwrap_cell(space, w_value):
return w_value.w_value
return w_value
@@ -366,8 +370,11 @@
tup = w_self._lookup_where(name)
return tup
name = promote_string(name)
- w_class, w_value = w_self._pure_lookup_where_with_method_cache(name,
version_tag)
- return w_class, unwrap_cell(space, w_value)
+ tup_w = w_self._pure_lookup_where_with_method_cache(name, version_tag)
+ w_class, w_value = tup_w
+ if needs_to_unwrap_cell(space, w_value):
+ return w_class, w_value.value
+ return tup_w # don't make a new tuple, reuse the old one
def _pure_lookup_where_possibly_with_method_cache(w_self, name,
version_tag):
if w_self.space.config.objspace.std.withmethodcache:
diff --git a/rpython/config/translationoption.py
b/rpython/config/translationoption.py
--- a/rpython/config/translationoption.py
+++ b/rpython/config/translationoption.py
@@ -129,7 +129,8 @@
default=False, cmdline=None),
# misc
- BoolOption("verbose", "Print extra information", default=False),
+ BoolOption("verbose", "Print extra information", default=False,
+ cmdline="--verbose"),
StrOption("cc", "Specify compiler to use for compiling generated C",
cmdline="--cc"),
StrOption("profopt", "Specify profile based optimization script",
cmdline="--profopt"),
diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py
--- a/rpython/flowspace/operation.py
+++ b/rpython/flowspace/operation.py
@@ -528,6 +528,10 @@
pyfunc = staticmethod(getattr)
def constfold(self):
+ from rpython.flowspace.flowcontext import FlowingError
+ if len(self.args) == 3:
+ raise FlowingError(
+ "getattr() with three arguments not supported: %s" % (self,))
w_obj, w_name = self.args
# handling special things like sys
if (w_obj in NOT_REALLY_CONST and
@@ -538,7 +542,6 @@
try:
result = getattr(obj, name)
except Exception as e:
- from rpython.flowspace.flowcontext import FlowingError
etype = e.__class__
msg = "getattr(%s, %s) always raises %s: %s" % (
obj, name, etype, e)
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
@@ -964,9 +964,40 @@
assembler_call = False
if warmrunnerstate.inlining:
if warmrunnerstate.can_inline_callable(greenboxes):
+ # We've found a potentially inlinable function; now we need to
+ # see if it's already on the stack. In other words: are we
about
+ # to enter recursion? If so, we don't want to inline the
+ # recursion, which would be equivalent to unrolling a while
+ # loop.
portal_code = targetjitdriver_sd.mainjitcode
- return self.metainterp.perform_call(portal_code, allboxes,
- greenkey=greenboxes)
+ count = 0
+ for f in self.metainterp.framestack:
+ if f.jitcode is not portal_code:
+ continue
+ gk = f.greenkey
+ if gk is None:
+ continue
+ assert len(gk) == len(greenboxes)
+ i = 0
+ for i in range(len(gk)):
+ if not gk[i].same_constant(greenboxes[i]):
+ break
+ else:
+ count += 1
+ memmgr =
self.metainterp.staticdata.warmrunnerdesc.memory_manager
+ if count >= memmgr.max_unroll_recursion:
+ # This function is recursive and has exceeded the
+ # maximum number of unrollings we allow. We want to stop
+ # inlining it further and to make sure that, if it
+ # hasn't happened already, the function is traced
+ # separately as soon as possible.
+ if have_debug_prints():
+ loc =
targetjitdriver_sd.warmstate.get_location_str(greenboxes)
+ debug_print("recursive function (not inlined):", loc)
+ warmrunnerstate.dont_trace_here(greenboxes)
+ else:
+ return self.metainterp.perform_call(portal_code, allboxes,
+ greenkey=greenboxes)
assembler_call = True
# verify that we have all green args, needed to make sure
# that assembler that we call is still correct
diff --git a/rpython/jit/metainterp/test/test_list.py
b/rpython/jit/metainterp/test/test_list.py
--- a/rpython/jit/metainterp/test/test_list.py
+++ b/rpython/jit/metainterp/test/test_list.py
@@ -97,28 +97,6 @@
assert res == f(10)
self.check_resops(setarrayitem_gc=0, call=0, getarrayitem_gc=0)
- def test_vlist_alloc_and_set(self):
- # the check_loops fails, because [non-null] * n is only supported
- # if n < 15 (otherwise it is implemented as a residual call)
- jitdriver = JitDriver(greens = [], reds = ['n'])
- def f(n):
- l = [1] * 20
- while n > 0:
- jitdriver.can_enter_jit(n=n)
- jitdriver.jit_merge_point(n=n)
- l = [1] * 20
- l[3] = 5
- x = l[-17] + l[5] - 1
- if n < 3:
- return x
- n -= 1
- return l[0]
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == f(10)
- py.test.skip("'[non-null] * n' for n >= 15 gives a residual call so
far")
- self.check_loops(setarrayitem_gc=0, getarrayitem_gc=0, call=0)
-
def test_arraycopy_simpleoptimize(self):
def f():
l = [1, 2, 3, 4]
diff --git a/rpython/jit/metainterp/test/test_recursive.py
b/rpython/jit/metainterp/test/test_recursive.py
--- a/rpython/jit/metainterp/test/test_recursive.py
+++ b/rpython/jit/metainterp/test/test_recursive.py
@@ -1112,6 +1112,37 @@
assert res == 2095
self.check_resops(call_assembler=12)
+ def test_inline_recursion_limit(self):
+ driver = JitDriver(greens = ["threshold", "loop"], reds=["i"])
+ @dont_look_inside
+ def f():
+ set_param(driver, "max_unroll_recursion", 10)
+ def portal(threshold, loop, i):
+ f()
+ if i > threshold:
+ return i
+ while True:
+ driver.jit_merge_point(threshold=threshold, loop=loop, i=i)
+ if loop:
+ portal(threshold, False, 0)
+ else:
+ portal(threshold, False, i + 1)
+ return i
+ if i > 10:
+ return 1
+ i += 1
+ driver.can_enter_jit(threshold=threshold, loop=loop, i=i)
+
+ res1 = portal(10, True, 0)
+ res2 = self.meta_interp(portal, [10, True, 0], inline=True)
+ assert res1 == res2
+ self.check_resops(call_assembler=2)
+
+ res1 = portal(9, True, 0)
+ res2 = self.meta_interp(portal, [9, True, 0], inline=True)
+ assert res1 == res2
+ self.check_resops(call_assembler=0)
+
def test_handle_jitexception_in_portal(self):
# a test for _handle_jitexception_in_portal in blackhole.py
driver = JitDriver(greens = ['codeno'], reds = ['i', 'str'],
diff --git a/rpython/jit/metainterp/test/test_send.py
b/rpython/jit/metainterp/test/test_send.py
--- a/rpython/jit/metainterp/test/test_send.py
+++ b/rpython/jit/metainterp/test/test_send.py
@@ -385,8 +385,7 @@
self.check_target_token_count(4)
def test_two_behaviors(self):
- py.test.skip("XXX fix me!!!!!!! problem in optimize.py")
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y'])
+ myjitdriver = JitDriver(greens = [], reds = ['y', 'x'])
class Int:
def __init__(self, value):
self.value = value
@@ -402,11 +401,6 @@
return x.value
res = self.meta_interp(f, [len(cases)])
assert res == 110
- # The generated loops don't contain a new_with_vtable at all. This
- # is true if we replace "if cases[y]" above with "if not cases[y]"
- # -- so there is no good reason that it fails.
- self.check_loops(new_with_vtable=0)
- self.check_trace_count(2)
def test_behavior_change_after_a_while(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'x'])
diff --git a/rpython/jit/metainterp/warmspot.py
b/rpython/jit/metainterp/warmspot.py
--- a/rpython/jit/metainterp/warmspot.py
+++ b/rpython/jit/metainterp/warmspot.py
@@ -69,7 +69,8 @@
backendopt=False, trace_limit=sys.maxint,
inline=False, loop_longevity=0, retrace_limit=5,
function_threshold=4,
- enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15, **kwds):
+ enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15,
+ max_unroll_recursion=7, **kwds):
from rpython.config.config import ConfigError
translator = interp.typer.annotator.translator
try:
@@ -91,6 +92,7 @@
jd.warmstate.set_param_retrace_limit(retrace_limit)
jd.warmstate.set_param_max_retrace_guards(max_retrace_guards)
jd.warmstate.set_param_enable_opts(enable_opts)
+ jd.warmstate.set_param_max_unroll_recursion(max_unroll_recursion)
warmrunnerdesc.finish()
if graph_and_interp_only:
return interp, graph
diff --git a/rpython/jit/metainterp/warmstate.py
b/rpython/jit/metainterp/warmstate.py
--- a/rpython/jit/metainterp/warmstate.py
+++ b/rpython/jit/metainterp/warmstate.py
@@ -291,6 +291,11 @@
if self.warmrunnerdesc.memory_manager:
self.warmrunnerdesc.memory_manager.max_unroll_loops = value
+ def set_param_max_unroll_recursion(self, value):
+ if self.warmrunnerdesc:
+ if self.warmrunnerdesc.memory_manager:
+ self.warmrunnerdesc.memory_manager.max_unroll_recursion = value
+
def disable_noninlinable_function(self, greenkey):
cell = self.JitCell.ensure_jit_cell_at_key(greenkey)
cell.flags |= JC_DONT_TRACE_HERE
@@ -567,19 +572,26 @@
jd = self.jitdriver_sd
cpu = self.cpu
- def can_inline_greenargs(*greenargs):
+ def can_inline_callable(greenkey):
+ greenargs = unwrap_greenkey(greenkey)
if can_never_inline(*greenargs):
return False
cell = JitCell.get_jitcell(*greenargs)
if cell is not None and (cell.flags & JC_DONT_TRACE_HERE) != 0:
return False
return True
- def can_inline_callable(greenkey):
- greenargs = unwrap_greenkey(greenkey)
- return can_inline_greenargs(*greenargs)
- self.can_inline_greenargs = can_inline_greenargs
self.can_inline_callable = can_inline_callable
+ def dont_trace_here(greenkey):
+ # Set greenkey as somewhere that tracing should not occur into;
+ # notice that, as per the description of JC_DONT_TRACE_HERE
earlier,
+ # if greenkey hasn't been traced separately, setting
+ # JC_DONT_TRACE_HERE will force tracing the next time the function
+ # is encountered.
+ cell = JitCell.ensure_jit_cell_at_key(greenkey)
+ cell.flags |= JC_DONT_TRACE_HERE
+ self.dont_trace_here = dont_trace_here
+
if jd._should_unroll_one_iteration_ptr is None:
def should_unroll_one_iteration(greenkey):
return False
diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -463,6 +463,7 @@
'max_unroll_loops': 'number of extra unrollings a loop can cause',
'enable_opts': 'INTERNAL USE ONLY (MAY NOT WORK OR LEAD TO CRASHES): '
'optimizations to enable, or all = %s' % ENABLE_ALL_OPTS,
+ 'max_unroll_recursion': 'how many levels deep to unroll a recursive
function'
}
PARAMETERS = {'threshold': 1039, # just above 1024, prime
@@ -476,6 +477,7 @@
'max_retrace_guards': 15,
'max_unroll_loops': 0,
'enable_opts': 'all',
+ 'max_unroll_recursion': 7,
}
unroll_parameters = unrolling_iterable(PARAMETERS.items())
diff --git a/rpython/rtyper/lltypesystem/lltype.py
b/rpython/rtyper/lltypesystem/lltype.py
--- a/rpython/rtyper/lltypesystem/lltype.py
+++ b/rpython/rtyper/lltypesystem/lltype.py
@@ -182,8 +182,8 @@
def _freeze_(self):
return True
- def _inline_is_varsize(self, last):
- return False
+ def _note_inlined_into(self, parent, first, last):
+ """Called when this type is being used inline in a container."""
def _is_atomic(self):
return False
@@ -201,8 +201,9 @@
class ContainerType(LowLevelType):
_adtmeths = {}
- def _inline_is_varsize(self, last):
- raise TypeError("%r cannot be inlined in structure" % self)
+ def _note_inlined_into(self, parent, first, last):
+ raise TypeError("%r cannot be inlined in %r" % (
+ self.__class__.__name__, parent.__class__.__name__))
def _install_extras(self, adtmeths={}, hints={}):
self._adtmeths = frozendict(adtmeths)
@@ -279,11 +280,13 @@
# look if we have an inlined variable-sized array as the last field
if fields:
+ first = True
for name, typ in fields[:-1]:
- typ._inline_is_varsize(False)
+ typ._note_inlined_into(self, first=first, last=False)
first = False
name, typ = fields[-1]
- if typ._inline_is_varsize(True):
+ typ._note_inlined_into(self, first=first, last=True)
+ if typ._is_varsize():
self._arrayfld = name
self._flds = frozendict(flds)
self._names = tuple(names)
@@ -299,11 +302,14 @@
return first, FIRSTTYPE
return None, None
- def _inline_is_varsize(self, last):
- if self._arrayfld:
+ def _note_inlined_into(self, parent, first, last):
+ if self._arrayfld is not None:
raise TypeError("cannot inline a var-sized struct "
"inside another container")
- return False
+ if self._gckind == 'gc':
+ if not first or not isinstance(parent, GcStruct):
+ raise TypeError("a GcStruct can only be inlined as the first "
+ "field of another GcStruct")
def _is_atomic(self):
for typ in self._flds.values():
@@ -428,15 +434,18 @@
if isinstance(self.OF, ContainerType) and self.OF._gckind != 'raw':
raise TypeError("cannot have a %s container as array item type"
% (self.OF._gckind,))
- self.OF._inline_is_varsize(False)
+ self.OF._note_inlined_into(self, first=False, last=False)
self._install_extras(**kwds)
- def _inline_is_varsize(self, last):
- if not last:
+ def _note_inlined_into(self, parent, first, last):
+ if not last or not isinstance(parent, Struct):
raise TypeError("cannot inline an array in another container"
" unless as the last field of a structure")
- return True
+ if self._gckind == 'gc':
+ raise TypeError("cannot inline a GC array inside a structure")
+ if parent._gckind == 'gc' and self._hints.get('nolength', False):
+ raise TypeError("cannot inline a no-length array inside a
GcStruct")
def _is_atomic(self):
return self.OF._is_atomic()
@@ -474,9 +483,6 @@
class GcArray(Array):
_gckind = 'gc'
- def _inline_is_varsize(self, last):
- raise TypeError("cannot inline a GC array inside a structure")
-
class FixedSizeArray(Struct):
# behaves more or less like a Struct with fields item0, item1, ...
@@ -508,7 +514,7 @@
if isinstance(self.OF, ContainerType) and self.OF._gckind != 'raw':
raise TypeError("cannot have a %s container as array item type"
% (self.OF._gckind,))
- self.OF._inline_is_varsize(False)
+ self.OF._note_inlined_into(self, first=False, last=False)
def _str_fields(self):
return str(self.OF)
@@ -579,8 +585,11 @@
def __str__(self):
return "%s (opaque)" % self.tag
- def _inline_is_varsize(self, last):
- return False # OpaqueType can be inlined
+ def _note_inlined_into(self, parent, first, last):
+ # OpaqueType can be inlined, but not GcOpaqueType
+ if self._gckind == 'gc':
+ raise TypeError("%r cannot be inlined in %r" % (
+ self.__class__.__name__, parent.__class__.__name__))
def _container_example(self):
return _opaque(self)
@@ -599,10 +608,6 @@
def __str__(self):
return "%s (gcopaque)" % self.tag
- def _inline_is_varsize(self, last):
- raise TypeError("%r cannot be inlined in structure" % self)
-
-
class ForwardReference(ContainerType):
_gckind = 'raw'
def become(self, realcontainertype):
diff --git a/rpython/rtyper/lltypesystem/test/test_lltype.py
b/rpython/rtyper/lltypesystem/test/test_lltype.py
--- a/rpython/rtyper/lltypesystem/test/test_lltype.py
+++ b/rpython/rtyper/lltypesystem/test/test_lltype.py
@@ -808,6 +808,20 @@
assert F.RESULT == Signed
assert F.ARGS == (Signed,)
+def test_cannot_inline_random_stuff_in_gcstruct():
+ S = GcStruct('S')
+ GcStruct('X', ('a', S)) # works
+ py.test.raises(TypeError, GcStruct, 'X', ('a', Signed), ('b', S))
+ GcStruct('X', ('a', Array(Signed))) # works
+ py.test.raises(TypeError, GcStruct, 'X', ('a', Array(Signed)),
+ ('b', Signed))
+ Struct('X', ('a', Array(Signed, hints={'nolength': True}))) # works
+ py.test.raises(TypeError, GcStruct, 'X',
+ ('a', Array(Signed, hints={'nolength': True})))
+ GcStruct('X', ('a', OpaqueType('foo'))) # works
+ py.test.raises(TypeError, GcStruct, 'X', ('a', GcOpaqueType('foo')))
+
+
class TestTrackAllocation:
def test_automatic_tracking(self):
# calls to start_tracking_allocations/stop_tracking_allocations
diff --git a/rpython/translator/backendopt/inline.py
b/rpython/translator/backendopt/inline.py
--- a/rpython/translator/backendopt/inline.py
+++ b/rpython/translator/backendopt/inline.py
@@ -478,6 +478,7 @@
'malloc': 2,
'instrument_count': 0,
'debug_assert': -1,
+ 'jit_force_virtualizable': 0,
}
def block_weight(block, weights=OP_WEIGHTS):
diff --git a/rpython/translator/backendopt/storesink.py
b/rpython/translator/backendopt/storesink.py
--- a/rpython/translator/backendopt/storesink.py
+++ b/rpython/translator/backendopt/storesink.py
@@ -5,7 +5,7 @@
from rpython.translator import simplify
def has_side_effects(op):
- if op.opname == 'debug_assert':
+ if op.opname == 'debug_assert' or op.opname == 'jit_force_virtualizable':
return False
try:
return getattr(llop, op.opname).sideeffects
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit