[pypy-commit] pypy cpyext-int: merge default into branch
mattip
noreply at buildbot.pypy.org
Sat Nov 9 22:11:46 CET 2013
Author: Matti Picus <matti.picus at gmail.com>
Branch: cpyext-int
Changeset: r67909:2f1482525200
Date: 2013-11-09 23:06 +0200
http://bitbucket.org/pypy/pypy/changeset/2f1482525200/
Log: merge default into branch
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -47,3 +47,7 @@
* post announcement on morepypy.blogspot.com
* send announcements to pypy-dev, python-list,
python-announce, python-dev ...
+
+* add a tag on jitviewer that corresponds to pypy release
+* add a tag on codespeed that corresponds to pypy release
+
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -7,7 +7,7 @@
appleveldefs = {
}
interpleveldefs = {
- '__version__': 'space.wrap("0.7")',
+ '__version__': 'space.wrap("0.8")',
'load_library': 'libraryobj.load_library',
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
@@ -19,9 +19,9 @@
_cdata = lltype.nullptr(rffi.CCHARP.TO)
def __init__(self, space, cdata, ctype):
- from pypy.module._cffi_backend import ctypeprim
+ from pypy.module._cffi_backend import ctypeobj
assert lltype.typeOf(cdata) == rffi.CCHARP
- assert isinstance(ctype, ctypeprim.W_CType)
+ assert isinstance(ctype, ctypeobj.W_CType)
self.space = space
self._cdata = cdata # don't forget keepalive_until_here!
self.ctype = ctype
@@ -211,7 +211,21 @@
keepalive_until_here(w_value)
return
#
+ # A fast path for <char[]>[0:N] = "somestring".
+ from pypy.module._cffi_backend import ctypeprim
space = self.space
+ if (space.isinstance_w(w_value, space.w_str) and
+ isinstance(ctitem, ctypeprim.W_CTypePrimitiveChar)):
+ from rpython.rtyper.annlowlevel import llstr
+ from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
+ value = space.str_w(w_value)
+ if len(value) != length:
+ raise operationerrfmt(space.w_ValueError,
+ "need a string of length %d, got %d",
+ length, len(value))
+ copy_string_to_raw(llstr(value), cdata, 0, length)
+ return
+ #
w_iter = space.iter(w_value)
for i in range(length):
try:
@@ -245,19 +259,22 @@
space = self.space
if isinstance(w_other, W_CData):
from pypy.module._cffi_backend import ctypeptr, ctypearray
+ from pypy.module._cffi_backend import ctypevoid
ct = w_other.ctype
if isinstance(ct, ctypearray.W_CTypeArray):
ct = ct.ctptr
#
if (ct is not self.ctype or
not isinstance(ct, ctypeptr.W_CTypePointer) or
- ct.ctitem.size <= 0):
+ (ct.ctitem.size <= 0 and not ct.is_void_ptr)):
raise operationerrfmt(space.w_TypeError,
"cannot subtract cdata '%s' and cdata '%s'",
self.ctype.name, ct.name)
#
+ itemsize = ct.ctitem.size
+ if itemsize <= 0: itemsize = 1
diff = (rffi.cast(lltype.Signed, self._cdata) -
- rffi.cast(lltype.Signed, w_other._cdata)) // ct.ctitem.size
+ rffi.cast(lltype.Signed, w_other._cdata)) // itemsize
return space.wrap(diff)
#
return self._add_or_sub(w_other, -1)
@@ -441,6 +458,7 @@
__getitem__ = interp2app(W_CData.getitem),
__setitem__ = interp2app(W_CData.setitem),
__add__ = interp2app(W_CData.add),
+ __radd__ = interp2app(W_CData.add),
__sub__ = interp2app(W_CData.sub),
__getattr__ = interp2app(W_CData.getattr),
__setattr__ = interp2app(W_CData.setattr),
diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py
--- a/pypy/module/_cffi_backend/ctypearray.py
+++ b/pypy/module/_cffi_backend/ctypearray.py
@@ -34,19 +34,8 @@
datasize = self.size
#
if datasize < 0:
- if (space.isinstance_w(w_init, space.w_list) or
- space.isinstance_w(w_init, space.w_tuple)):
- length = space.int_w(space.len(w_init))
- elif space.isinstance_w(w_init, space.w_basestring):
- # from a string, we add the null terminator
- length = space.int_w(space.len(w_init)) + 1
- else:
- length = space.getindex_w(w_init, space.w_OverflowError)
- if length < 0:
- raise OperationError(space.w_ValueError,
- space.wrap("negative array length"))
- w_init = space.w_None
- #
+ from pypy.module._cffi_backend import misc
+ w_init, length = misc.get_new_array_length(space, w_init)
try:
datasize = ovfcheck(length * self.ctitem.size)
except OverflowError:
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -2,27 +2,25 @@
Pointers.
"""
-from pypy.interpreter.error import OperationError, operationerrfmt, wrap_oserror
-
from rpython.rlib import rposix
from rpython.rlib.objectmodel import keepalive_until_here
from rpython.rlib.rarithmetic import ovfcheck
+from rpython.rtyper.annlowlevel import llstr, llunicode
from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw, copy_unicode_to_raw
+from pypy.interpreter.error import OperationError, operationerrfmt, wrap_oserror
from pypy.module._cffi_backend import cdataobj, misc, ctypeprim, ctypevoid
from pypy.module._cffi_backend.ctypeobj import W_CType
class W_CTypePtrOrArray(W_CType):
- _attrs_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr',
- 'length']
- _immutable_fields_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr',
- 'length']
+ _attrs_ = ['ctitem', 'can_cast_anything', 'length']
+ _immutable_fields_ = ['ctitem', 'can_cast_anything', 'length']
length = -1
def __init__(self, space, size, extra, extra_position, ctitem,
could_cast_anything=True):
- from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
name, name_position = ctitem.insert_name(extra, extra_position)
W_CType.__init__(self, space, size, name, name_position)
# this is the "underlying type":
@@ -31,7 +29,6 @@
# - for functions, it is the return type
self.ctitem = ctitem
self.can_cast_anything = could_cast_anything and ctitem.cast_anything
- self.is_struct_ptr = isinstance(ctitem, W_CTypeStructOrUnion)
def is_char_ptr_or_array(self):
return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar)
@@ -90,8 +87,7 @@
"initializer string is too long for '%s'"
" (got %d characters)",
self.name, n)
- for i in range(n):
- cdata[i] = s[i]
+ copy_string_to_raw(llstr(s), cdata, 0, n)
if n != self.length:
cdata[n] = '\x00'
elif isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar):
@@ -105,8 +101,7 @@
" (got %d characters)",
self.name, n)
unichardata = rffi.cast(rffi.CWCHARP, cdata)
- for i in range(n):
- unichardata[i] = s[i]
+ copy_unicode_to_raw(llunicode(s), unichardata, 0, n)
if n != self.length:
unichardata[n] = u'\x00'
else:
@@ -157,7 +152,6 @@
return cdataobj.W_CData(self.space, ptrdata, self)
def convert_from_object(self, cdata, w_ob):
- space = self.space
if not isinstance(w_ob, cdataobj.W_CData):
raise self._convert_error("cdata pointer", w_ob)
other = w_ob.ctype
@@ -197,6 +191,7 @@
W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem)
def newp(self, w_init):
+ from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
space = self.space
ctitem = self.ctitem
datasize = ctitem.size
@@ -204,10 +199,15 @@
raise operationerrfmt(space.w_TypeError,
"cannot instantiate ctype '%s' of unknown size",
self.name)
- if self.is_struct_ptr:
+ if isinstance(ctitem, W_CTypeStructOrUnion):
# 'newp' on a struct-or-union pointer: in this case, we return
# a W_CDataPtrToStruct object which has a strong reference
# to a W_CDataNewOwning that really contains the structure.
+ #
+ if ctitem.with_var_array and not space.is_w(w_init, space.w_None):
+ datasize = ctitem.convert_struct_from_object(
+ lltype.nullptr(rffi.CCHARP.TO), w_init, datasize)
+ #
cdatastruct = cdataobj.W_CDataNewOwning(space, datasize, ctitem)
cdata = cdataobj.W_CDataPtrToStructOrUnion(space,
cdatastruct._cdata,
@@ -238,11 +238,15 @@
def add(self, cdata, i):
space = self.space
ctitem = self.ctitem
+ itemsize = ctitem.size
if ctitem.size < 0:
- raise operationerrfmt(space.w_TypeError,
+ if self.is_void_ptr:
+ itemsize = 1
+ else:
+ raise operationerrfmt(space.w_TypeError,
"ctype '%s' points to items of unknown size",
self.name)
- p = rffi.ptradd(cdata, i * self.ctitem.size)
+ p = rffi.ptradd(cdata, i * itemsize)
return cdataobj.W_CData(space, p, self)
def cast(self, w_ob):
@@ -298,7 +302,6 @@
def convert_argument_from_object(self, cdata, w_ob):
from pypy.module._cffi_backend.ctypefunc import set_mustfree_flag
- space = self.space
result = (not isinstance(w_ob, cdataobj.W_CData) and
self._prepare_pointer_call_argument(w_ob, cdata))
if result == 0:
@@ -320,7 +323,8 @@
space = self.space
ctype2 = cdata.ctype
if (isinstance(ctype2, W_CTypeStructOrUnion) or
- (isinstance(ctype2, W_CTypePtrOrArray) and ctype2.is_struct_ptr)):
+ (isinstance(ctype2, W_CTypePtrOrArray) and
+ isinstance(ctype2.ctitem, W_CTypeStructOrUnion))):
ptrdata = rffi.ptradd(cdata._cdata, offset)
return cdataobj.W_CData(space, ptrdata, self)
else:
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
@@ -9,7 +9,8 @@
from rpython.rlib import jit
from rpython.rlib.objectmodel import keepalive_until_here
from rpython.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, intmask
-from rpython.rtyper.lltypesystem import rffi
+from rpython.rlib.rarithmetic import ovfcheck
+from rpython.rtyper.lltypesystem import lltype, rffi
from pypy.module._cffi_backend import cdataobj, ctypeprim, misc
from pypy.module._cffi_backend.ctypeobj import W_CType
@@ -17,12 +18,13 @@
class W_CTypeStructOrUnion(W_CType):
_immutable_fields_ = ['alignment?', 'fields_list?', 'fields_dict?',
- 'custom_field_pos?']
+ 'custom_field_pos?', 'with_var_array?']
# fields added by complete_struct_or_union():
alignment = -1
fields_list = None
fields_dict = None
custom_field_pos = False
+ with_var_array = False
def __init__(self, space, name):
W_CType.__init__(self, space, -1, name, len(name))
@@ -90,12 +92,13 @@
pass
def convert_from_object(self, cdata, w_ob):
- space = self.space
- if self._copy_from_same(cdata, w_ob):
- return
+ if not self._copy_from_same(cdata, w_ob):
+ self.convert_struct_from_object(cdata, w_ob, optvarsize=-1)
+ def convert_struct_from_object(self, cdata, w_ob, optvarsize):
self._check_only_one_argument_for_union(w_ob)
+ space = self.space
if (space.isinstance_w(w_ob, space.w_list) or
space.isinstance_w(w_ob, space.w_tuple)):
lst_w = space.listview(w_ob)
@@ -104,7 +107,9 @@
"too many initializers for '%s' (got %d)",
self.name, len(lst_w))
for i in range(len(lst_w)):
- self.fields_list[i].write(cdata, lst_w[i])
+ optvarsize = self.fields_list[i].write_v(cdata, lst_w[i],
+ optvarsize)
+ return optvarsize
elif space.isinstance_w(w_ob, space.w_dict):
lst_w = space.fixedview(w_ob)
@@ -116,11 +121,16 @@
except KeyError:
space.raise_key_error(w_key)
assert 0
- cf.write(cdata, space.getitem(w_ob, w_key))
+ optvarsize = cf.write_v(cdata, space.getitem(w_ob, w_key),
+ optvarsize)
+ return optvarsize
else:
- raise self._convert_error("list or tuple or dict or struct-cdata",
- w_ob)
+ if optvarsize == -1:
+ msg = "list or tuple or dict or struct-cdata"
+ else:
+ msg = "list or tuple or dict"
+ raise self._convert_error(msg, w_ob)
@jit.elidable
def _getcfield_const(self, attr):
@@ -192,6 +202,37 @@
else:
self.ctype.convert_from_object(cdata, w_ob)
+ def write_v(self, cdata, w_ob, optvarsize):
+ # a special case for var-sized C99 arrays
+ from pypy.module._cffi_backend import ctypearray
+ ct = self.ctype
+ if isinstance(ct, ctypearray.W_CTypeArray) and ct.length < 0:
+ space = ct.space
+ w_ob, varsizelength = misc.get_new_array_length(space, w_ob)
+ if optvarsize != -1:
+ # in this mode, the only purpose of this function is to compute
+ # the real size of the structure from a var-sized C99 array
+ assert cdata == lltype.nullptr(rffi.CCHARP.TO)
+ itemsize = ct.ctitem.size
+ try:
+ varsize = ovfcheck(itemsize * varsizelength)
+ size = ovfcheck(self.offset + varsize)
+ except OverflowError:
+ raise OperationError(space.w_OverflowError,
+ space.wrap("array size would overflow a ssize_t"))
+ assert size >= 0
+ return max(size, optvarsize)
+ # if 'value' was only an integer, get_new_array_length() returns
+ # w_ob = space.w_None. Detect if this was the case,
+ # and if so, stop here, leaving the content uninitialized
+ # (it should be zero-initialized from somewhere else).
+ if space.is_w(w_ob, space.w_None):
+ return optvarsize
+ #
+ if optvarsize == -1:
+ self.write(cdata, w_ob)
+ return optvarsize
+
def convert_bitfield_to_object(self, cdata):
ctype = self.ctype
space = ctype.space
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
@@ -278,6 +278,22 @@
# ____________________________________________________________
+def get_new_array_length(space, w_value):
+ if (space.isinstance_w(w_value, space.w_list) or
+ space.isinstance_w(w_value, space.w_tuple)):
+ return (w_value, space.int_w(space.len(w_value)))
+ elif space.isinstance_w(w_value, space.w_basestring):
+ # from a string, we add the null terminator
+ return (w_value, space.int_w(space.len(w_value)) + 1)
+ else:
+ explicitlength = space.getindex_w(w_value, space.w_OverflowError)
+ if explicitlength < 0:
+ raise OperationError(space.w_ValueError,
+ space.wrap("negative array length"))
+ return (space.w_None, explicitlength)
+
+# ____________________________________________________________
+
@specialize.arg(0)
def _raw_memcopy_tp(TPP, source, dest):
# in its own function: LONGLONG may make the whole function jit-opaque
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -158,8 +158,10 @@
fields_list = []
fields_dict = {}
custom_field_pos = False
+ with_var_array = False
- for w_field in fields_w:
+ for i in range(len(fields_w)):
+ w_field = fields_w[i]
field_w = space.fixedview(w_field)
if not (2 <= len(field_w) <= 4):
raise OperationError(space.w_TypeError,
@@ -176,7 +178,11 @@
"duplicate field name '%s'", fname)
#
if ftype.size < 0:
- raise operationerrfmt(space.w_TypeError,
+ if (isinstance(ftype, ctypearray.W_CTypeArray) and fbitsize < 0
+ and (i == len(fields_w) - 1 or foffset != -1)):
+ with_var_array = True
+ else:
+ raise operationerrfmt(space.w_TypeError,
"field '%s.%s' has ctype '%s' of unknown size",
w_ctype.name, fname, ftype.name)
#
@@ -235,7 +241,8 @@
fields_list.append(fld)
fields_dict[fname] = fld
- boffset += ftype.size * 8
+ if ftype.size >= 0:
+ boffset += ftype.size * 8
prev_bitfield_size = 0
else:
@@ -359,6 +366,7 @@
w_ctype.fields_list = fields_list
w_ctype.fields_dict = fields_dict
w_ctype.custom_field_pos = custom_field_pos
+ w_ctype.with_var_array = with_var_array
# ____________________________________________________________
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -542,6 +542,7 @@
assert repr(a) == "<cdata 'int[3][5]' owning %d bytes>" % (
3*5*size_of_int(),)
assert repr(a + 0).startswith("<cdata 'int(*)[5]' 0x")
+ assert 0 + a == a + 0 != 1 + a == a + 1
assert repr(a[0]).startswith("<cdata 'int[5]' 0x")
assert repr((a + 0)[0]).startswith("<cdata 'int[5]' 0x")
assert repr(a[0] + 0).startswith("<cdata 'int *' 0x")
@@ -1631,9 +1632,6 @@
def test_void_errors():
py.test.raises(ValueError, alignof, new_void_type())
py.test.raises(TypeError, newp, new_pointer_type(new_void_type()), None)
- x = cast(new_pointer_type(new_void_type()), 42)
- py.test.raises(TypeError, "x + 1")
- py.test.raises(TypeError, "x - 1")
def test_too_many_items():
BChar = new_primitive_type("char")
@@ -2952,6 +2950,166 @@
_test_bitfield_details(flag=4)
+def test_struct_array_no_length():
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BArray = new_array_type(BIntP, None)
+ BStruct = new_struct_type("foo")
+ py.test.raises(TypeError, complete_struct_or_union,
+ BStruct, [('x', BArray),
+ ('y', BInt)])
+ #
+ BStruct = new_struct_type("foo")
+ complete_struct_or_union(BStruct, [('x', BInt),
+ ('y', BArray)])
+ assert sizeof(BStruct) == size_of_int()
+ d = BStruct.fields
+ assert len(d) == 2
+ assert d[0][0] == 'x'
+ assert d[0][1].type is BInt
+ assert d[0][1].offset == 0
+ assert d[0][1].bitshift == -1
+ assert d[0][1].bitsize == -1
+ assert d[1][0] == 'y'
+ assert d[1][1].type is BArray
+ assert d[1][1].offset == size_of_int()
+ assert d[1][1].bitshift == -1
+ assert d[1][1].bitsize == -1
+ #
+ p = newp(new_pointer_type(BStruct))
+ p.x = 42
+ assert p.x == 42
+ assert typeof(p.y) is BIntP
+ assert p.y == cast(BIntP, p) + 1
+ #
+ p = newp(new_pointer_type(BStruct), [100])
+ assert p.x == 100
+ #
+ # Tests for
+ # ffi.new("struct_with_var_array *", [field.., [the_array_items..]])
+ # ffi.new("struct_with_var_array *", [field.., array_size])
+ plist = []
+ for i in range(20):
+ if i % 2 == 0:
+ p = newp(new_pointer_type(BStruct), [100, [200, i, 400]])
+ else:
+ p = newp(new_pointer_type(BStruct), [100, 3])
+ p.y[1] = i
+ p.y[0] = 200
+ assert p.y[2] == 0
+ p.y[2] = 400
+ plist.append(p)
+ for i in range(20):
+ p = plist[i]
+ assert p.x == 100
+ assert p.y[0] == 200
+ assert p.y[1] == i
+ assert p.y[2] == 400
+ assert list(p.y[0:3]) == [200, i, 400]
+ #
+ # the following assignment works, as it normally would, for any array field
+ p.y = [500, 600]
+ assert list(p.y[0:3]) == [500, 600, 400]
+ #
+ # error cases
+ py.test.raises(TypeError, "p.y = cast(BIntP, 0)")
+ py.test.raises(TypeError, "p.y = 15")
+ py.test.raises(TypeError, "p.y = None")
+ #
+ # accepting this may be specified by the C99 standard,
+ # or a GCC strangeness...
+ BStruct2 = new_struct_type("bar")
+ complete_struct_or_union(BStruct2, [('f', BStruct),
+ ('n', BInt)])
+ p = newp(new_pointer_type(BStruct2), {'n': 42})
+ assert p.n == 42
+ #
+ # more error cases
+ py.test.raises(TypeError, newp, new_pointer_type(BStruct), [100, None])
+ BArray4 = new_array_type(BIntP, 4)
+ BStruct4 = new_struct_type("test4")
+ complete_struct_or_union(BStruct4, [('a', BArray4)]) # not varsized
+ py.test.raises(TypeError, newp, new_pointer_type(BStruct4), [None])
+ py.test.raises(TypeError, newp, new_pointer_type(BStruct4), [4])
+ p = newp(new_pointer_type(BStruct4), [[10, 20, 30]])
+ assert p.a[0] == 10
+ assert p.a[1] == 20
+ assert p.a[2] == 30
+ assert p.a[3] == 0
+
+def test_struct_array_no_length_explicit_position():
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BArray = new_array_type(BIntP, None)
+ BStruct = new_struct_type("foo")
+ complete_struct_or_union(BStruct, [('x', BArray, -1, 0), # actually 3 items
+ ('y', BInt, -1, 12)])
+ p = newp(new_pointer_type(BStruct), [[10, 20], 30])
+ assert p.x[0] == 10
+ assert p.x[1] == 20
+ assert p.x[2] == 0
+ assert p.y == 30
+ p = newp(new_pointer_type(BStruct), {'x': [40], 'y': 50})
+ assert p.x[0] == 40
+ assert p.x[1] == 0
+ assert p.x[2] == 0
+ assert p.y == 50
+ p = newp(new_pointer_type(BStruct), {'y': 60})
+ assert p.x[0] == 0
+ assert p.x[1] == 0
+ assert p.x[2] == 0
+ assert p.y == 60
+ #
+ # This "should" work too, allocating a larger structure
+ # (a bit strange in this case, but useful in general)
+ plist = []
+ for i in range(20):
+ p = newp(new_pointer_type(BStruct), [[10, 20, 30, 40, 50, 60, 70]])
+ plist.append(p)
+ for i in range(20):
+ p = plist[i]
+ assert p.x[0] == 10
+ assert p.x[1] == 20
+ assert p.x[2] == 30
+ assert p.x[3] == 40 == p.y
+ assert p.x[4] == 50
+ assert p.x[5] == 60
+ assert p.x[6] == 70
+
+def test_ass_slice():
+ BChar = new_primitive_type("char")
+ BArray = new_array_type(new_pointer_type(BChar), None)
+ p = newp(BArray, b"foobar")
+ p[2:5] = [b"*", b"Z", b"T"]
+ p[1:3] = b"XY"
+ assert list(p) == [b"f", b"X", b"Y", b"Z", b"T", b"r", b"\x00"]
+ py.test.raises(TypeError, "p[1:5] = u+'XYZT'")
+ py.test.raises(TypeError, "p[1:5] = [1, 2, 3, 4]")
+ #
+ BUniChar = new_primitive_type("wchar_t")
+ BArray = new_array_type(new_pointer_type(BUniChar), None)
+ p = newp(BArray, u+"foobar")
+ p[2:5] = [u+"*", u+"Z", u+"T"]
+ p[1:3] = u+"XY"
+ assert list(p) == [u+"f", u+"X", u+"Y", u+"Z", u+"T", u+"r", u+"\x00"]
+ py.test.raises(TypeError, "p[1:5] = b'XYZT'")
+ py.test.raises(TypeError, "p[1:5] = [1, 2, 3, 4]")
+
+def test_void_p_arithmetic():
+ BVoid = new_void_type()
+ BInt = new_primitive_type("intptr_t")
+ p = cast(new_pointer_type(BVoid), 100000)
+ assert int(cast(BInt, p)) == 100000
+ assert int(cast(BInt, p + 42)) == 100042
+ assert int(cast(BInt, p - (-42))) == 100042
+ assert (p + 42) - p == 42
+ q = cast(new_pointer_type(new_primitive_type("char")), 100000)
+ py.test.raises(TypeError, "p - q")
+ py.test.raises(TypeError, "q - p")
+ py.test.raises(TypeError, "p + cast(new_primitive_type('int'), 42)")
+ py.test.raises(TypeError, "p - cast(new_primitive_type('int'), 42)")
+
+
def test_version():
# this test is here mostly for PyPy
- assert __version__ == "0.7"
+ assert __version__ == "0.8"
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -410,7 +410,6 @@
def descr_getslice(self, space, w_i, w_j):
return space.getitem(self, space.newslice(w_i, w_j, space.w_None))
-
def descr_setitem(self, space, w_idx, w_item):
"x.__setitem__(i, y) <==> x[i]=y"
if space.isinstance_w(w_idx, space.w_slice):
@@ -869,9 +868,6 @@
self.buffer[i] = w_item.buffer[j]
j += 1
- # We can't look into this function until ptradd works with things (in the
- # JIT) other than rffi.CCHARP
- @jit.dont_look_inside
def delitem(self, space, i, j):
if i < 0:
i += self.len
@@ -907,16 +903,23 @@
lltype.free(oldbuffer, flavor='raw')
# Add and mul methods
-
def descr_add(self, space, w_other):
if not isinstance(w_other, W_Array):
return space.w_NotImplemented
a = mytype.w_class(space)
a.setlen(self.len + w_other.len, overallocate=False)
- for i in range(self.len):
- a.buffer[i] = self.buffer[i]
- for i in range(w_other.len):
- a.buffer[i + self.len] = w_other.buffer[i]
+ if self.len:
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, a.buffer),
+ rffi.cast(rffi.VOIDP, self.buffer),
+ self.len * mytype.bytes
+ )
+ if w_other.len:
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, rffi.ptradd(a.buffer, self.len)),
+ rffi.cast(rffi.VOIDP, w_other.buffer),
+ w_other.len * mytype.bytes
+ )
return a
def descr_inplace_add(self, space, w_other):
@@ -925,8 +928,12 @@
oldlen = self.len
otherlen = w_other.len
self.setlen(oldlen + otherlen)
- for i in range(otherlen):
- self.buffer[oldlen + i] = w_other.buffer[i]
+ if otherlen:
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, oldlen)),
+ rffi.cast(rffi.VOIDP, w_other.buffer),
+ otherlen * mytype.bytes
+ )
return self
def descr_mul(self, space, w_repeat):
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -519,10 +519,13 @@
# by converting nonnative byte order.
if self.is_scalar():
return space.wrap(0)
- s = self.get_dtype().name
- if not self.get_dtype().is_native():
- s = s[1:]
- dtype = interp_dtype.get_dtype_cache(space).dtypes_by_name[s]
+ if not self.get_dtype().is_flexible_type():
+ s = self.get_dtype().name
+ if not self.get_dtype().is_native():
+ s = s[1:]
+ dtype = interp_dtype.get_dtype_cache(space).dtypes_by_name[s]
+ else:
+ dtype = self.get_dtype()
contig = self.implementation.astype(space, dtype)
return contig.argsort(space, w_axis)
diff --git a/pypy/module/micronumpy/test/test_sorting.py b/pypy/module/micronumpy/test/test_sorting.py
--- a/pypy/module/micronumpy/test/test_sorting.py
+++ b/pypy/module/micronumpy/test/test_sorting.py
@@ -12,8 +12,7 @@
exp = sorted(range(len(exp)), key=exp.__getitem__)
c = a.copy()
res = a.argsort()
- assert (res == exp).all(), \
- 'a,res,dtype %r,%r,%r' % (a,res,dtype)
+ assert (res == exp).all(), '%r\n%r\n%r' % (a,res,exp)
assert (a == c).all() # not modified
a = arange(100, dtype=dtype)
@@ -60,11 +59,10 @@
for dtype in ['int', 'float', 'int16', 'float32', 'uint64',
'i2', complex]:
a = array([6, 4, -1, 3, 8, 3, 256+20, 100, 101], dtype=dtype)
- b = sorted(list(a))
- c = a.copy()
- a.sort()
- assert (a == b).all(), \
- 'a,orig,dtype %r,%r,%r' % (a,c,dtype)
+ exp = sorted(list(a))
+ res = a.copy()
+ res.sort()
+ assert (res == exp).all(), '%r\n%r\n%r' % (a,res,exp)
a = arange(100, dtype=dtype)
c = a.copy()
@@ -85,7 +83,6 @@
#assert (a == b).all(), \
# 'a,orig,dtype %r,%r,%r' % (a,c,dtype)
-
# tests from numpy/tests/test_multiarray.py
def test_sort_corner_cases(self):
# test ordering for floats and complex containing nans. It is only
@@ -307,7 +304,6 @@
assert (r == array([('a', 1), ('c', 3), ('b', 255), ('d', 258)],
dtype=mydtype)).all()
-
# tests from numpy/tests/test_regression.py
def test_sort_bigendian(self):
skip('not implemented yet')
@@ -325,3 +321,13 @@
y = fromstring("\x00\x01\x00\x02", dtype="S2")
x.sort(kind='q')
assert (x == y).all()
+
+ def test_string_mergesort(self):
+ import numpypy as np
+ import sys
+ x = np.array(['a'] * 32)
+ if '__pypy__' in sys.builtin_module_names:
+ exc = raises(NotImplementedError, "x.argsort(kind='m')")
+ assert 'non-numeric types' in exc.value.message
+ else:
+ assert (x.argsort(kind='m') == np.arange(32)).all()
diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py
--- a/pypy/module/mmap/interp_mmap.py
+++ b/pypy/module/mmap/interp_mmap.py
@@ -163,6 +163,8 @@
if step == 0: # index only
return space.wrap(self.mmap.getitem(start))
elif step == 1:
+ if stop - start < 0:
+ return space.wrap("")
return space.wrap(self.mmap.getslice(start, stop - start))
else:
res = "".join([self.mmap.getitem(i)
diff --git a/pypy/module/mmap/test/test_mmap.py b/pypy/module/mmap/test/test_mmap.py
--- a/pypy/module/mmap/test/test_mmap.py
+++ b/pypy/module/mmap/test/test_mmap.py
@@ -525,6 +525,8 @@
m = mmap(f.fileno(), 6)
assert m[-3:7] == "bar"
+ assert m[1:0:1] == ""
+
f.close()
def test_sequence_type(self):
diff --git a/pypy/module/posix/__init__.py b/pypy/module/posix/__init__.py
--- a/pypy/module/posix/__init__.py
+++ b/pypy/module/posix/__init__.py
@@ -131,6 +131,11 @@
if hasattr(os, 'fpathconf'):
interpleveldefs['fpathconf'] = 'interp_posix.fpathconf'
interpleveldefs['pathconf_names'] = 'space.wrap(os.pathconf_names)'
+ if hasattr(os, 'pathconf'):
+ interpleveldefs['pathconf'] = 'interp_posix.pathconf'
+ if hasattr(os, 'confstr'):
+ interpleveldefs['confstr'] = 'interp_posix.confstr'
+ interpleveldefs['confstr_names'] = 'space.wrap(os.confstr_names)'
if hasattr(os, 'ttyname'):
interpleveldefs['ttyname'] = 'interp_posix.ttyname'
if hasattr(os, 'getloadavg'):
@@ -155,7 +160,9 @@
for name in ['setsid', 'getuid', 'geteuid', 'getgid', 'getegid', 'setuid',
'seteuid', 'setgid', 'setegid', 'getgroups', 'getpgrp',
'setpgrp', 'getppid', 'getpgid', 'setpgid', 'setreuid',
- 'setregid', 'getsid', 'setsid', 'fstatvfs', 'statvfs']:
+ 'setregid', 'getsid', 'setsid', 'fstatvfs', 'statvfs',
+ 'setgroups', 'initgroups', 'tcgetpgrp', 'tcsetpgrp',
+ 'getresuid', 'getresgid', 'setresuid', 'setresgid']:
if hasattr(os, name):
interpleveldefs[name] = 'interp_posix.%s' % (name,)
# not visible via os, inconsistency in nt:
diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -987,7 +987,39 @@
Return list of supplemental group IDs for the process.
"""
- return space.newlist([space.wrap(e) for e in os.getgroups()])
+ try:
+ list = os.getgroups()
+ except OSError, e:
+ raise wrap_oserror(space, e)
+ return space.newlist([space.wrap(e) for e in list])
+
+def setgroups(space, w_list):
+ """ setgroups(list)
+
+ Set the groups of the current process to list.
+ """
+ list = []
+ for w_gid in space.unpackiterable(w_list):
+ gid = space.int_w(w_gid)
+ check_uid_range(space, gid)
+ list.append(gid)
+ try:
+ os.setgroups(list[:])
+ except OSError, e:
+ raise wrap_oserror(space, e)
+
+ at unwrap_spec(username=str, gid=c_gid_t)
+def initgroups(space, username, gid):
+ """ initgroups(username, gid) -> None
+
+ Call the system initgroups() to initialize the group access list with all of
+ the groups of which the specified username is a member, plus the specified
+ group id.
+ """
+ try:
+ os.initgroups(username, gid)
+ except OSError, e:
+ raise wrap_oserror(space, e)
def getpgrp(space):
""" getpgrp() -> pgrp
@@ -1089,6 +1121,77 @@
raise wrap_oserror(space, e)
return space.w_None
+ at unwrap_spec(fd=c_int)
+def tcgetpgrp(space, fd):
+ """ tcgetpgrp(fd) -> pgid
+
+ Return the process group associated with the terminal given by a fd.
+ """
+ try:
+ pgid = os.tcgetpgrp(fd)
+ except OSError, e:
+ raise wrap_oserror(space, e)
+ return space.wrap(pgid)
+
+ at unwrap_spec(fd=c_int, pgid=c_gid_t)
+def tcsetpgrp(space, fd, pgid):
+ """ tcsetpgrp(fd, pgid)
+
+ Set the process group associated with the terminal given by a fd.
+ """
+ try:
+ os.tcsetpgrp(fd, pgid)
+ except OSError, e:
+ raise wrap_oserror(space, e)
+
+def getresuid(space):
+ """ getresuid() -> (ruid, euid, suid)
+
+ Get tuple of the current process's real, effective, and saved user ids.
+ """
+ try:
+ (ruid, euid, suid) = os.getresuid()
+ except OSError, e:
+ raise wrap_oserror(space, e)
+ return space.newtuple([space.wrap(ruid),
+ space.wrap(euid),
+ space.wrap(suid)])
+
+def getresgid(space):
+ """ getresgid() -> (rgid, egid, sgid)
+
+ Get tuple of the current process's real, effective, and saved group ids.
+ """
+ try:
+ (rgid, egid, sgid) = os.getresgid()
+ except OSError, e:
+ raise wrap_oserror(space, e)
+ return space.newtuple([space.wrap(rgid),
+ space.wrap(egid),
+ space.wrap(sgid)])
+
+ at unwrap_spec(ruid=c_uid_t, euid=c_uid_t, suid=c_uid_t)
+def setresuid(space, ruid, euid, suid):
+ """ setresuid(ruid, euid, suid)
+
+ Set the current process's real, effective, and saved user ids.
+ """
+ try:
+ os.setresuid(ruid, euid, suid)
+ except OSError, e:
+ raise wrap_oserror(space, e)
+
+ at unwrap_spec(rgid=c_gid_t, egid=c_gid_t, sgid=c_gid_t)
+def setresgid(space, rgid, egid, sgid):
+ """ setresgid(rgid, egid, sgid)
+
+ Set the current process's real, effective, and saved group ids.
+ """
+ try:
+ os.setresgid(rgid, egid, sgid)
+ except OSError, e:
+ raise wrap_oserror(space, e)
+
def declare_new_w_star(name):
if name in RegisterOs.w_star_returning_int:
@unwrap_spec(status=c_int)
@@ -1130,15 +1233,37 @@
def sysconf(space, w_name):
num = confname_w(space, w_name, os.sysconf_names)
- return space.wrap(os.sysconf(num))
+ try:
+ res = os.sysconf(num)
+ except OSError, e:
+ raise wrap_oserror(space, e)
+ return space.wrap(res)
@unwrap_spec(fd=c_int)
def fpathconf(space, fd, w_name):
num = confname_w(space, w_name, os.pathconf_names)
try:
- return space.wrap(os.fpathconf(fd, num))
+ res = os.fpathconf(fd, num)
except OSError, e:
raise wrap_oserror(space, e)
+ return space.wrap(res)
+
+ at unwrap_spec(path='str0')
+def pathconf(space, path, w_name):
+ num = confname_w(space, w_name, os.pathconf_names)
+ try:
+ res = os.pathconf(path, num)
+ except OSError, e:
+ raise wrap_oserror(space, e)
+ return space.wrap(res)
+
+def confstr(space, w_name):
+ num = confname_w(space, w_name, os.confstr_names)
+ try:
+ res = os.confstr(num)
+ except OSError, e:
+ raise wrap_oserror(space, e)
+ return space.wrap(res)
@unwrap_spec(path='str0', uid=c_uid_t, gid=c_gid_t)
def chown(space, path, uid, gid):
diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -78,6 +78,11 @@
cls.w_sysconf_name = space.wrap(sysconf_name)
cls.w_sysconf_value = space.wrap(os.sysconf_names[sysconf_name])
cls.w_sysconf_result = space.wrap(os.sysconf(sysconf_name))
+ if hasattr(os, 'confstr'):
+ confstr_name = os.confstr_names.keys()[0]
+ cls.w_confstr_name = space.wrap(confstr_name)
+ cls.w_confstr_value = space.wrap(os.confstr_names[confstr_name])
+ cls.w_confstr_result = space.wrap(os.confstr(confstr_name))
cls.w_SIGABRT = space.wrap(signal.SIGABRT)
cls.w_python = space.wrap(sys.executable)
if hasattr(os, 'major'):
@@ -616,6 +621,30 @@
os = self.posix
assert os.getgroups() == self.getgroups
+ if hasattr(os, 'setgroups'):
+ def test_os_setgroups(self):
+ os = self.posix
+ raises(TypeError, os.setgroups, [2, 5, "hello"])
+ try:
+ os.setgroups(os.getgroups())
+ except OSError:
+ pass
+
+ if hasattr(os, 'initgroups'):
+ def test_os_initgroups(self):
+ os = self.posix
+ raises(OSError, os.initgroups, "crW2hTQC", 100)
+
+ if hasattr(os, 'tcgetpgrp'):
+ def test_os_tcgetpgrp(self):
+ os = self.posix
+ raises(OSError, os.tcgetpgrp, 9999)
+
+ if hasattr(os, 'tcsetpgrp'):
+ def test_os_tcsetpgrp(self):
+ os = self.posix
+ raises(OSError, os.tcsetpgrp, 9999, 1)
+
if hasattr(os, 'getpgid'):
def test_os_getpgid(self):
os = self.posix
@@ -634,6 +663,30 @@
assert os.getsid(0) == self.getsid0
raises(OSError, os.getsid, -100000)
+ if hasattr(os, 'getresuid'):
+ def test_os_getresuid(self):
+ os = self.posix
+ res = os.getresuid()
+ assert len(res) == 3
+
+ if hasattr(os, 'getresgid'):
+ def test_os_getresgid(self):
+ os = self.posix
+ res = os.getresgid()
+ assert len(res) == 3
+
+ if hasattr(os, 'setresuid'):
+ def test_os_setresuid(self):
+ os = self.posix
+ a, b, c = os.getresuid()
+ os.setresuid(a, b, c)
+
+ if hasattr(os, 'setresgid'):
+ def test_os_setresgid(self):
+ os = self.posix
+ a, b, c = os.getresgid()
+ os.setresgid(a, b, c)
+
if hasattr(os, 'sysconf'):
def test_os_sysconf(self):
os = self.posix
@@ -652,6 +705,25 @@
raises(OSError, os.fpathconf, -1, "PC_PIPE_BUF")
raises(ValueError, os.fpathconf, 1, "##")
+ if hasattr(os, 'pathconf'):
+ def test_os_pathconf(self):
+ os = self.posix
+ assert os.pathconf("/tmp", "PC_NAME_MAX") >= 31
+ # Linux: the following gets 'No such file or directory'
+ raises(OSError, os.pathconf, "", "PC_PIPE_BUF")
+ raises(ValueError, os.pathconf, "/tmp", "##")
+
+ if hasattr(os, 'confstr'):
+ def test_os_confstr(self):
+ os = self.posix
+ assert os.confstr(self.confstr_value) == self.confstr_result
+ assert os.confstr(self.confstr_name) == self.confstr_result
+ assert os.confstr_names[self.confstr_name] == self.confstr_value
+
+ def test_os_confstr_error(self):
+ os = self.posix
+ raises(ValueError, os.confstr, "!@#$%!#$!@#")
+
if hasattr(os, 'wait'):
def test_os_wait(self):
os = self.posix
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -228,7 +228,7 @@
except ImportError:
sys.stderr.write('SKIP: cannot import cffi\n')
return 0
-
+
ffi = cffi.FFI()
ffi.cdef("""
@@ -301,5 +301,30 @@
f(1)
#
libm_name = get_libm_name(sys.platform)
- log = self.run(main, [libm_name])
+ self.run(main, [libm_name])
# assert did not crash
+
+ def test_cffi_init_struct_with_list(self):
+ def main(n):
+ import sys
+ try:
+ import cffi
+ except ImportError:
+ sys.stderr.write('SKIP: cannot import cffi\n')
+ return 0
+
+ ffi = cffi.FFI()
+ ffi.cdef("""
+ struct s {
+ int x;
+ int y;
+ int z;
+ };
+ """)
+
+ for i in xrange(n):
+ ffi.new("struct s *", [i, i, i])
+
+ log = self.run(main, [300])
+ loop, = log.loops_by_filename(self.filepath)
+ assert False, "XXX: fill this in"
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
@@ -568,8 +568,6 @@
def _create_new_type(space, w_typetype, w_name, w_bases, w_dict):
# this is in its own function because we want the special case 'type(x)'
# above to be seen by the jit.
- from pypy.objspace.std.typeobject import W_TypeObject
-
if w_bases is None or w_dict is None:
raise OperationError(space.w_TypeError, space.wrap("type() takes 1 or 3 arguments"))
@@ -611,7 +609,6 @@
return w_type
def _precheck_for_new(space, w_type):
- from pypy.objspace.std.typeobject import W_TypeObject
if not isinstance(w_type, W_TypeObject):
raise operationerrfmt(space.w_TypeError, "X is not a type object (%T)",
w_type)
@@ -620,7 +617,6 @@
# ____________________________________________________________
def _check(space, w_type, w_msg=None):
- from pypy.objspace.std.typeobject import W_TypeObject
if not isinstance(w_type, W_TypeObject):
if w_msg is None:
w_msg = space.wrap("descriptor is for 'type'")
@@ -653,7 +649,6 @@
return space.newtuple(w_type.bases_w)
def mro_subclasses(space, w_type, temp):
- from pypy.objspace.std.typeobject import W_TypeObject, compute_mro
temp.append((w_type, w_type.mro_w))
compute_mro(w_type)
for w_sc in w_type.get_subclasses():
@@ -662,9 +657,6 @@
def descr_set__bases__(space, w_type, w_value):
# this assumes all app-level type objects are W_TypeObject
- from pypy.objspace.std.typeobject import (W_TypeObject, get_parent_layout,
- check_and_find_best_base, is_mro_purely_of_types)
-
w_type = _check(space, w_type)
if not w_type.is_heaptype():
raise operationerrfmt(space.w_TypeError,
@@ -728,7 +720,6 @@
assert w_type.w_same_layout_as is get_parent_layout(w_type) # invariant
def descr__base(space, w_type):
- from pypy.objspace.std.typeobject import find_best_base
w_type = _check(space, w_type)
return find_best_base(space, w_type.bases_w)
diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py
--- a/rpython/jit/backend/x86/callbuilder.py
+++ b/rpython/jit/backend/x86/callbuilder.py
@@ -304,8 +304,12 @@
except IndexError:
return None
if hint in self.DONT_MOVE_GPR:
- self.ARGUMENTS_GPR[i] = hint
- res = hint
+ for j in range(i):
+ if hint is self.ARGUMENTS_GPR[j]:
+ break
+ else:
+ self.ARGUMENTS_GPR[i] = hint
+ res = hint
return res
def _unused_xmm(self):
diff --git a/rpython/jit/backend/x86/test/test_callbuilder.py b/rpython/jit/backend/x86/test/test_callbuilder.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/x86/test/test_callbuilder.py
@@ -0,0 +1,33 @@
+from rpython.jit.backend.x86 import callbuilder
+from rpython.jit.backend.x86.regloc import esi, edi, ebx, ecx, ImmedLoc
+
+
+class FakeAssembler:
+ mc = None
+ class _regalloc:
+ class rm:
+ free_regs = [ebx]
+
+ def __init__(self):
+ self._log = []
+
+ def _is_asmgcc(self):
+ return False
+
+ def regalloc_mov(self, src, dst):
+ self._log.append(('mov', src, dst))
+
+
+def test_base_case():
+ asm = FakeAssembler()
+ cb = callbuilder.CallBuilder64(asm, ImmedLoc(12345), [ebx, ebx])
+ cb.prepare_arguments()
+ assert asm._log == [('mov', ebx, edi),
+ ('mov', ebx, esi)]
+
+def test_bug_call_release_gil():
+ asm = FakeAssembler()
+ cb = callbuilder.CallBuilder64(asm, ImmedLoc(12345), [ebx, ebx])
+ cb.select_call_release_gil_mode()
+ cb.prepare_arguments()
+ assert asm._log == [('mov', ebx, ecx)]
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
@@ -1162,10 +1162,19 @@
v_result)
def rewrite_op_direct_ptradd(self, op):
- # xxx otherwise, not implemented:
- assert op.args[0].concretetype == rffi.CCHARP
+ v_shift = op.args[1]
+ assert v_shift.concretetype == lltype.Signed
+ ops = []
#
- return SpaceOperation('int_add', [op.args[0], op.args[1]], op.result)
+ if op.args[0].concretetype != rffi.CCHARP:
+ v_prod = varoftype(lltype.Signed)
+ by = llmemory.sizeof(op.args[0].concretetype.TO.OF)
+ c_by = Constant(by, lltype.Signed)
+ ops.append(SpaceOperation('int_mul', [v_shift, c_by], v_prod))
+ v_shift = v_prod
+ #
+ ops.append(SpaceOperation('int_add', [op.args[0], v_shift], op.result))
+ return ops
# ----------
# Long longs, for 32-bit only. Supported operations are left unmodified,
diff --git a/rpython/jit/codewriter/test/test_flatten.py b/rpython/jit/codewriter/test/test_flatten.py
--- a/rpython/jit/codewriter/test/test_flatten.py
+++ b/rpython/jit/codewriter/test/test_flatten.py
@@ -993,6 +993,16 @@
int_return %i2
""", transform=True)
+ def test_direct_ptradd_2(self):
+ def f(p, n):
+ return lltype.direct_ptradd(p, n + 2)
+ self.encoding_test(f, [lltype.nullptr(rffi.SHORTP.TO), 123], """
+ int_add %i1, $2 -> %i2
+ int_mul %i2, $<ItemOffset <SHORT> 1> -> %i3
+ int_add %i0, %i3 -> %i4
+ int_return %i4
+ """, transform=True)
+
def test_convert_float_bytes(self):
from rpython.rlib.longlong2float import float2longlong, longlong2float
def f(x):
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
@@ -514,7 +514,8 @@
#
if metainterp_sd.warmrunnerdesc is not None: # for tests
jitcounter = metainterp_sd.warmrunnerdesc.jitcounter
- self.status = jitcounter.fetch_next_index() << self.ST_SHIFT
+ index = jitcounter.in_second_half(jitcounter.fetch_next_index())
+ self.status = index << self.ST_SHIFT
def make_a_counter_per_value(self, guard_value_op):
assert guard_value_op.getopnum() == rop.GUARD_VALUE
@@ -598,7 +599,7 @@
hash = (current_object_addr_as_int(self) * 777767777 +
intval * 1442968193)
- index = jitcounter.get_index(hash)
+ index = jitcounter.in_second_half(jitcounter.get_index(hash))
#
increment = jitdriver_sd.warmstate.increment_trace_eagerness
return jitcounter.tick(index, increment)
diff --git a/rpython/jit/metainterp/counter.py b/rpython/jit/metainterp/counter.py
--- a/rpython/jit/metainterp/counter.py
+++ b/rpython/jit/metainterp/counter.py
@@ -18,11 +18,20 @@
while (UINT32MAX >> self.shift) != size - 1:
self.shift += 1
assert self.shift < 999, "size is not a power of two <= 2**31"
- self.timetable = lltype.malloc(rffi.CArray(rffi.FLOAT), size,
+ #
+ # The table of timings. The first half is used for starting the
+ # compilation of new loops. The second half is used for turning
+ # failing guards into bridges. The two halves are split to avoid
+ # too much interference.
+ self.timetablesize = size * 2
+ self.timetable = lltype.malloc(rffi.CArray(rffi.FLOAT),
+ self.timetablesize,
flavor='raw', zero=True,
track_allocation=False)
+ self._nextindex = r_uint(0)
+ #
+ # The table of JitCell entries, recording already-compiled loops
self.celltable = [None] * size
- self._nextindex = r_uint(0)
#
if translator is not None:
class Glob:
@@ -61,6 +70,10 @@
self._nextindex = (result + 1) & self.get_index(-1)
return result
+ def in_second_half(self, index):
+ assert index < r_uint(self.size)
+ return self.size + index
+
def tick(self, index, increment):
counter = float(self.timetable[index]) + increment
if counter < 1.0:
@@ -112,7 +125,7 @@
# important in corner cases where we would suddenly compile more
# than one loop because all counters reach the bound at the same
# time, but where compiling all but the first one is pointless.
- size = self.size
+ size = self.timetablesize
pypy__decay_jit_counters(self.timetable, self.decay_by_mult, size)
@@ -152,6 +165,10 @@
"NOT_RPYTHON"
pass
+ def in_second_half(self, index):
+ "NOT_RPYTHON"
+ return index + 12345
+
def _clear_all(self):
self.timetable.clear()
self.celltable.clear()
diff --git a/rpython/jit/metainterp/heapcache.py b/rpython/jit/metainterp/heapcache.py
--- a/rpython/jit/metainterp/heapcache.py
+++ b/rpython/jit/metainterp/heapcache.py
@@ -96,8 +96,13 @@
idx += 1
def _escape(self, box):
- if box in self.new_boxes:
- self.new_boxes[box] = False
+ try:
+ unescaped = self.new_boxes[box]
+ except KeyError:
+ pass
+ else:
+ if unescaped:
+ self.new_boxes[box] = False
try:
deps = self.dependencies.pop(box)
except KeyError:
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -5125,18 +5125,39 @@
def test_str_copy_virtual_src_concrete_dst(self):
ops = """
[p0]
- p1 = newstr(1)
+ p1 = newstr(2)
strsetitem(p1, 0, 101)
- copystrcontent(p1, p0, 0, 0, 1)
+ strsetitem(p1, 1, 102)
+ copystrcontent(p1, p0, 0, 0, 2)
finish(p0)
"""
expected = """
[p0]
strsetitem(p0, 0, 101)
+ strsetitem(p0, 1, 102)
finish(p0)
"""
self.optimize_strunicode_loop(ops, expected)
+ def test_str_copy_bug1(self):
+ ops = """
+ [i0]
+ p1 = newstr(1)
+ strsetitem(p1, 0, i0)
+ p2 = newstr(1)
+ escape(p2)
+ copystrcontent(p1, p2, 0, 0, 1)
+ finish()
+ """
+ expected = """
+ [i0]
+ p2 = newstr(1)
+ escape(p2)
+ strsetitem(p2, 0, i0)
+ finish()
+ """
+ self.optimize_strunicode_loop(ops, expected)
+
def test_call_pure_vstring_const(self):
py.test.skip("implement me")
ops = """
diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py
--- a/rpython/jit/metainterp/optimizeopt/vstring.py
+++ b/rpython/jit/metainterp/optimizeopt/vstring.py
@@ -154,6 +154,7 @@
return self._chars[index] # may return None!
def setitem(self, index, charvalue):
+ assert self.is_virtual()
assert isinstance(charvalue, optimizer.OptValue)
assert self._chars[index] is None, (
"setitem() on an already-initialized location")
@@ -512,29 +513,28 @@
srcstart = self.getvalue(op.getarg(2))
dststart = self.getvalue(op.getarg(3))
length = self.getvalue(op.getarg(4))
+ dst_virtual = (isinstance(dst, VStringPlainValue) and dst.is_virtual())
if length.is_constant() and length.box.getint() == 0:
return
elif ((src.is_virtual() or src.is_constant()) and
srcstart.is_constant() and dststart.is_constant() and
- length.is_constant()):
+ length.is_constant() and
+ (length.force_box(self).getint() < 20 or (src.is_virtual() and dst_virtual))):
src_start = srcstart.force_box(self).getint()
dst_start = dststart.force_box(self).getint()
- # 'length' must be <= MAX_CONST_LEN here, because 'dst' is a
- # VStringPlainValue, which is limited to MAX_CONST_LEN.
actual_length = length.force_box(self).getint()
- assert actual_length <= MAX_CONST_LEN
for index in range(actual_length):
vresult = self.strgetitem(src, optimizer.ConstantValue(ConstInt(index + src_start)), mode)
- if isinstance(dst, VStringPlainValue):
+ if dst_virtual:
dst.setitem(index + dst_start, vresult)
else:
- op = ResOperation(mode.STRSETITEM, [
- op.getarg(1),
+ new_op = ResOperation(mode.STRSETITEM, [
+ dst.force_box(self),
ConstInt(index + dst_start),
vresult.force_box(self),
], None)
- self.emit_operation(op)
+ self.emit_operation(new_op)
else:
copy_str_content(self,
src.force_box(self),
diff --git a/rpython/rlib/rstring.py b/rpython/rlib/rstring.py
--- a/rpython/rlib/rstring.py
+++ b/rpython/rlib/rstring.py
@@ -371,6 +371,7 @@
self._grow(times)
def append_charpsize(self, s, size):
+ assert size >= 0
l = []
for i in xrange(size):
l.append(s[i])
diff --git a/rpython/rtyper/lltypesystem/rbytearray.py b/rpython/rtyper/lltypesystem/rbytearray.py
--- a/rpython/rtyper/lltypesystem/rbytearray.py
+++ b/rpython/rtyper/lltypesystem/rbytearray.py
@@ -8,10 +8,10 @@
def mallocbytearray(size):
return lltype.malloc(BYTEARRAY, size)
-_, copy_bytearray_contents = rstr._new_copy_contents_fun(BYTEARRAY, BYTEARRAY,
+_, _, copy_bytearray_contents = rstr._new_copy_contents_fun(BYTEARRAY, BYTEARRAY,
lltype.Char,
'bytearray')
-_, copy_bytearray_contents_from_str = rstr._new_copy_contents_fun(rstr.STR,
+_, _, copy_bytearray_contents_from_str = rstr._new_copy_contents_fun(rstr.STR,
BYTEARRAY,
lltype.Char,
'bytearray_from_str')
diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py
--- a/rpython/rtyper/module/ll_os.py
+++ b/rpython/rtyper/module/ll_os.py
@@ -129,10 +129,6 @@
('tms_cutime', rffi.INT),
('tms_cstime', rffi.INT)])
- GID_T = platform.SimpleType('gid_t', rffi.INT)
- #TODO right now is used only in getgroups, may need to update other
- #functions like setgid
-
# For now we require off_t to be the same size as LONGLONG, which is the
# interface required by callers of functions that thake an argument of type
# off_t
@@ -655,6 +651,46 @@
return extdef([int, int], int, "ll_os.ll_fpathconf",
llimpl=fpathconf_llimpl)
+ @registering_if(os, 'pathconf')
+ def register_os_pathconf(self):
+ c_pathconf = self.llexternal('pathconf',
+ [rffi.CCHARP, rffi.INT], rffi.LONG)
+
+ def pathconf_llimpl(path, i):
+ rposix.set_errno(0)
+ res = c_pathconf(path, i)
+ if res == -1:
+ errno = rposix.get_errno()
+ if errno != 0:
+ raise OSError(errno, "pathconf failed")
+ return res
+ return extdef([str0, int], int, "ll_os.ll_pathconf",
+ llimpl=pathconf_llimpl)
+
+ @registering_if(os, 'confstr')
+ def register_os_confstr(self):
+ c_confstr = self.llexternal('confstr', [rffi.INT, rffi.CCHARP,
+ rffi.SIZE_T], rffi.SIZE_T)
+
+ def confstr_llimpl(i):
+ rposix.set_errno(0)
+ n = c_confstr(i, lltype.nullptr(rffi.CCHARP.TO), 0)
+ n = rffi.cast(lltype.Signed, n)
+ if n > 0:
+ buf = lltype.malloc(rffi.CCHARP.TO, n, flavor='raw')
+ try:
+ c_confstr(i, buf, n)
+ return rffi.charp2strn(buf, n)
+ finally:
+ lltype.free(buf, flavor='raw')
+ else:
+ errno = rposix.get_errno()
+ if errno != 0:
+ raise OSError(errno, "confstr failed")
+ return None
+ return extdef([int], SomeString(can_be_None=True),
+ "ll_os.ll_confstr", llimpl=confstr_llimpl)
+
@registering_if(os, 'getuid')
def register_os_getuid(self):
return self.extdef_for_os_function_returning_int('getuid')
@@ -693,7 +729,7 @@
@registering_if(os, 'getgroups')
def register_os_getgroups(self):
- GP = rffi.CArrayPtr(self.GID_T)
+ GP = rffi.CArrayPtr(rffi.PID_T)
c_getgroups = self.llexternal('getgroups', [rffi.INT, GP], rffi.INT)
def getgroups_llimpl():
@@ -702,16 +738,50 @@
groups = lltype.malloc(GP.TO, n, flavor='raw')
try:
n = c_getgroups(n, groups)
- result = [groups[i] for i in range(n)]
+ result = [rffi.cast(lltype.Signed, groups[i])
+ for i in range(n)]
finally:
lltype.free(groups, flavor='raw')
if n >= 0:
return result
raise OSError(rposix.get_errno(), "os_getgroups failed")
- return extdef([], [self.GID_T], llimpl=getgroups_llimpl,
+ return extdef([], [int], llimpl=getgroups_llimpl,
export_name="ll_os.ll_getgroups")
+ @registering_if(os, 'setgroups')
+ def register_os_setgroups(self):
+ GP = rffi.CArrayPtr(rffi.PID_T)
+ c_setgroups = self.llexternal('setgroups', [rffi.SIZE_T, GP], rffi.INT)
+
+ def setgroups_llimpl(list):
+ n = len(list)
+ groups = lltype.malloc(GP.TO, n, flavor='raw')
+ try:
+ for i in range(n):
+ groups[i] = rffi.cast(rffi.PID_T, list[i])
+ n = c_setgroups(rffi.cast(rffi.SIZE_T, n), groups)
+ finally:
+ lltype.free(groups, flavor='raw')
+ if n != 0:
+ raise OSError(rposix.get_errno(), "os_setgroups failed")
+
+ return extdef([[int]], None, llimpl=setgroups_llimpl,
+ export_name="ll_os.ll_setgroups")
+
+ @registering_if(os, 'initgroups')
+ def register_os_initgroups(self):
+ c_initgroups = self.llexternal('initgroups',
+ [rffi.CCHARP, rffi.PID_T], rffi.INT)
+
+ def initgroups_llimpl(user, group):
+ n = c_initgroups(user, rffi.cast(rffi.PID_T, group))
+ if n != 0:
+ raise OSError(rposix.get_errno(), "os_initgroups failed")
+
+ return extdef([str, int], None, llimpl=initgroups_llimpl,
+ export_name="ll_os.ll_initgroups")
+
@registering_if(os, 'getpgrp')
def register_os_getpgrp(self):
name = 'getpgrp'
@@ -747,6 +817,35 @@
else:
return self.extdef_for_os_function_accepting_0int(name)
+ @registering_if(os, 'tcgetpgrp')
+ def register_os_tcgetpgrp(self):
+ c_tcgetpgrp = self.llexternal('tcgetpgrp', [rffi.INT], rffi.PID_T)
+
+ def c_tcgetpgrp_llimpl(fd):
+ res = c_tcgetpgrp(rffi.cast(rffi.INT, fd))
+ res = rffi.cast(lltype.Signed, res)
+ if res == -1:
+ raise OSError(rposix.get_errno(), "tcgetpgrp failed")
+ return res
+
+ return extdef([int], int, llimpl=c_tcgetpgrp_llimpl,
+ export_name='ll_os.ll_os_tcgetpgrp')
+
+ @registering_if(os, 'tcsetpgrp')
+ def register_os_tcsetpgrp(self):
+ c_tcsetpgrp = self.llexternal('tcsetpgrp', [rffi.INT, rffi.PID_T],
+ rffi.INT)
+
+ def c_tcsetpgrp_llimpl(fd, pgrp):
+ res = c_tcsetpgrp(rffi.cast(rffi.INT, fd),
+ rffi.cast(rffi.PID_T, pgrp))
+ res = rffi.cast(lltype.Signed, res)
+ if res == -1:
+ raise OSError(rposix.get_errno(), "tcsetpgrp failed")
+
+ return extdef([int, int], None, llimpl=c_tcsetpgrp_llimpl,
+ export_name='ll_os.ll_os_tcsetpgrp')
+
@registering_if(os, 'getppid')
def register_os_getppid(self):
return self.extdef_for_os_function_returning_int('getppid')
@@ -775,6 +874,76 @@
def register_os_setsid(self):
return self.extdef_for_os_function_returning_int('setsid')
+ @registering_if(os, 'getresuid')
+ def register_os_getresuid(self):
+ c_getresuid = self.llexternal('getresuid', [rffi.INTP] * 3, rffi.INT)
+
+ def c_getresuid_llimpl():
+ out = lltype.malloc(rffi.INTP.TO, 3, flavor='raw')
+ try:
+ res = c_getresuid(rffi.ptradd(out, 0),
+ rffi.ptradd(out, 1),
+ rffi.ptradd(out, 2))
+ res = rffi.cast(lltype.Signed, res)
+ if res == -1:
+ raise OSError(rposix.get_errno(), "getresuid failed")
+ return (rffi.cast(lltype.Signed, out[0]),
+ rffi.cast(lltype.Signed, out[1]),
+ rffi.cast(lltype.Signed, out[2]))
+ finally:
+ lltype.free(out, flavor='raw')
+
+ return extdef([], (int, int, int), llimpl=c_getresuid_llimpl,
+ export_name='ll_os.ll_os_getresuid')
+
+ @registering_if(os, 'getresgid')
+ def register_os_getresgid(self):
+ c_getresgid = self.llexternal('getresgid', [rffi.INTP] * 3, rffi.INT)
+
+ def c_getresgid_llimpl():
+ out = lltype.malloc(rffi.INTP.TO, 3, flavor='raw')
+ try:
+ res = c_getresgid(rffi.ptradd(out, 0),
+ rffi.ptradd(out, 1),
+ rffi.ptradd(out, 2))
+ res = rffi.cast(lltype.Signed, res)
+ if res == -1:
+ raise OSError(rposix.get_errno(), "getresgid failed")
+ return (rffi.cast(lltype.Signed, out[0]),
+ rffi.cast(lltype.Signed, out[1]),
+ rffi.cast(lltype.Signed, out[2]))
+ finally:
+ lltype.free(out, flavor='raw')
+
+ return extdef([], (int, int, int), llimpl=c_getresgid_llimpl,
+ export_name='ll_os.ll_os_getresgid')
+
+ @registering_if(os, 'setresuid')
+ def register_os_setresuid(self):
+ c_setresuid = self.llexternal('setresuid', [rffi.INT] * 3, rffi.INT)
+
+ def c_setresuid_llimpl(ruid, euid, suid):
+ res = c_setresuid(ruid, euid, suid)
+ res = rffi.cast(lltype.Signed, res)
+ if res == -1:
+ raise OSError(rposix.get_errno(), "setresuid failed")
+
+ return extdef([int, int, int], None, llimpl=c_setresuid_llimpl,
+ export_name='ll_os.ll_os_setresuid')
+
+ @registering_if(os, 'setresgid')
+ def register_os_setresgid(self):
+ c_setresgid = self.llexternal('setresgid', [rffi.INT] * 3, rffi.INT)
+
+ def c_setresgid_llimpl(rgid, egid, sgid):
+ res = c_setresgid(rgid, egid, sgid)
+ res = rffi.cast(lltype.Signed, res)
+ if res == -1:
+ raise OSError(rposix.get_errno(), "setresgid failed")
+
+ return extdef([int, int, int], None, llimpl=c_setresgid_llimpl,
+ export_name='ll_os.ll_os_setresgid')
+
@registering_str_unicode(os.open)
def register_os_open(self, traits):
os_open = self.llexternal(traits.posix_function_name('open'),
diff --git a/rpython/rtyper/module/test/test_posix.py b/rpython/rtyper/module/test/test_posix.py
--- a/rpython/rtyper/module/test/test_posix.py
+++ b/rpython/rtyper/module/test/test_posix.py
@@ -1,5 +1,6 @@
import py
from rpython.rtyper.test.tool import BaseRtypingTest
+from rpython.rtyper.annlowlevel import hlstr
from rpython.tool.udir import udir
from rpython.rlib.rarithmetic import is_valid_int
@@ -176,6 +177,27 @@
return os.sysconf(i)
assert self.interpret(f, [13]) == f(13)
+ if hasattr(os, 'confstr'):
+ def test_os_confstr(self):
+ def f(i):
+ try:
+ return os.confstr(i)
+ except OSError:
+ return "oooops!!"
+ some_value = os.confstr_names.values()[-1]
+ res = self.interpret(f, [some_value])
+ assert hlstr(res) == f(some_value)
+ res = self.interpret(f, [94781413])
+ assert hlstr(res) == "oooops!!"
+
+ if hasattr(os, 'pathconf'):
+ def test_os_pathconf(self):
+ def f(i):
+ return os.pathconf("/tmp", i)
+ i = os.pathconf_names["PC_NAME_MAX"]
+ some_value = self.interpret(f, [i])
+ assert some_value >= 31
+
if hasattr(os, 'chroot'):
def test_os_chroot(self):
def f():
@@ -205,3 +227,78 @@
return os.getgroups()
ll_a = self.interpret(f, [])
assert self.ll_to_list(ll_a) == f()
+
+ if hasattr(os, 'setgroups'):
+ def test_setgroups(self):
+ def f():
+ try:
+ os.setgroups(os.getgroups())
+ except OSError:
+ pass
+ self.interpret(f, [])
+
+ if hasattr(os, 'initgroups'):
+ def test_initgroups(self):
+ def f():
+ try:
+ os.initgroups('sUJJeumz', 4321)
+ except OSError:
+ return 1
+ return 0
+ res = self.interpret(f, [])
+ assert res == 1
+
+ if hasattr(os, 'tcgetpgrp'):
+ def test_tcgetpgrp(self):
+ def f(fd):
+ try:
+ return os.tcgetpgrp(fd)
+ except OSError:
+ return 42
+ res = self.interpret(f, [9999])
+ assert res == 42
+
+ if hasattr(os, 'tcsetpgrp'):
+ def test_tcsetpgrp(self):
+ def f(fd, pgrp):
+ try:
+ os.tcsetpgrp(fd, pgrp)
+ except OSError:
+ return 1
+ return 0
+ res = self.interpret(f, [9999, 1])
+ assert res == 1
+
+ if hasattr(os, 'getresuid'):
+ def test_getresuid(self):
+ def f():
+ a, b, c = os.getresuid()
+ return a + b * 37 + c * 1291
+ res = self.interpret(f, [])
+ a, b, c = os.getresuid()
+ assert res == a + b * 37 + c * 1291
+
+ if hasattr(os, 'getresgid'):
+ def test_getresgid(self):
+ def f():
+ a, b, c = os.getresgid()
+ return a + b * 37 + c * 1291
+ res = self.interpret(f, [])
+ a, b, c = os.getresgid()
+ assert res == a + b * 37 + c * 1291
+
+ if hasattr(os, 'setresuid'):
+ def test_setresuid(self):
+ def f():
+ a, b, c = os.getresuid()
+ a = (a + 1) - 1
+ os.setresuid(a, b, c)
+ self.interpret(f, [])
+
+ if hasattr(os, 'setresgid'):
+ def test_setresgid(self):
+ def f():
+ a, b, c = os.getresgid()
+ a = (a + 1) - 1
+ os.setresgid(a, b, c)
+ self.interpret(f, [])
More information about the pypy-commit
mailing list