Author: Tim Felgentreff <[email protected]>
Branch:
Changeset: r89901:c613943ef39a
Date: 2017-02-02 11:07 +0100
http://bitbucket.org/pypy/pypy/changeset/c613943ef39a/
Log: merge default
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -102,7 +102,11 @@
% (len(buf) + offset, size + offset))
raw_addr = buf._pypy_raw_address()
result = self.from_address(raw_addr)
- result._ensure_objects()['ffffffff'] = obj
+ objects = result._ensure_objects()
+ if objects is not None:
+ objects['ffffffff'] = obj
+ else: # case e.g. of a primitive type like c_int
+ result._objects = obj
return result
def from_buffer_copy(self, obj, offset=0):
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -198,10 +198,21 @@
def getdict(self, space):
if self.w_func_dict is None:
+ if not self.can_change_code:
+ raise oefmt(space.w_AttributeError,
+ "cannot set extra attributes on built-in
functions")
self.w_func_dict = space.newdict(instance=True)
return self.w_func_dict
+ def getdictvalue(self, space, attr):
+ if not self.can_change_code:
+ return None
+ return W_Root.getdictvalue(self, space, attr)
+
def setdict(self, space, w_dict):
+ if not self.can_change_code:
+ raise oefmt(space.w_AttributeError,
+ "cannot set __dict__ on built-in functions")
if not space.isinstance_w(w_dict, space.w_dict):
raise oefmt(space.w_TypeError,
"setting function's dictionary to a non-dict")
@@ -660,7 +671,7 @@
Function.__init__(self, func.space, func.code, func.w_func_globals,
func.defs_w, func.closure, func.name)
self.w_doc = func.w_doc
- self.w_func_dict = func.w_func_dict
+ #self.w_func_dict = func.w_func_dict---nowadays, always None
self.w_module = func.w_module
def descr_builtinfunction__new__(space, w_subtype):
diff --git a/pypy/interpreter/test/test_function.py
b/pypy/interpreter/test/test_function.py
--- a/pypy/interpreter/test/test_function.py
+++ b/pypy/interpreter/test/test_function.py
@@ -95,8 +95,16 @@
def test_write_code_builtin_forbidden(self):
def f(*args):
return 42
- raises(TypeError, "dir.func_code = f.func_code")
- raises(TypeError, "list.append.im_func.func_code = f.func_code")
+ raises(TypeError, "dir.func_code = f.func_code")
+ raises(TypeError, "list.append.im_func.func_code = f.func_code")
+
+ def test_write_extra_attributes_builtin_forbidden(self):
+ raises(AttributeError, "dir.abcd = 5")
+ raises(AttributeError, "list.append.im_func.efgh = 6")
+ raises(AttributeError, "dir.__dict__")
+ raises(AttributeError, "dir.__dict__ = {}")
+ c = all.__call__ # this should work
+ assert c([4, 5, 6]) is True
def test_set_module_to_name_eagerly(self):
skip("fails on PyPy but works on CPython. Unsure we want to care")
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
@@ -122,12 +122,120 @@
hints={'nolength': True}))
class W_ArrayBase(W_Root):
- _attrs_ = ('space', 'len', 'allocated', '_lifeline_') # no buffer
+ _attrs_ = ('space', 'len', 'allocated', '_lifeline_', '_buffer')
def __init__(self, space):
self.space = space
self.len = 0
self.allocated = 0
+ self._buffer = lltype.nullptr(rffi.CCHARP.TO)
+
+ @rgc.must_be_light_finalizer
+ def __del__(self):
+ if self._buffer:
+ lltype.free(self._buffer, flavor='raw')
+
+ def setlen(self, size, zero=False, overallocate=True):
+ if size > 0:
+ if size > self.allocated or size < self.allocated / 2:
+ if overallocate:
+ if size < 9:
+ some = 3
+ else:
+ some = 6
+ some += size >> 3
+ else:
+ some = 0
+ self.allocated = size + some
+ byte_size = self.allocated * self.itemsize
+ if zero:
+ new_buffer = lltype.malloc(
+ rffi.CCHARP.TO, byte_size, flavor='raw',
+ add_memory_pressure=True, zero=True)
+ else:
+ new_buffer = lltype.malloc(
+ rffi.CCHARP.TO, byte_size, flavor='raw',
+ add_memory_pressure=True)
+ copy_bytes = min(size, self.len) * self.itemsize
+ rffi.c_memcpy(rffi.cast(rffi.VOIDP, new_buffer),
+ rffi.cast(rffi.VOIDP, self._buffer),
+ copy_bytes)
+ else:
+ self.len = size
+ return
+ else:
+ assert size == 0
+ self.allocated = 0
+ new_buffer = lltype.nullptr(rffi.CCHARP.TO)
+
+ if self._buffer:
+ lltype.free(self._buffer, flavor='raw')
+ self._buffer = new_buffer
+ self.len = size
+
+ def _fromiterable(self, w_seq):
+ # used by fromsequence().
+ # a more careful case if w_seq happens to be a very large
+ # iterable: don't copy the items into some intermediate list
+ w_iterator = self.space.iter(w_seq)
+ tp = self.space.type(w_iterator)
+ while True:
+ unpack_driver.jit_merge_point(selfclass=self.__class__,
+ tp=tp, self=self,
+ w_iterator=w_iterator)
+ space = self.space
+ try:
+ w_item = space.next(w_iterator)
+ except OperationError as e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ break # done
+ self.descr_append(space, w_item)
+
+ def _charbuf_start(self):
+ return self._buffer
+
+ def _buffer_as_unsigned(self):
+ return rffi.cast(lltype.Unsigned, self._buffer)
+
+ def _charbuf_stop(self):
+ keepalive_until_here(self)
+
+ def delitem(self, space, i, j):
+ if i < 0:
+ i += self.len
+ if i < 0:
+ i = 0
+ if j < 0:
+ j += self.len
+ if j < 0:
+ j = 0
+ if j > self.len:
+ j = self.len
+ if i >= j:
+ return None
+ oldbuffer = self._buffer
+ self._buffer = lltype.malloc(rffi.CCHARP.TO,
+ (self.len - (j - i)) * self.itemsize, flavor='raw',
+ add_memory_pressure=True)
+ if i:
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, self._buffer),
+ rffi.cast(rffi.VOIDP, oldbuffer),
+ i * self.itemsize
+ )
+ if j < self.len:
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, rffi.ptradd(self._buffer,
+ i * self.itemsize)),
+ rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer,
+ j * self.itemsize)),
+ (self.len - j) * self.itemsize
+ )
+ self.len -= j - i
+ self.allocated = self.len
+ if oldbuffer:
+ lltype.free(oldbuffer, flavor='raw')
def readbuf_w(self, space):
return ArrayBuffer(self, True)
@@ -154,14 +262,24 @@
Return number of occurrences of x in the array.
"""
- raise NotImplementedError
+ cnt = 0
+ for i in range(self.len):
+ # XXX jitdriver
+ w_item = self.w_getitem(space, i)
+ if space.is_true(space.eq(w_item, w_val)):
+ cnt += 1
+ return space.wrap(cnt)
def descr_index(self, space, w_x):
""" index(x)
Return index of first occurrence of x in the array.
"""
- raise NotImplementedError
+ for i in range(self.len):
+ w_item = self.w_getitem(space, i)
+ if space.is_true(space.eq(w_item, w_x)):
+ return space.wrap(i)
+ raise oefmt(space.w_ValueError, "array.index(x): x not in list")
def descr_reverse(self, space):
""" reverse()
@@ -175,7 +293,8 @@
Remove the first occurrence of x in the array.
"""
- raise NotImplementedError
+ w_idx = self.descr_index(space, w_val)
+ self.descr_pop(space, space.int_w(w_idx))
@unwrap_spec(i=int)
def descr_pop(self, space, i=-1):
@@ -453,16 +572,102 @@
return space.newseqiter(self)
def descr_add(self, space, w_other):
- raise NotImplementedError
+ if (not isinstance(w_other, W_ArrayBase)
+ or w_other.typecode != self.typecode):
+ return space.w_NotImplemented
+ a = self.constructor(space)
+ a.setlen(self.len + w_other.len, overallocate=False)
+ if self.len:
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, a._buffer),
+ rffi.cast(rffi.VOIDP, self._buffer),
+ self.len * self.itemsize
+ )
+ if w_other.len:
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, rffi.ptradd(a._buffer,
+ self.len * self.itemsize)),
+ rffi.cast(rffi.VOIDP, w_other._buffer),
+ w_other.len * self.itemsize
+ )
+ keepalive_until_here(self)
+ keepalive_until_here(a)
+ return a
def descr_inplace_add(self, space, w_other):
- raise NotImplementedError
+ if (not isinstance(w_other, W_ArrayBase)
+ or w_other.typecode != self.typecode):
+ return space.w_NotImplemented
+ oldlen = self.len
+ otherlen = w_other.len
+ self.setlen(oldlen + otherlen)
+ if otherlen:
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, rffi.ptradd(self._buffer,
+ oldlen * self.itemsize)),
+ rffi.cast(rffi.VOIDP, w_other._buffer),
+ otherlen * self.itemsize
+ )
+ keepalive_until_here(self)
+ keepalive_until_here(w_other)
+ return self
+
+ def _mul_helper(self, space, w_repeat, is_inplace):
+ try:
+ repeat = space.getindex_w(w_repeat, space.w_OverflowError)
+ except OperationError as e:
+ if e.match(space, space.w_TypeError):
+ return space.w_NotImplemented
+ raise
+ if is_inplace:
+ a = self
+ start = 1
+ else:
+ a = self.constructor(space)
+ start = 0
+ if repeat <= start:
+ if repeat <= 0:
+ a.setlen(0, overallocate=False)
+ return a
+ oldlen = self.len
+ try:
+ newlen = ovfcheck(oldlen * repeat)
+ except OverflowError:
+ raise MemoryError
+ #
+ srcbuf = self._buffer
+ srcsize = self.len * self.itemsize
+ for i in range(srcsize):
+ if srcbuf[i] != '\x00':
+ break
+ else:
+ # the source is entirely zero: initialize the target
+ # with zeroes too
+ a.setlen(newlen, zero=True, overallocate=False)
+ return a
+ #
+ a.setlen(newlen, overallocate=False)
+ srcbuf = self._buffer # reload this, in case self is a
+ if oldlen == 1:
+ self._repeat_single_item(a, start, repeat)
+ else:
+ dstbuf = a._buffer
+ if start == 1:
+ dstbuf = rffi.ptradd(dstbuf, srcsize)
+ for r in range(start, repeat):
+ rffi.c_memcpy(rffi.cast(rffi.VOIDP, dstbuf),
+ rffi.cast(rffi.VOIDP, srcbuf),
+ srcsize)
+ dstbuf = rffi.ptradd(dstbuf, srcsize)
+ keepalive_until_here(self)
+ keepalive_until_here(a)
+ return a
def descr_mul(self, space, w_repeat):
- raise NotImplementedError
+ return self._mul_helper(space, w_repeat, False)
def descr_inplace_mul(self, space, w_repeat):
- raise NotImplementedError
+ return self._mul_helper(space, w_repeat, True)
def descr_radd(self, space, w_other):
return self.descr_add(space, w_other)
@@ -551,6 +756,7 @@
self.itemtype = itemtype
self.bytes = rffi.sizeof(itemtype)
self.arraytype = lltype.Array(itemtype, hints={'nolength': True})
+ self.arrayptrtype = lltype.Ptr(self.arraytype)
self.unwrap = unwrap
self.signed = signed
self.canoverflow = canoverflow
@@ -640,22 +846,21 @@
return self.array._charbuf_start()
+unpack_driver = jit.JitDriver(name='unpack_array',
+ greens=['selfclass', 'tp'],
+ reds=['self', 'w_iterator'])
+
def make_array(mytype):
W_ArrayBase = globals()['W_ArrayBase']
- unpack_driver = jit.JitDriver(name='unpack_array',
- greens=['tp'],
- reds=['self', 'w_iterator'])
-
class W_Array(W_ArrayBase):
itemsize = mytype.bytes
typecode = mytype.typecode
- _attrs_ = ('space', 'len', 'allocated', '_lifeline_', 'buffer')
+ _attrs_ = W_ArrayBase._attrs_
- def __init__(self, space):
- W_ArrayBase.__init__(self, space)
- self.buffer = lltype.nullptr(mytype.arraytype)
+ def get_buffer(self):
+ return rffi.cast(mytype.arrayptrtype, self._buffer)
def item_w(self, w_item):
space = self.space
@@ -709,46 +914,6 @@
self.space.wrap(msg))
return result
- @rgc.must_be_light_finalizer
- def __del__(self):
- if self.buffer:
- lltype.free(self.buffer, flavor='raw')
-
- def setlen(self, size, zero=False, overallocate=True):
- if size > 0:
- if size > self.allocated or size < self.allocated / 2:
- if overallocate:
- if size < 9:
- some = 3
- else:
- some = 6
- some += size >> 3
- else:
- some = 0
- self.allocated = size + some
- if zero:
- new_buffer = lltype.malloc(
- mytype.arraytype, self.allocated, flavor='raw',
- add_memory_pressure=True, zero=True)
- else:
- new_buffer = lltype.malloc(
- mytype.arraytype, self.allocated, flavor='raw',
- add_memory_pressure=True)
- for i in range(min(size, self.len)):
- new_buffer[i] = self.buffer[i]
- else:
- self.len = size
- return
- else:
- assert size == 0
- self.allocated = 0
- new_buffer = lltype.nullptr(mytype.arraytype)
-
- if self.buffer:
- lltype.free(self.buffer, flavor='raw')
- self.buffer = new_buffer
- self.len = size
-
def fromsequence(self, w_seq):
space = self.space
oldlen = self.len
@@ -764,20 +929,21 @@
if lst is not None:
self.setlen(oldlen + len(lst))
try:
- buf = self.buffer
+ buf = self.get_buffer()
for num in lst:
buf[newlen] = self.item_from_int_or_float(num)
newlen += 1
except OperationError:
self.setlen(newlen)
raise
+ keepalive_until_here(self)
return
# this is the common case: w_seq is a list or a tuple
lst_w = space.listview_no_unpack(w_seq)
if lst_w is not None:
self.setlen(oldlen + len(lst_w))
- buf = self.buffer
+ buf = self.get_buffer()
try:
for w_num in lst_w:
# note: self.item_w() might invoke arbitrary code.
@@ -788,30 +954,14 @@
buf[newlen] = self.item_w(w_num)
newlen += 1
except OperationError:
- if buf == self.buffer:
+ if buf == self.get_buffer():
self.setlen(newlen)
raise
+ keepalive_until_here(self)
return
self._fromiterable(w_seq)
- def _fromiterable(self, w_seq):
- # a more careful case if w_seq happens to be a very large
- # iterable: don't copy the items into some intermediate list
- w_iterator = self.space.iter(w_seq)
- tp = self.space.type(w_iterator)
- while True:
- unpack_driver.jit_merge_point(tp=tp, self=self,
- w_iterator=w_iterator)
- space = self.space
- try:
- w_item = space.next(w_iterator)
- except OperationError as e:
- if not e.match(space, space.w_StopIteration):
- raise
- break # done
- self.descr_append(space, w_item)
-
def extend(self, w_iterable, accept_different_array=False):
space = self.space
if isinstance(w_iterable, W_Array):
@@ -819,11 +969,14 @@
new = w_iterable.len
self.setlen(self.len + new)
i = 0
+ buf = self.get_buffer()
+ srcbuf = w_iterable.get_buffer()
while i < new:
if oldlen + i >= self.len:
self.setlen(oldlen + i + 1)
- self.buffer[oldlen + i] = w_iterable.buffer[i]
+ buf[oldlen + i] = srcbuf[i]
i += 1
+ keepalive_until_here(w_iterable)
self.setlen(oldlen + i)
elif (not accept_different_array
and isinstance(w_iterable, W_ArrayBase)):
@@ -832,17 +985,9 @@
else:
self.fromsequence(w_iterable)
- def _charbuf_start(self):
- return rffi.cast(rffi.CCHARP, self.buffer)
-
- def _buffer_as_unsigned(self):
- return rffi.cast(lltype.Unsigned, self.buffer)
-
- def _charbuf_stop(self):
+ def w_getitem(self, space, idx):
+ item = self.get_buffer()[idx]
keepalive_until_here(self)
-
- def w_getitem(self, space, idx):
- item = self.buffer[idx]
if mytype.typecode in 'bBhHil':
item = rffi.cast(lltype.Signed, item)
elif mytype.typecode == 'f':
@@ -855,29 +1000,16 @@
x = self.item_w(w_x)
index = self.len
self.setlen(index + 1)
- self.buffer[index] = x
+ self.get_buffer()[index] = x
+ keepalive_until_here(self)
# List interface
- def descr_count(self, space, w_val):
- cnt = 0
- for i in range(self.len):
- # XXX jitdriver
- w_item = self.w_getitem(space, i)
- if space.is_true(space.eq(w_item, w_val)):
- cnt += 1
- return space.wrap(cnt)
-
- def descr_index(self, space, w_val):
- for i in range(self.len):
- w_item = self.w_getitem(space, i)
- if space.is_true(space.eq(w_item, w_val)):
- return space.wrap(i)
- raise oefmt(space.w_ValueError, "array.index(x): x not in list")
def descr_reverse(self, space):
- b = self.buffer
+ b = self.get_buffer()
for i in range(self.len / 2):
b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i]
+ keepalive_until_here(self)
def descr_pop(self, space, i):
if i < 0:
@@ -885,16 +1017,14 @@
if i < 0 or i >= self.len:
raise oefmt(space.w_IndexError, "pop index out of range")
w_val = self.w_getitem(space, i)
+ b = self.get_buffer()
while i < self.len - 1:
- self.buffer[i] = self.buffer[i + 1]
+ b[i] = b[i + 1]
i += 1
+ keepalive_until_here(self)
self.setlen(self.len - 1)
return w_val
- def descr_remove(self, space, w_val):
- w_idx = self.descr_index(space, w_val)
- self.descr_pop(space, space.int_w(w_idx))
-
def descr_insert(self, space, idx, w_val):
if idx < 0:
idx += self.len
@@ -906,10 +1036,12 @@
val = self.item_w(w_val)
self.setlen(self.len + 1)
i = self.len - 1
+ b = self.get_buffer()
while i > idx:
- self.buffer[i] = self.buffer[i - 1]
+ b[i] = b[i - 1]
i -= 1
- self.buffer[i] = val
+ b[i] = val
+ keepalive_until_here(self)
def getitem_slice(self, space, w_idx):
start, stop, step, size = space.decode_index4(w_idx, self.len)
@@ -917,9 +1049,13 @@
w_a.setlen(size, overallocate=False)
assert step != 0
j = 0
+ buf = w_a.get_buffer()
+ srcbuf = self.get_buffer()
for i in range(start, stop, step):
- w_a.buffer[j] = self.buffer[i]
+ buf[j] = srcbuf[i]
j += 1
+ keepalive_until_here(self)
+ keepalive_until_here(w_a)
return w_a
def setitem(self, space, w_idx, w_item):
@@ -928,7 +1064,8 @@
raise oefmt(self.space.w_TypeError,
"can only assign array to array slice")
item = self.item_w(w_item)
- self.buffer[idx] = item
+ self.get_buffer()[idx] = item
+ keepalive_until_here(self)
def setitem_slice(self, space, w_idx, w_item):
if not isinstance(w_item, W_Array):
@@ -945,127 +1082,21 @@
self.fromsequence(w_lst)
else:
j = 0
+ buf = self.get_buffer()
+ srcbuf = w_item.get_buffer()
for i in range(start, stop, step):
- self.buffer[i] = w_item.buffer[j]
+ buf[i] = srcbuf[j]
j += 1
+ keepalive_until_here(w_item)
+ keepalive_until_here(self)
- def delitem(self, space, i, j):
- if i < 0:
- i += self.len
- if i < 0:
- i = 0
- if j < 0:
- j += self.len
- if j < 0:
- j = 0
- if j > self.len:
- j = self.len
- if i >= j:
- return None
- oldbuffer = self.buffer
- self.buffer = lltype.malloc(
- mytype.arraytype, max(self.len - (j - i), 0), flavor='raw',
- add_memory_pressure=True)
- if i:
- rffi.c_memcpy(
- rffi.cast(rffi.VOIDP, self.buffer),
- rffi.cast(rffi.VOIDP, oldbuffer),
- i * mytype.bytes
- )
- if j < self.len:
- rffi.c_memcpy(
- rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)),
- rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)),
- (self.len - j) * mytype.bytes
- )
- self.len -= j - i
- self.allocated = self.len
- if oldbuffer:
- 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)
- 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):
- if not isinstance(w_other, W_Array):
- return space.w_NotImplemented
- oldlen = self.len
- otherlen = w_other.len
- self.setlen(oldlen + otherlen)
- 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):
- return _mul_helper(space, self, w_repeat, False)
-
- def descr_inplace_mul(self, space, w_repeat):
- return _mul_helper(space, self, w_repeat, True)
-
- def _mul_helper(space, self, w_repeat, is_inplace):
- try:
- repeat = space.getindex_w(w_repeat, space.w_OverflowError)
- except OperationError as e:
- if e.match(space, space.w_TypeError):
- return space.w_NotImplemented
- raise
- repeat = max(repeat, 0)
- try:
- newlen = ovfcheck(self.len * repeat)
- except OverflowError:
- raise MemoryError
- oldlen = self.len
- if is_inplace:
- a = self
- start = 1
- else:
- a = mytype.w_class(space)
- start = 0
- # <a performance hack>
- if oldlen == 1:
- if mytype.unwrap == 'str_w' or mytype.unwrap == 'unicode_w':
- zero = not ord(self.buffer[0])
- elif mytype.unwrap == 'int_w' or mytype.unwrap == 'bigint_w':
- zero = not widen(self.buffer[0])
- #elif mytype.unwrap == 'float_w':
- # value = ...float(self.buffer[0]) xxx handle the case of -0.0
- else:
- zero = False
- if zero:
- a.setlen(newlen, zero=True, overallocate=False)
- return a
- a.setlen(newlen, overallocate=False)
- item = self.buffer[0]
+ def _repeat_single_item(self, a, start, repeat):
+ # <a performance hack>
+ assert isinstance(a, W_Array)
+ item = self.get_buffer()[0]
+ dstbuf = a.get_buffer()
for r in range(start, repeat):
- a.buffer[r] = item
- return a
- # </a performance hack>
- a.setlen(newlen, overallocate=False)
- for r in range(start, repeat):
- for i in range(oldlen):
- a.buffer[r * oldlen + i] = self.buffer[i]
- return a
+ dstbuf[r] = item
mytype.w_class = W_Array
W_Array.constructor = W_Array
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py
b/pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py
@@ -24,6 +24,16 @@
assert b[0] == "a"
assert b[:] == "abc\0"
+ def test_from_buffer(self):
+ b1 = bytearray("abcde")
+ b = (c_char * 5).from_buffer(b1)
+ assert b[2] == "c"
+ #
+ b1 = bytearray("abcd")
+ b = c_int.from_buffer(b1)
+ assert b.value in (1684234849, # little endian
+ 1633837924) # big endian
+
try:
c_wchar
except NameError:
diff --git a/rpython/jit/codewriter/test/test_call.py
b/rpython/jit/codewriter/test/test_call.py
--- a/rpython/jit/codewriter/test/test_call.py
+++ b/rpython/jit/codewriter/test/test_call.py
@@ -281,6 +281,8 @@
def test_elidable_kinds():
from rpython.jit.backend.llgraph.runner import LLGraphCPU
+ from rpython.rlib.objectmodel import compute_hash
+ from rpython.rlib.rsiphash import enable_siphash24
@jit.elidable
def f1(n, m):
@@ -293,12 +295,17 @@
if n > m:
raise ValueError
return n + m
+ @jit.elidable
+ def f4(n, m):
+ return compute_hash(str(n) + str(m))
def f(n, m):
a = f1(n, m)
b = f2(n, m)
c = f3(n, m)
- return a + len(b) + c
+ d = f4(n, m)
+ enable_siphash24()
+ return a + len(b) + c + d
rtyper = support.annotate(f, [7, 9])
jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
@@ -309,7 +316,8 @@
for index, expected in [
(0, EffectInfo.EF_ELIDABLE_CANNOT_RAISE),
(1, EffectInfo.EF_ELIDABLE_OR_MEMORYERROR),
- (2, EffectInfo.EF_ELIDABLE_CAN_RAISE)]:
+ (2, EffectInfo.EF_ELIDABLE_CAN_RAISE),
+ (3, EffectInfo.EF_ELIDABLE_OR_MEMORYERROR)]:
call_op = f_graph.startblock.operations[index]
assert call_op.opname == 'direct_call'
call_descr = cc.getcalldescr(call_op)
diff --git a/rpython/memory/gctransform/asmgcroot.py
b/rpython/memory/gctransform/asmgcroot.py
--- a/rpython/memory/gctransform/asmgcroot.py
+++ b/rpython/memory/gctransform/asmgcroot.py
@@ -26,7 +26,6 @@
class AsmGcRootFrameworkGCTransformer(BaseFrameworkGCTransformer):
_asmgcc_save_restore_arguments = None
- _seen_gctransformer_hint_close_stack = None
def push_roots(self, hop, keep_current_args=False):
livevars = self.get_livevars_for_roots(hop, keep_current_args)
@@ -50,29 +49,28 @@
hop.genop("direct_call", [c_asm_nocollect, name])
def gct_direct_call(self, hop):
+ # just a sanity check: if we find a fnptr with the hint on the
+ # _callable, then we'd also find the hint by looking only at the
+ # graph. We'll actually change this graph only later, in
+ # start_transforming_graph().
fnptr = hop.spaceop.args[0].value
try:
close_stack = fnptr._obj._callable._gctransformer_hint_close_stack_
except AttributeError:
+ pass
+ else:
+ assert fnptr._obj.graph.func is fnptr._obj._callable
+ BaseFrameworkGCTransformer.gct_direct_call(self, hop)
+
+ def start_transforming_graph(self, graph):
+ try:
+ close_stack = graph.func._gctransformer_hint_close_stack_
+ except AttributeError:
close_stack = False
if close_stack:
- self.handle_call_with_close_stack(hop)
- else:
- BaseFrameworkGCTransformer.gct_direct_call(self, hop)
+ self._transform_hint_close_stack(graph)
- def handle_call_with_close_stack(self, hop):
- fnptr = hop.spaceop.args[0].value
- if self._seen_gctransformer_hint_close_stack is None:
- self._seen_gctransformer_hint_close_stack = {}
- if fnptr._obj.graph not in self._seen_gctransformer_hint_close_stack:
- self._transform_hint_close_stack(fnptr)
- self._seen_gctransformer_hint_close_stack[fnptr._obj.graph] = True
- #
- livevars = self.push_roots(hop)
- self.default(hop)
- self.pop_roots(hop, livevars)
-
- def _transform_hint_close_stack(self, fnptr):
+ def _transform_hint_close_stack(self, graph):
# We cannot easily pass variable amount of arguments of the call
# across the call to the pypy_asm_stackwalk helper. So we store
# them away and restore them. More precisely, we need to
@@ -83,8 +81,8 @@
sradict = self._asmgcc_save_restore_arguments
sra = [] # list of pointers to raw-malloced containers for args
seen = {}
- FUNC1 = lltype.typeOf(fnptr).TO
- for TYPE in FUNC1.ARGS:
+ ARGS = [v.concretetype for v in graph.getargs()]
+ for TYPE in ARGS:
if isinstance(TYPE, lltype.Ptr):
TYPE = llmemory.Address
num = seen.get(TYPE, 0)
@@ -98,8 +96,10 @@
sra.append(sradict[key])
#
# make a copy of the graph that will reload the values
- graph = fnptr._obj.graph
graph2 = copygraph(graph)
+ del graph2.func # otherwise, start_transforming_graph() will
+ # again transform graph2, and we get an
+ # infinite loop
#
# edit the original graph to only store the value of the arguments
block = Block(graph.startblock.inputargs)
@@ -116,17 +116,18 @@
SpaceOperation("bare_setfield", [c_p, c_item0, v_arg], v_void))
#
# call asm_stackwalk(graph2)
- FUNC2 = lltype.FuncType([], FUNC1.RESULT)
+ RESULT = graph.getreturnvar().concretetype
+ FUNC2 = lltype.FuncType([], RESULT)
fnptr2 = lltype.functionptr(FUNC2,
- fnptr._obj._name + '_reload',
+ graph.name + '_reload',
graph=graph2)
c_fnptr2 = Constant(fnptr2, lltype.Ptr(FUNC2))
HELPERFUNC = lltype.FuncType([lltype.Ptr(FUNC2),
- ASM_FRAMEDATA_HEAD_PTR], FUNC1.RESULT)
+ ASM_FRAMEDATA_HEAD_PTR], RESULT)
v_asm_stackwalk = varoftype(lltype.Ptr(HELPERFUNC), "asm_stackwalk")
block.operations.append(
SpaceOperation("cast_pointer", [c_asm_stackwalk], v_asm_stackwalk))
- v_result = varoftype(FUNC1.RESULT)
+ v_result = varoftype(RESULT)
block.operations.append(
SpaceOperation("indirect_call", [v_asm_stackwalk, c_fnptr2,
c_gcrootanchor,
diff --git a/rpython/memory/gctransform/transform.py
b/rpython/memory/gctransform/transform.py
--- a/rpython/memory/gctransform/transform.py
+++ b/rpython/memory/gctransform/transform.py
@@ -201,6 +201,9 @@
self.var_last_needed_in = None
self.curr_block = None
+ def start_transforming_graph(self, graph):
+ pass # for asmgcc.py
+
def transform_graph(self, graph):
if graph in self.minimal_transform:
if self.minimalgctransformer:
@@ -210,6 +213,7 @@
if graph in self.seen_graphs:
return
self.seen_graphs.add(graph)
+ self.start_transforming_graph(graph)
self.links_to_split = {} # link -> vars to pop_alive across the link
diff --git a/rpython/rlib/test/test_rsignal.py
b/rpython/rlib/test/test_rsignal.py
--- a/rpython/rlib/test/test_rsignal.py
+++ b/rpython/rlib/test/test_rsignal.py
@@ -1,4 +1,4 @@
-import os, py
+import os, py, errno
from rpython.translator.c.test.test_genc import compile
from rpython.rlib import rsignal
@@ -37,3 +37,24 @@
def test_compile():
fn = compile(test_simple, [])
fn()
+
+def test_compile_wakeup_fd():
+ def fn():
+ rd, wr = os.pipe()
+ rsignal.pypysig_set_wakeup_fd(wr, False)
+ for i in range(3):
+ rsignal.pypysig_setflag(rsignal.SIGUSR1)
+ os.kill(os.getpid(), rsignal.SIGUSR1)
+ check(rsignal.SIGUSR1)
+ check(-1)
+ check(-1)
+ x = os.read(rd, 10)
+ assert x == chr(rsignal.SIGUSR1) * 3
+ #
+ rsignal.pypysig_set_wakeup_fd(rd, False) # can't write there
+ os.kill(os.getpid(), rsignal.SIGUSR1)
+
+ fn = compile(fn, [], return_stderr=True)
+ stderr = fn()
+ assert stderr.endswith('Exception ignored when trying to write to the '
+ 'signal wakeup fd: Errno %d\n' % errno.EBADF)
diff --git a/rpython/rtyper/lltypesystem/lloperation.py
b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -539,7 +539,6 @@
'decode_arg_def': LLOp(canraise=(Exception,)),
'getslice': LLOp(canraise=(Exception,)),
'check_and_clear_exc': LLOp(),
- 'call_at_startup': LLOp(canrun=True),
'threadlocalref_addr': LLOp(), # get (or make) addr of
tl
'threadlocalref_get': LLOp(sideeffects=False), # read field (no check)
diff --git a/rpython/rtyper/lltypesystem/opimpl.py
b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -742,9 +742,6 @@
def op_gc_move_out_of_nursery(obj):
return obj
-def op_call_at_startup(init_func):
- pass # do nothing
-
# ____________________________________________________________
def get_op_impl(opname):
diff --git a/rpython/translator/c/database.py b/rpython/translator/c/database.py
--- a/rpython/translator/c/database.py
+++ b/rpython/translator/c/database.py
@@ -60,7 +60,6 @@
self.completed = False
self.instrument_ncounter = 0
- self.call_at_startup = set()
def gettypedefnode(self, T, varlength=None):
if varlength is None:
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -941,18 +941,3 @@
cdecl(typename, ''),
self.expr(op.args[0]),
self.expr(op.result))
-
- def OP_CALL_AT_STARTUP(self, op):
- c = op.args[0]
- if not isinstance(c, Constant):
- # Bah, maybe it comes from a same_as(const) just before...
- # Can occur if running without backendopts
- for op1 in self._current_block.operations:
- if op1.result is op.args[0]:
- assert op1.opname == "same_as"
- c = op1.args[0]
- break
- assert isinstance(c, Constant)
- func = self.expr(c)
- self.db.call_at_startup.add(func)
- return '/* call_at_startup %s */' % (func,)
diff --git a/rpython/translator/c/src/signals.c
b/rpython/translator/c/src/signals.c
--- a/rpython/translator/c/src/signals.c
+++ b/rpython/translator/c/src/signals.c
@@ -2,6 +2,7 @@
#include <limits.h>
#include <stdlib.h>
+#include <errno.h>
#ifdef _WIN32
#include <process.h>
#include <io.h>
@@ -82,27 +83,51 @@
}
}
+static void write_str(int fd, const char *p)
+{
+ int i = 0;
+ while (p[i] != '\x00')
+ i++;
+ (void)write(fd, p, i);
+}
+
static void signal_setflag_handler(int signum)
{
pypysig_pushback(signum);
- if (wakeup_fd != -1)
- {
+ /* Warning, this logic needs to be async-signal-safe */
+ if (wakeup_fd != -1) {
#ifndef _WIN32
ssize_t res;
#else
int res;
#endif
- if (wakeup_with_nul_byte)
- {
- res = write(wakeup_fd, "\0", 1);
- } else {
- unsigned char byte = (unsigned char)signum;
- res = write(wakeup_fd, &byte, 1);
- }
-
- /* the return value is ignored here */
- }
+ int old_errno = errno;
+ retry:
+ if (wakeup_with_nul_byte) {
+ res = write(wakeup_fd, "\0", 1);
+ } else {
+ unsigned char byte = (unsigned char)signum;
+ res = write(wakeup_fd, &byte, 1);
+ }
+ if (res < 0) {
+ unsigned int e = (unsigned int)errno;
+ char c[27], *p;
+ if (e == EINTR)
+ goto retry;
+ write_str(2, "Exception ignored when trying to write to the "
+ "signal wakeup fd: Errno ");
+ p = c + sizeof(c);
+ *--p = 0;
+ *--p = '\n';
+ do {
+ *--p = '0' + e % 10;
+ e /= 10;
+ } while (e != 0);
+ write_str(2, p);
+ }
+ errno = old_errno;
+ }
}
void pypysig_setflag(int signum)
diff --git a/rpython/translator/c/test/test_standalone.py
b/rpython/translator/c/test/test_standalone.py
--- a/rpython/translator/c/test/test_standalone.py
+++ b/rpython/translator/c/test/test_standalone.py
@@ -1063,23 +1063,39 @@
assert out.strip() == expected
def test_call_at_startup(self):
- from rpython.rtyper.lltypesystem import lltype
- from rpython.rtyper.lltypesystem.lloperation import llop
- from rpython.rtyper.annlowlevel import llhelper
+ from rpython.rtyper.extregistry import ExtRegistryEntry
+
class State:
seen = 0
state = State()
def startup():
state.seen += 1
- F = lltype.Ptr(lltype.FuncType([], lltype.Void))
+ def enablestartup():
+ "NOT_RPYTHON"
def entry_point(argv):
state.seen += 100
assert state.seen == 101
print 'ok'
- ll = llhelper(F, startup)
- llop.call_at_startup(lltype.Void, ll)
+ enablestartup()
return 0
+ class Entry(ExtRegistryEntry):
+ _about_ = enablestartup
+
+ def compute_result_annotation(self):
+ bk = self.bookkeeper
+ s_callable = bk.immutablevalue(startup)
+ key = (enablestartup,)
+ bk.emulate_pbc_call(key, s_callable, [])
+
+ def specialize_call(self, hop):
+ hop.exception_cannot_occur()
+ bk = hop.rtyper.annotator.bookkeeper
+ s_callable = bk.immutablevalue(startup)
+ r_callable = hop.rtyper.getrepr(s_callable)
+ ll_init = r_callable.get_unique_llfn().value
+ bk.annotator.translator._call_at_startup.append(ll_init)
+
t, cbuilder = self.compile(entry_point)
out = cbuilder.cmdexec('')
assert out.strip() == 'ok'
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit