Author: Maciej Fijalkowski <fij...@gmail.com> Branch: Changeset: r76322:98040ad7de44 Date: 2015-03-11 12:28 +0200 http://bitbucket.org/pypy/pypy/changeset/98040ad7de44/
Log: merge diff too long, truncating to 2000 out of 3245 lines diff --git a/lib_pypy/cffi.egg-info b/lib_pypy/cffi.egg-info --- a/lib_pypy/cffi.egg-info +++ b/lib_pypy/cffi.egg-info @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: cffi -Version: 0.8.6+ +Version: 0.9.0 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "0.8.6+" -__version_info__ = (0, 8, 6, "plus") +__version__ = "0.9.0" +__version_info__ = (0, 9, 0) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -34,3 +34,6 @@ .. branch: nonquadratic-heapcache Speed up the warmup times of the JIT by removing a quadratic algorithm in the heapcache. + +.. branch: online-transforms-2 +Simplify flow graphs on the fly during annotation phase. 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 @@ -8,7 +8,7 @@ appleveldefs = { } interpleveldefs = { - '__version__': 'space.wrap("0.8.6+")', + '__version__': 'space.wrap("0.9.0")', 'load_library': 'libraryobj.load_library', diff --git a/pypy/module/_cffi_backend/cbuffer.py b/pypy/module/_cffi_backend/cbuffer.py --- a/pypy/module/_cffi_backend/cbuffer.py +++ b/pypy/module/_cffi_backend/cbuffer.py @@ -81,4 +81,5 @@ if size < 0: raise oefmt(space.w_TypeError, "don't know the size pointed to by '%s'", ctype.name) - return space.wrap(MiniBuffer(LLBuffer(w_cdata._cdata, size), w_cdata)) + ptr = w_cdata.unsafe_escaping_ptr() # w_cdata kept alive by MiniBuffer() + return space.wrap(MiniBuffer(LLBuffer(ptr, size), w_cdata)) diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py --- a/pypy/module/_cffi_backend/ccallback.py +++ b/pypy/module/_cffi_backend/ccallback.py @@ -48,9 +48,12 @@ raise oefmt(space.w_NotImplementedError, "%s: callback with unsupported argument or " "return type or with '...'", self.getfunctype().name) - res = clibffi.c_ffi_prep_closure(self.get_closure(), cif_descr.cif, - invoke_callback, - rffi.cast(rffi.VOIDP, self.unique_id)) + with self as ptr: + closure_ptr = rffi.cast(clibffi.FFI_CLOSUREP, ptr) + unique_id = rffi.cast(rffi.VOIDP, self.unique_id) + res = clibffi.c_ffi_prep_closure(closure_ptr, cif_descr.cif, + invoke_callback, + unique_id) if rffi.cast(lltype.Signed, res) != clibffi.FFI_OK: raise OperationError(space.w_SystemError, space.wrap("libffi failed to build this callback")) @@ -62,12 +65,9 @@ from pypy.module.thread.os_thread import setup_threads setup_threads(space) - def get_closure(self): - return rffi.cast(clibffi.FFI_CLOSUREP, self._cdata) - #@rgc.must_be_light_finalizer def __del__(self): - clibffi.closureHeap.free(self.get_closure()) + clibffi.closureHeap.free(rffi.cast(clibffi.FFI_CLOSUREP, self._ptr)) if self.ll_error: lltype.free(self.ll_error, flavor='raw') @@ -106,7 +106,7 @@ fresult = self.getfunctype().ctitem if fresult.size > 0: misc._raw_memcopy(self.ll_error, ll_res, fresult.size) - keepalive_until_here(self) + keepalive_until_here(self) # to keep self.ll_error alive global_callback_mapping = rweakref.RWeakValueDictionary(int, W_CDataCallback) 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 @@ -14,21 +14,37 @@ class W_CData(W_Root): - _attrs_ = ['space', '_cdata', 'ctype', '_lifeline_'] - _immutable_fields_ = ['_cdata', 'ctype'] - _cdata = lltype.nullptr(rffi.CCHARP.TO) + _attrs_ = ['space', '_ptr', 'ctype', '_lifeline_'] + _immutable_fields_ = ['_ptr', 'ctype'] + _ptr = lltype.nullptr(rffi.CCHARP.TO) - def __init__(self, space, cdata, ctype): + def __init__(self, space, ptr, ctype): from pypy.module._cffi_backend import ctypeobj - assert lltype.typeOf(cdata) == rffi.CCHARP + assert lltype.typeOf(ptr) == rffi.CCHARP assert isinstance(ctype, ctypeobj.W_CType) self.space = space - self._cdata = cdata # don't forget keepalive_until_here! + self._ptr = ptr # don't access directly! use "with cdata as ptr:" self.ctype = ctype + def __enter__(self): + """Use 'with cdata as ptr:' to access the raw memory. It will + stay alive at least until the end of the 'with' block. + """ + return self._ptr + + def __exit__(self, *args): + keepalive_until_here(self) + + def unsafe_escaping_ptr(self): + """Generally unsafe: escape the pointer to raw memory. + If 'self' is a subclass that frees the pointer in a destructor, + it may be freed under your feet at any time. + """ + return self._ptr + def _repr_extra(self): - extra = self.ctype.extra_repr(self._cdata) - keepalive_until_here(self) + with self as ptr: + extra = self.ctype.extra_repr(ptr) return extra def _repr_extra_owning(self): @@ -54,11 +70,13 @@ self.ctype.name, extra1, extra2)) def nonzero(self): - return self.space.wrap(bool(self._cdata)) + with self as ptr: + nonzero = bool(ptr) + return self.space.wrap(nonzero) def int(self, space): - w_result = self.ctype.cast_to_int(self._cdata) - keepalive_until_here(self) + with self as ptr: + w_result = self.ctype.cast_to_int(ptr) return w_result def long(self, space): @@ -69,8 +87,8 @@ return w_result def float(self): - w_result = self.ctype.float(self._cdata) - keepalive_until_here(self) + with self as ptr: + w_result = self.ctype.float(ptr) return w_result def len(self): @@ -88,20 +106,19 @@ def _cmp(self, w_other): from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitive space = self.space - cdata1 = self._cdata - if isinstance(w_other, W_CData): - cdata2 = w_other._cdata - else: + if not isinstance(w_other, W_CData): return space.w_NotImplemented - if requires_ordering: - if (isinstance(self.ctype, W_CTypePrimitive) or - isinstance(w_other.ctype, W_CTypePrimitive)): - raise OperationError(space.w_TypeError, - space.wrap("cannot do comparison on a primitive cdata")) - cdata1 = rffi.cast(lltype.Unsigned, cdata1) - cdata2 = rffi.cast(lltype.Unsigned, cdata2) - return space.newbool(op(cdata1, cdata2)) + with self as ptr1, w_other as ptr2: + if requires_ordering: + if (isinstance(self.ctype, W_CTypePrimitive) or + isinstance(w_other.ctype, W_CTypePrimitive)): + raise OperationError(space.w_TypeError, space.wrap( + "cannot do comparison on a primitive cdata")) + ptr1 = rffi.cast(lltype.Unsigned, ptr1) + ptr2 = rffi.cast(lltype.Unsigned, ptr2) + result = op(ptr1, ptr2) + return space.newbool(result) # return func_with_new_name(_cmp, name) @@ -113,7 +130,8 @@ ge = _make_comparison('ge') def hash(self): - h = rffi.cast(lltype.Signed, self._cdata) + ptr = self.unsafe_escaping_ptr() + h = rffi.cast(lltype.Signed, ptr) # To hash pointers in dictionaries. Assumes that h shows some # alignment (to 4, 8, maybe 16 bytes), so we use the following # formula to avoid the trailing bits being always 0. @@ -128,26 +146,27 @@ i = space.getindex_w(w_index, space.w_IndexError) ctype = self.ctype._check_subscript_index(self, i) w_o = self._do_getitem(ctype, i) - keepalive_until_here(self) return w_o def _do_getitem(self, ctype, i): ctitem = ctype.ctitem - return ctitem.convert_to_object( - rffi.ptradd(self._cdata, i * ctitem.size)) + with self as ptr: + return ctitem.convert_to_object( + rffi.ptradd(ptr, i * ctitem.size)) def setitem(self, w_index, w_value): space = self.space if space.isinstance_w(w_index, space.w_slice): - self._do_setslice(w_index, w_value) + with self as ptr: + self._do_setslice(w_index, w_value, ptr) else: i = space.getindex_w(w_index, space.w_IndexError) ctype = self.ctype._check_subscript_index(self, i) ctitem = ctype.ctitem - ctitem.convert_from_object( - rffi.ptradd(self._cdata, i * ctitem.size), - w_value) - keepalive_until_here(self) + with self as ptr: + ctitem.convert_from_object( + rffi.ptradd(ptr, i * ctitem.size), + w_value) def _do_getslicearg(self, w_slice): from pypy.module._cffi_backend.ctypeptr import W_CTypePointer @@ -188,14 +207,15 @@ ctarray = newtype.new_array_type(space, ctptr, space.w_None) ctptr.cache_array_type = ctarray # - p = rffi.ptradd(self._cdata, start * ctarray.ctitem.size) - return W_CDataSliced(space, p, ctarray, length) + ptr = self.unsafe_escaping_ptr() + ptr = rffi.ptradd(ptr, start * ctarray.ctitem.size) + return W_CDataSliced(space, ptr, ctarray, length) - def _do_setslice(self, w_slice, w_value): + def _do_setslice(self, w_slice, w_value, ptr): ctptr, start, length = self._do_getslicearg(w_slice) ctitem = ctptr.ctitem ctitemsize = ctitem.size - cdata = rffi.ptradd(self._cdata, start * ctitemsize) + target = rffi.ptradd(ptr, start * ctitemsize) # if isinstance(w_value, W_CData): from pypy.module._cffi_backend import ctypearray @@ -204,9 +224,8 @@ ctv.ctitem is ctitem and w_value.get_array_length() == length): # fast path: copying from exactly the correct type - s = w_value._cdata - rffi.c_memcpy(cdata, s, ctitemsize * length) - keepalive_until_here(w_value) + with w_value as source: + rffi.c_memcpy(target, source, ctitemsize * length) return # # A fast path for <char[]>[0:N] = "somestring". @@ -221,7 +240,7 @@ raise oefmt(space.w_ValueError, "need a string of length %d, got %d", length, len(value)) - copy_string_to_raw(llstr(value), cdata, 0, length) + copy_string_to_raw(llstr(value), target, 0, length) return # w_iter = space.iter(w_value) @@ -233,8 +252,8 @@ raise raise oefmt(space.w_ValueError, "need %d values to unpack, got %d", length, i) - ctitem.convert_from_object(cdata, w_item) - cdata = rffi.ptradd(cdata, ctitemsize) + ctitem.convert_from_object(target, w_item) + target = rffi.ptradd(target, ctitemsize) try: space.next(w_iter) except OperationError, e: @@ -247,7 +266,8 @@ def _add_or_sub(self, w_other, sign): space = self.space i = sign * space.getindex_w(w_other, space.w_OverflowError) - return self.ctype.add(self._cdata, i) + ptr = self.unsafe_escaping_ptr() + return self.ctype.add(ptr, i) def add(self, w_other): return self._add_or_sub(w_other, +1) @@ -268,9 +288,11 @@ 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)) // itemsize + if itemsize <= 0: + itemsize = 1 + with self as ptr1, w_other as ptr2: + diff = (rffi.cast(lltype.Signed, ptr1) - + rffi.cast(lltype.Signed, ptr2)) // itemsize return space.wrap(diff) # return self._add_or_sub(w_other, -1) @@ -279,17 +301,19 @@ return self.ctype.getcfield(self.space.str_w(w_attr)) def getattr(self, w_attr): - w_res = self.getcfield(w_attr).read(self._cdata) - keepalive_until_here(self) + cfield = self.getcfield(w_attr) + with self as ptr: + w_res = cfield.read(ptr) return w_res def setattr(self, w_attr, w_value): - self.getcfield(w_attr).write(self._cdata, w_value) - keepalive_until_here(self) + cfield = self.getcfield(w_attr) + with self as ptr: + cfield.write(ptr, w_value) def call(self, args_w): - w_result = self.ctype.call(self._cdata, args_w) - keepalive_until_here(self) + with self as ptr: + w_result = self.ctype.call(ptr, args_w) return w_result def iter(self): @@ -311,21 +335,21 @@ @specialize.argtype(1) def write_raw_signed_data(self, source): - misc.write_raw_signed_data(self._cdata, source, self.ctype.size) - keepalive_until_here(self) + with self as ptr: + misc.write_raw_signed_data(ptr, source, self.ctype.size) @specialize.argtype(1) def write_raw_unsigned_data(self, source): - misc.write_raw_unsigned_data(self._cdata, source, self.ctype.size) - keepalive_until_here(self) + with self as ptr: + misc.write_raw_unsigned_data(ptr, source, self.ctype.size) def write_raw_float_data(self, source): - misc.write_raw_float_data(self._cdata, source, self.ctype.size) - keepalive_until_here(self) + with self as ptr: + misc.write_raw_float_data(ptr, source, self.ctype.size) def convert_to_object(self): - w_obj = self.ctype.convert_to_object(self._cdata) - keepalive_until_here(self) + with self as ptr: + w_obj = self.ctype.convert_to_object(ptr) return w_obj def get_array_length(self): @@ -353,7 +377,7 @@ @rgc.must_be_light_finalizer def __del__(self): - lltype.free(self._cdata, flavor='raw') + lltype.free(self._ptr, flavor='raw') class W_CDataNewOwning(W_CDataMem): 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 @@ -8,7 +8,6 @@ from pypy.interpreter.typedef import TypeDef from rpython.rtyper.lltypesystem import rffi -from rpython.rlib.objectmodel import keepalive_until_here from rpython.rlib.rarithmetic import ovfcheck from pypy.module._cffi_backend import cdataobj @@ -49,8 +48,8 @@ cdata = cdataobj.W_CDataNewOwning(space, datasize, self) # if not space.is_w(w_init, space.w_None): - self.convert_from_object(cdata._cdata, w_init) - keepalive_until_here(cdata) + with cdata as ptr: + self.convert_from_object(ptr, w_init) return cdata def _check_subscript_index(self, w_cdata, i): @@ -119,8 +118,8 @@ self.ctitem = ctitem self.cdata = cdata length = cdata.get_array_length() - self._next = cdata._cdata - self._stop = rffi.ptradd(cdata._cdata, length * ctitem.size) + self._next = cdata.unsafe_escaping_ptr() + self._stop = rffi.ptradd(self._next, length * ctitem.size) def iter_w(self): return self.space.wrap(self) diff --git a/pypy/module/_cffi_backend/ctypeenum.py b/pypy/module/_cffi_backend/ctypeenum.py --- a/pypy/module/_cffi_backend/ctypeenum.py +++ b/pypy/module/_cffi_backend/ctypeenum.py @@ -2,8 +2,6 @@ Enums. """ -from rpython.rlib.objectmodel import keepalive_until_here - from pypy.module._cffi_backend import misc from pypy.module._cffi_backend.ctypeprim import (W_CTypePrimitiveSigned, W_CTypePrimitiveUnsigned) @@ -47,8 +45,8 @@ return '%s: %s' % (value, s) def string(self, cdataobj, maxlen): - value = self._get_value(cdataobj._cdata) - keepalive_until_here(cdataobj) + with cdataobj as ptr: + value = self._get_value(ptr) try: s = self.enumvalues2erators[value] except KeyError: diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py --- a/pypy/module/_cffi_backend/ctypeobj.py +++ b/pypy/module/_cffi_backend/ctypeobj.py @@ -177,8 +177,8 @@ raise oefmt(space.w_AttributeError, "cdata '%s' has no attribute '%s'", self.name, attr) - def copy_and_convert_to_object(self, cdata): - return self.convert_to_object(cdata) + def copy_and_convert_to_object(self, source): + return self.convert_to_object(source) # __________ app-level attributes __________ def dir(self): diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -5,7 +5,6 @@ import sys from rpython.rlib.rarithmetic import r_uint, r_ulonglong, intmask -from rpython.rlib.objectmodel import keepalive_until_here from rpython.rlib import jit from rpython.rtyper.lltypesystem import lltype, rffi @@ -53,7 +52,8 @@ space = self.space if (isinstance(w_ob, cdataobj.W_CData) and isinstance(w_ob.ctype, ctypeptr.W_CTypePtrOrArray)): - value = rffi.cast(lltype.Signed, w_ob._cdata) + ptr = w_ob.unsafe_escaping_ptr() + value = rffi.cast(lltype.Signed, ptr) value = self._cast_result(value) elif space.isinstance_w(w_ob, space.w_str): value = self.cast_str(w_ob) @@ -81,8 +81,8 @@ def string(self, cdataobj, maxlen): if self.size == 1: - s = cdataobj._cdata[0] - keepalive_until_here(cdataobj) + with cdataobj as ptr: + s = ptr[0] return self.space.wrap(s) return W_CType.string(self, cdataobj, maxlen) @@ -116,7 +116,8 @@ return s[0] if (isinstance(w_ob, cdataobj.W_CData) and isinstance(w_ob.ctype, W_CTypePrimitiveChar)): - return w_ob._cdata[0] + with w_ob as ptr: + return ptr[0] raise self._convert_error("string of length 1", w_ob) def convert_from_object(self, cdata, w_ob): @@ -137,8 +138,8 @@ return self.space.wrap(s) def string(self, cdataobj, maxlen): - w_res = self.convert_to_object(cdataobj._cdata) - keepalive_until_here(cdataobj) + with cdataobj as ptr: + w_res = self.convert_to_object(ptr) return w_res def _convert_to_unichar(self, w_ob): @@ -149,7 +150,8 @@ return s[0] if (isinstance(w_ob, cdataobj.W_CData) and isinstance(w_ob.ctype, W_CTypePrimitiveUniChar)): - return rffi.cast(rffi.CWCHARP, w_ob._cdata)[0] + with w_ob as ptr: + return rffi.cast(rffi.CWCHARP, ptr)[0] raise self._convert_error("unicode string of length 1", w_ob) def convert_from_object(self, cdata, w_ob): @@ -219,13 +221,15 @@ if self.size == rffi.sizeof(rffi.LONG): from rpython.rlib.rrawarray import populate_list_from_raw_array res = [] - buf = rffi.cast(rffi.LONGP, w_cdata._cdata) length = w_cdata.get_array_length() - populate_list_from_raw_array(res, buf, length) + with w_cdata as ptr: + buf = rffi.cast(rffi.LONGP, ptr) + populate_list_from_raw_array(res, buf, length) return res elif self.value_smaller_than_long: res = [0] * w_cdata.get_array_length() - misc.unpack_list_from_raw_array(res, w_cdata._cdata, self.size) + with w_cdata as ptr: + misc.unpack_list_from_raw_array(res, ptr, self.size) return res return None @@ -308,8 +312,8 @@ def unpack_list_of_int_items(self, w_cdata): if self.value_fits_long: res = [0] * w_cdata.get_array_length() - misc.unpack_unsigned_list_from_raw_array(res, w_cdata._cdata, - self.size) + with w_cdata as ptr: + misc.unpack_unsigned_list_from_raw_array(res, ptr, self.size) return res return None @@ -363,8 +367,8 @@ if not isinstance(self, W_CTypePrimitiveLongDouble): w_cdata.write_raw_float_data(value) else: - self._to_longdouble_and_write(value, w_cdata._cdata) - keepalive_until_here(w_cdata) + with w_cdata as ptr: + self._to_longdouble_and_write(value, ptr) return w_cdata def cast_to_int(self, cdata): @@ -387,13 +391,15 @@ if self.size == rffi.sizeof(rffi.DOUBLE): from rpython.rlib.rrawarray import populate_list_from_raw_array res = [] - buf = rffi.cast(rffi.DOUBLEP, w_cdata._cdata) length = w_cdata.get_array_length() - populate_list_from_raw_array(res, buf, length) + with w_cdata as ptr: + buf = rffi.cast(rffi.DOUBLEP, ptr) + populate_list_from_raw_array(res, buf, length) return res elif self.size == rffi.sizeof(rffi.FLOAT): res = [0.0] * w_cdata.get_array_length() - misc.unpack_cfloat_list_from_raw_array(res, w_cdata._cdata) + with w_cdata as ptr: + misc.unpack_cfloat_list_from_raw_array(res, ptr) return res return None @@ -423,8 +429,8 @@ def cast(self, w_ob): if (isinstance(w_ob, cdataobj.W_CData) and isinstance(w_ob.ctype, W_CTypePrimitiveLongDouble)): - w_cdata = self.convert_to_object(w_ob._cdata) - keepalive_until_here(w_ob) + with w_ob as ptr: + w_cdata = self.convert_to_object(ptr) return w_cdata else: return W_CTypePrimitiveFloat.cast(self, w_ob) @@ -451,16 +457,16 @@ def convert_to_object(self, cdata): w_cdata = cdataobj.W_CDataMem(self.space, self.size, self) - self._copy_longdouble(cdata, w_cdata._cdata) - keepalive_until_here(w_cdata) + with w_cdata as ptr: + self._copy_longdouble(cdata, ptr) return w_cdata def convert_from_object(self, cdata, w_ob): space = self.space if (isinstance(w_ob, cdataobj.W_CData) and isinstance(w_ob.ctype, W_CTypePrimitiveLongDouble)): - self._copy_longdouble(w_ob._cdata, cdata) - keepalive_until_here(w_ob) + with w_ob as ptr: + self._copy_longdouble(ptr, cdata) else: value = space.float_w(space.float(w_ob)) self._to_longdouble_and_write(value, cdata) 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 @@ -3,7 +3,6 @@ """ 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 @@ -49,7 +48,7 @@ space = self.space if (isinstance(w_ob, cdataobj.W_CData) and isinstance(w_ob.ctype, W_CTypePtrOrArray)): - value = w_ob._cdata + value = w_ob.unsafe_escaping_ptr() else: value = misc.as_unsigned_long(space, w_ob, strict=False) value = rffi.cast(rffi.CCHARP, value) @@ -108,34 +107,33 @@ def string(self, cdataobj, maxlen): space = self.space if isinstance(self.ctitem, ctypeprim.W_CTypePrimitive): - cdata = cdataobj._cdata - if not cdata: - raise oefmt(space.w_RuntimeError, "cannot use string() on %s", - space.str_w(cdataobj.repr())) - # - from pypy.module._cffi_backend import ctypearray - length = maxlen - if length < 0 and isinstance(self, ctypearray.W_CTypeArray): - length = cdataobj.get_array_length() - # - # pointer to a primitive type of size 1: builds and returns a str - if self.ctitem.size == rffi.sizeof(lltype.Char): - if length < 0: - s = rffi.charp2str(cdata) - else: - s = rffi.charp2strn(cdata, length) - keepalive_until_here(cdataobj) - return space.wrap(s) - # - # pointer to a wchar_t: builds and returns a unicode - if self.is_unichar_ptr_or_array(): - cdata = rffi.cast(rffi.CWCHARP, cdata) - if length < 0: - u = rffi.wcharp2unicode(cdata) - else: - u = rffi.wcharp2unicoden(cdata, length) - keepalive_until_here(cdataobj) - return space.wrap(u) + with cdataobj as ptr: + if not ptr: + raise oefmt(space.w_RuntimeError, + "cannot use string() on %s", + space.str_w(cdataobj.repr())) + # + from pypy.module._cffi_backend import ctypearray + length = maxlen + if length < 0 and isinstance(self, ctypearray.W_CTypeArray): + length = cdataobj.get_array_length() + # + # pointer to a primitive type of size 1: builds and returns a str + if self.ctitem.size == rffi.sizeof(lltype.Char): + if length < 0: + s = rffi.charp2str(ptr) + else: + s = rffi.charp2strn(ptr, length) + return space.wrap(s) + # + # pointer to a wchar_t: builds and returns a unicode + if self.is_unichar_ptr_or_array(): + cdata = rffi.cast(rffi.CWCHARP, ptr) + if length < 0: + u = rffi.wcharp2unicode(cdata) + else: + u = rffi.wcharp2unicoden(cdata, length) + return space.wrap(u) # return W_CType.string(self, cdataobj, maxlen) @@ -162,7 +160,7 @@ if not (self.can_cast_anything or other.can_cast_anything): raise self._convert_error("compatible pointer", w_ob) - rffi.cast(rffi.CCHARPP, cdata)[0] = w_ob._cdata + rffi.cast(rffi.CCHARPP, cdata)[0] = w_ob.unsafe_escaping_ptr() def _alignof(self): from pypy.module._cffi_backend import newtype @@ -206,8 +204,8 @@ lltype.nullptr(rffi.CCHARP.TO), w_init, datasize) # cdatastruct = cdataobj.W_CDataNewOwning(space, datasize, ctitem) - cdata = cdataobj.W_CDataPtrToStructOrUnion(space, - cdatastruct._cdata, + ptr = cdatastruct.unsafe_escaping_ptr() + cdata = cdataobj.W_CDataPtrToStructOrUnion(space, ptr, self, cdatastruct) else: if self.is_char_or_unichar_ptr_or_array(): @@ -215,8 +213,8 @@ cdata = cdataobj.W_CDataNewOwning(space, datasize, self) # if not space.is_w(w_init, space.w_None): - ctitem.convert_from_object(cdata._cdata, w_init) - keepalive_until_here(cdata) + with cdata as ptr: + ctitem.convert_from_object(ptr, w_init) return cdata def _check_subscript_index(self, w_cdata, i): @@ -332,8 +330,9 @@ ctype2 = cdata.ctype if (isinstance(ctype2, W_CTypeStructOrUnion) or isinstance(ctype2, W_CTypePtrOrArray)): - ptrdata = rffi.ptradd(cdata._cdata, offset) - return cdataobj.W_CData(space, ptrdata, self) + ptr = cdata.unsafe_escaping_ptr() + ptr = rffi.ptradd(ptr, offset) + return cdataobj.W_CData(space, ptr, self) else: raise OperationError(space.w_TypeError, space.wrap("expected a cdata struct/union/array/pointer" 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 @@ -7,7 +7,6 @@ from pypy.interpreter.typedef import TypeDef, interp_attrproperty 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.rlib.rarithmetic import ovfcheck from rpython.rtyper.lltypesystem import lltype, rffi @@ -57,12 +56,12 @@ self.check_complete() return cdataobj.W_CData(space, cdata, self) - def copy_and_convert_to_object(self, cdata): + def copy_and_convert_to_object(self, source): space = self.space self.check_complete() ob = cdataobj.W_CDataNewOwning(space, self.size, self) - misc._raw_memcopy(cdata, ob._cdata, self.size) - keepalive_until_here(ob) + with ob as target: + misc._raw_memcopy(source, target, self.size) return ob def typeoffsetof_field(self, fieldname, following): @@ -80,8 +79,8 @@ def _copy_from_same(self, cdata, w_ob): if isinstance(w_ob, cdataobj.W_CData): if w_ob.ctype is self and self.size >= 0: - misc._raw_memcopy(w_ob._cdata, cdata, self.size) - keepalive_until_here(w_ob) + with w_ob as ptr: + misc._raw_memcopy(ptr, cdata, self.size) return True return False diff --git a/pypy/module/_cffi_backend/ctypevoid.py b/pypy/module/_cffi_backend/ctypevoid.py --- a/pypy/module/_cffi_backend/ctypevoid.py +++ b/pypy/module/_cffi_backend/ctypevoid.py @@ -13,5 +13,5 @@ def __init__(self, space): W_CType.__init__(self, space, -1, "void", len("void")) - def copy_and_convert_to_object(self, cdata): + def copy_and_convert_to_object(self, source): return self.space.w_None diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py --- a/pypy/module/_cffi_backend/handle.py +++ b/pypy/module/_cffi_backend/handle.py @@ -34,8 +34,9 @@ raise oefmt(space.w_TypeError, "expected a 'cdata' object with a 'void *' out of " "new_handle(), got '%s'", ctype.name) - index = rffi.cast(lltype.Signed, w_cdata._cdata) - original_cdataobj = get(space).fetch_handle(index - 1) + with w_cdata as ptr: + index = rffi.cast(lltype.Signed, ptr) + original_cdataobj = get(space).fetch_handle(index - 1) # if isinstance(original_cdataobj, cdataobj.W_CDataHandle): return original_cdataobj.w_keepalive 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 @@ -3,7 +3,7 @@ from pypy.interpreter.error import OperationError from rpython.rlib import jit -from rpython.rlib.objectmodel import keepalive_until_here, specialize +from rpython.rlib.objectmodel import specialize from rpython.rlib.rarithmetic import r_uint, r_ulonglong from rpython.rlib.unroll import unrolling_iterable from rpython.rtyper.lltypesystem import lltype, llmemory, rffi @@ -272,11 +272,11 @@ from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveLongDouble is_cdata = isinstance(w_ob, W_CData) if is_cdata and isinstance(w_ob.ctype, W_CTypePrimitiveFloat): - if isinstance(w_ob.ctype, W_CTypePrimitiveLongDouble): - result = is_nonnull_longdouble(w_ob._cdata) - else: - result = is_nonnull_float(w_ob._cdata, w_ob.ctype.size) - keepalive_until_here(w_ob) + with w_ob as ptr: + if isinstance(w_ob.ctype, W_CTypePrimitiveLongDouble): + result = is_nonnull_longdouble(ptr) + else: + result = is_nonnull_float(ptr, w_ob.ctype.size) return result # if not is_cdata and space.lookup(w_ob, '__float__') is not None: 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 @@ -3249,4 +3249,4 @@ def test_version(): # this test is here mostly for PyPy - assert __version__ == "0.8.6+" + assert __version__ == "0.9.0" diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py --- a/pypy/module/_random/test/test_random.py +++ b/pypy/module/_random/test/test_random.py @@ -102,3 +102,10 @@ self.x = x r = R(x=15) assert r.x == 15 + + def test_exact_result(self): + # this passes on CPython 2.7.9 on Linux 32 and Linux 64 + import _random + rnd = _random.Random(-3**31) + x = rnd.random() + assert x == 0.8181851342382107 diff --git a/pypy/module/cppyy/capi/loadable_capi.py b/pypy/module/cppyy/capi/loadable_capi.py --- a/pypy/module/cppyy/capi/loadable_capi.py +++ b/pypy/module/cppyy/capi/loadable_capi.py @@ -259,7 +259,8 @@ if not objectmodel.we_are_translated(): leakfinder.remember_free(c_call.ctype.cif_descr._obj0) state.capi_calls[name] = c_call - return c_call.ctype.rcall(c_call._cdata, args) + with c_call as ptr: + return c_call.ctype.rcall(ptr, args) def _cdata_to_cobject(space, w_cdata): return rffi.cast(C_OBJECT, space.uint_w(w_cdata)) @@ -271,8 +272,9 @@ return rffi.cast(rffi.LONG, space.int_w(w_cdata)) def _cdata_to_ptr(space, w_cdata): # TODO: this is both a hack and dreadfully slow - return rffi.cast(rffi.VOIDP, - space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False)._cdata) + w_cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False) + ptr = w_cdata.unsafe_escaping_ptr() + return rffi.cast(rffi.VOIDP, ptr) def c_load_dictionary(name): return libffi.CDLL(name) diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -46,7 +46,7 @@ @staticmethod def from_shape_and_storage(space, shape, storage, dtype, storage_bytes=-1, order='C', owning=False, w_subtype=None, - w_base=None, writable=True, strides=None): + w_base=None, writable=True, strides=None, start=0): from pypy.module.micronumpy import concrete from pypy.module.micronumpy.strides import (calc_strides, calc_backstrides) @@ -75,8 +75,9 @@ raise OperationError(space.w_ValueError, space.wrap("Cannot have owning=True when specifying a buffer")) if writable: - impl = concrete.ConcreteArrayWithBase(shape, dtype, order, strides, - backstrides, storage, w_base) + impl = concrete.ConcreteArrayWithBase(shape, dtype, order, + strides, backstrides, storage, w_base, + start=start) else: impl = concrete.ConcreteNonWritableArrayWithBase(shape, dtype, order, strides, backstrides, @@ -128,6 +129,9 @@ def get_order(self): return self.implementation.order + def get_start(self): + return self.implementation.start + def ndims(self): return len(self.get_shape()) ndims._always_inline_ = True diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -12,6 +12,7 @@ from pypy.module.micronumpy.strides import (Chunk, Chunks, NewAxisChunk, RecordChunk, calc_strides, calc_new_strides, shape_agreement, calculate_broadcast_strides, calc_backstrides) +from rpython.rlib.objectmodel import keepalive_until_here class BaseConcreteArray(object): @@ -312,12 +313,15 @@ l_w = [w_res.descr_getitem(space, space.wrap(d)) for d in range(nd)] return space.newtuple(l_w) - def get_storage_as_int(self, space): - return rffi.cast(lltype.Signed, self.storage) + self.start - - def get_storage(self): + ##def get_storage(self): + ## return self.storage + ## use a safer context manager + def __enter__(self): return self.storage + def __exit__(self, typ, value, traceback): + keepalive_until_here(self) + def get_buffer(self, space, readonly): return ArrayBuffer(self, readonly) @@ -331,7 +335,7 @@ class ConcreteArrayNotOwning(BaseConcreteArray): - def __init__(self, shape, dtype, order, strides, backstrides, storage): + def __init__(self, shape, dtype, order, strides, backstrides, storage, start=0): make_sure_not_resized(shape) make_sure_not_resized(strides) make_sure_not_resized(backstrides) @@ -342,6 +346,7 @@ self.strides = strides self.backstrides = backstrides self.storage = storage + self.start = start def fill(self, space, box): self.dtype.itemtype.fill(self.storage, self.dtype.elsize, @@ -350,7 +355,7 @@ def set_shape(self, space, orig_array, new_shape): strides, backstrides = calc_strides(new_shape, self.dtype, self.order) - return SliceArray(0, strides, backstrides, new_shape, self, + return SliceArray(self.start, strides, backstrides, new_shape, self, orig_array) def set_dtype(self, space, dtype): @@ -384,9 +389,10 @@ class ConcreteArrayWithBase(ConcreteArrayNotOwning): - def __init__(self, shape, dtype, order, strides, backstrides, storage, orig_base): + def __init__(self, shape, dtype, order, strides, backstrides, storage, + orig_base, start=0): ConcreteArrayNotOwning.__init__(self, shape, dtype, order, - strides, backstrides, storage) + strides, backstrides, storage, start) self.orig_base = orig_base def base(self): diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -99,10 +99,12 @@ for i in range(w_object.get_size()): elems_w[i] = w_object.implementation.getitem(i * elsize) else: - sz = support.product(w_object.get_shape()) * dtype.elsize - return W_NDimArray.from_shape_and_storage(space, - w_object.get_shape(),w_object.implementation.storage, - dtype, storage_bytes=sz, w_base=w_object) + imp = w_object.implementation + with imp as storage: + sz = support.product(w_object.get_shape()) * dtype.elsize + return W_NDimArray.from_shape_and_storage(space, + w_object.get_shape(), storage, dtype, storage_bytes=sz, + w_base=w_object, start=imp.start) else: # not an array shape, elems_w = strides.find_shape_and_elems(space, w_object, dtype) diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -604,14 +604,15 @@ iter, state = arr.create_iter() w_res_str = W_NDimArray.from_shape(space, [1], arr.get_dtype(), order='C') itemsize = arr.get_dtype().elsize - res_str_casted = rffi.cast(rffi.CArrayPtr(lltype.Char), - w_res_str.implementation.get_storage_as_int(space)) - while not iter.done(state): - w_res_str.implementation.setitem(0, iter.getitem(state)) - for i in range(itemsize): - builder.append(res_str_casted[i]) - state = iter.next(state) - return builder.build() + with w_res_str.implementation as storage: + res_str_casted = rffi.cast(rffi.CArrayPtr(lltype.Char), + support.get_storage_as_int(storage)) + while not iter.done(state): + w_res_str.implementation.setitem(0, iter.getitem(state)) + for i in range(itemsize): + builder.append(res_str_casted[i]) + state = iter.next(state) + return builder.build() getitem_int_driver = jit.JitDriver(name = 'numpy_getitem_int', greens = ['shapelen', 'indexlen', diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -532,20 +532,25 @@ self.get_dtype(), storage_bytes=sz, w_base=self) def descr_array_iface(self, space): - addr = self.implementation.get_storage_as_int(space) - # will explode if it can't - w_d = space.newdict() - space.setitem_str(w_d, 'data', - space.newtuple([space.wrap(addr), space.w_False])) - space.setitem_str(w_d, 'shape', self.descr_get_shape(space)) - space.setitem_str(w_d, 'typestr', self.get_dtype().descr_get_str(space)) - if self.implementation.order == 'C': - # Array is contiguous, no strides in the interface. - strides = space.w_None - else: - strides = self.descr_get_strides(space) - space.setitem_str(w_d, 'strides', strides) - return w_d + ''' + Note: arr.__array__.data[0] is a pointer so arr must be kept alive + while it is in use + ''' + with self.implementation as storage: + addr = support.get_storage_as_int(storage, self.get_start()) + # will explode if it can't + w_d = space.newdict() + space.setitem_str(w_d, 'data', + space.newtuple([space.wrap(addr), space.w_False])) + space.setitem_str(w_d, 'shape', self.descr_get_shape(space)) + space.setitem_str(w_d, 'typestr', self.get_dtype().descr_get_str(space)) + if self.implementation.order == 'C': + # Array is contiguous, no strides in the interface. + strides = space.w_None + else: + strides = self.descr_get_strides(space) + space.setitem_str(w_d, 'strides', strides) + return w_d w_pypy_data = None @@ -1165,7 +1170,8 @@ builder.append(box.raw_str()) state = iter.next(state) else: - builder.append_charpsize(self.implementation.get_storage(), + with self.implementation as storage: + builder.append_charpsize(storage, self.implementation.get_storage_size()) state = space.newtuple([ diff --git a/pypy/module/micronumpy/selection.py b/pypy/module/micronumpy/selection.py --- a/pypy/module/micronumpy/selection.py +++ b/pypy/module/micronumpy/selection.py @@ -33,14 +33,14 @@ self.values = values self.indexes = indexes - def getitem(self, item): + def getitem(self, idx): if count < 2: - v = raw_storage_getitem(TP, self.values, item * self.stride_size + v = raw_storage_getitem(TP, self.values, idx * self.stride_size + self.start) else: v = [] for i in range(count): - _v = raw_storage_getitem(TP, self.values, item * self.stride_size + _v = raw_storage_getitem(TP, self.values, idx * self.stride_size + self.start + step * i) v.append(_v) if comp_type == 'int': @@ -52,7 +52,7 @@ else: raise NotImplementedError('cannot reach') return (v, raw_storage_getitem(lltype.Signed, self.indexes, - item * self.index_stride_size + + idx * self.index_stride_size + self.index_start)) def setitem(self, idx, item): @@ -134,37 +134,37 @@ # create array of indexes dtype = descriptor.get_dtype_cache(space).w_longdtype index_arr = W_NDimArray.from_shape(space, arr.get_shape(), dtype) - storage = index_arr.implementation.get_storage() - if len(arr.get_shape()) == 1: - for i in range(arr.get_size()): - raw_storage_setitem(storage, i * INT_SIZE, i) - r = Repr(INT_SIZE, itemsize, arr.get_size(), arr.get_storage(), - storage, 0, arr.start) - ArgSort(r).sort() - else: - shape = arr.get_shape() - if axis < 0: - axis = len(shape) + axis - if axis < 0 or axis >= len(shape): - raise oefmt(space.w_IndexError, "Wrong axis %d", axis) - arr_iter = AllButAxisIter(arr, axis) - arr_state = arr_iter.reset() - index_impl = index_arr.implementation - index_iter = AllButAxisIter(index_impl, axis) - index_state = index_iter.reset() - stride_size = arr.strides[axis] - index_stride_size = index_impl.strides[axis] - axis_size = arr.shape[axis] - while not arr_iter.done(arr_state): - for i in range(axis_size): - raw_storage_setitem(storage, i * index_stride_size + - index_state.offset, i) - r = Repr(index_stride_size, stride_size, axis_size, - arr.get_storage(), storage, index_state.offset, arr_state.offset) + with index_arr.implementation as storage, arr as arr_storage: + if len(arr.get_shape()) == 1: + for i in range(arr.get_size()): + raw_storage_setitem(storage, i * INT_SIZE, i) + r = Repr(INT_SIZE, itemsize, arr.get_size(), arr_storage, + storage, 0, arr.start) ArgSort(r).sort() - arr_state = arr_iter.next(arr_state) - index_state = index_iter.next(index_state) - return index_arr + else: + shape = arr.get_shape() + if axis < 0: + axis = len(shape) + axis + if axis < 0 or axis >= len(shape): + raise oefmt(space.w_IndexError, "Wrong axis %d", axis) + arr_iter = AllButAxisIter(arr, axis) + arr_state = arr_iter.reset() + index_impl = index_arr.implementation + index_iter = AllButAxisIter(index_impl, axis) + index_state = index_iter.reset() + stride_size = arr.strides[axis] + index_stride_size = index_impl.strides[axis] + axis_size = arr.shape[axis] + while not arr_iter.done(arr_state): + for i in range(axis_size): + raw_storage_setitem(storage, i * index_stride_size + + index_state.offset, i) + r = Repr(index_stride_size, stride_size, axis_size, + arr_storage, storage, index_state.offset, arr_state.offset) + ArgSort(r).sort() + arr_state = arr_iter.next(arr_state) + index_state = index_iter.next(index_state) + return index_arr return argsort @@ -282,25 +282,25 @@ axis = -1 else: axis = space.int_w(w_axis) - # create array of indexes - if len(arr.get_shape()) == 1: - r = Repr(itemsize, arr.get_size(), arr.get_storage(), - arr.start) - ArgSort(r).sort() - else: - shape = arr.get_shape() - if axis < 0: - axis = len(shape) + axis - if axis < 0 or axis >= len(shape): - raise oefmt(space.w_IndexError, "Wrong axis %d", axis) - arr_iter = AllButAxisIter(arr, axis) - arr_state = arr_iter.reset() - stride_size = arr.strides[axis] - axis_size = arr.shape[axis] - while not arr_iter.done(arr_state): - r = Repr(stride_size, axis_size, arr.get_storage(), arr_state.offset) + with arr as storage: + if len(arr.get_shape()) == 1: + r = Repr(itemsize, arr.get_size(), storage, + arr.start) ArgSort(r).sort() - arr_state = arr_iter.next(arr_state) + else: + shape = arr.get_shape() + if axis < 0: + axis = len(shape) + axis + if axis < 0 or axis >= len(shape): + raise oefmt(space.w_IndexError, "Wrong axis %d", axis) + arr_iter = AllButAxisIter(arr, axis) + arr_state = arr_iter.reset() + stride_size = arr.strides[axis] + axis_size = arr.shape[axis] + while not arr_iter.done(arr_state): + r = Repr(stride_size, axis_size, storage, arr_state.offset) + ArgSort(r).sort() + arr_state = arr_iter.next(arr_state) return sort diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py --- a/pypy/module/micronumpy/support.py +++ b/pypy/module/micronumpy/support.py @@ -1,6 +1,7 @@ from pypy.interpreter.error import OperationError, oefmt from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck +from rpython.rtyper.lltypesystem import rffi, lltype def issequence_w(space, w_obj): @@ -147,3 +148,7 @@ if cur_core_dim == 0: ufunc.core_enabled = False return 0 # for historical reasons, any failures will raise + +def get_storage_as_int(storage, start=0): + return rffi.cast(lltype.Signed, storage) + start + diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py --- a/pypy/module/micronumpy/test/test_subtype.py +++ b/pypy/module/micronumpy/test/test_subtype.py @@ -2,7 +2,7 @@ class AppTestSupport(BaseNumpyAppTest): - spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii", "mmap"]) def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) @@ -476,3 +476,120 @@ a = self.SubType(array([[1, 2], [3, 4]])) b = array(a, subok=False) assert type(b) is ndarray + + def test_numpypy_mmap(self): + # issue #21 on pypy/numpy + from numpy import array, ndarray, arange, dtype as dtypedescr + import mmap + import os.path + from tempfile import mkdtemp + import os.path as path + valid_filemodes = ["r", "c", "r+", "w+"] + writeable_filemodes = ["r+", "w+"] + mode_equivalents = { + "readonly":"r", + "copyonwrite":"c", + "readwrite":"r+", + "write":"w+" + } + + class memmap(ndarray): + def __new__(subtype, filename, dtype='uint8', mode='r+', offset=0, shape=None, order='C'): + # Import here to minimize 'import numpy' overhead + try: + mode = mode_equivalents[mode] + except KeyError: + if mode not in valid_filemodes: + raise ValueError("mode must be one of %s" % + (valid_filemodes + list(mode_equivalents.keys()))) + + if hasattr(filename, 'read'): + fid = filename + own_file = False + else: + fid = open(filename, (mode == 'c' and 'r' or mode)+'b') + own_file = True + + if (mode == 'w+') and shape is None: + raise ValueError("shape must be given") + + fid.seek(0, 2) + flen = fid.tell() + descr = dtypedescr(dtype) + _dbytes = descr.itemsize + + if shape is None: + bytes = flen - offset + if (bytes % _dbytes): + fid.close() + raise ValueError("Size of available data is not a " + "multiple of the data-type size.") + size = bytes // _dbytes + shape = (size,) + else: + if not isinstance(shape, tuple): + shape = (shape,) + size = 1 + for k in shape: + size *= k + + bytes = long(offset + size*_dbytes) + + if mode == 'w+' or (mode == 'r+' and flen < bytes): + fid.seek(bytes - 1, 0) + fid.write('\0') + fid.flush() + + if mode == 'c': + acc = mmap.ACCESS_COPY + elif mode == 'r': + acc = mmap.ACCESS_READ + else: + acc = mmap.ACCESS_WRITE + + start = offset - offset % mmap.ALLOCATIONGRANULARITY + bytes -= start + offset -= start + mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start) + + self = ndarray.__new__(subtype, shape, dtype=descr, buffer=mm, + offset=offset, order=order) + self._mmap = mm + self.offset = offset + self.mode = mode + + if isinstance(filename, basestring): + self.filename = os.path.abspath(filename) + # py3 returns int for TemporaryFile().name + elif (hasattr(filename, "name") and + isinstance(filename.name, basestring)): + self.filename = os.path.abspath(filename.name) + # same as memmap copies (e.g. memmap + 1) + else: + self.filename = None + + if own_file: + fid.close() + + return self + + def flush(self): + if self.base is not None and hasattr(self.base, 'flush'): + self.base.flush() + + def asarray(obj, itemsize=None, order=None): + return array(obj, itemsize, copy=False, order=order) + + filename = path.join(mkdtemp(), 'newfile.dat') + data = arange(10*10*36).reshape(10, 10, 36) + fp = memmap(filename, dtype='float32', mode='w+', shape=data.shape) + vals = [ 242, 507, 255, 505, 315, 316, 308, 506, + 309, 255, 211, 505, 315, 316, 308, 506, + 309, 255, 255, 711, 194, 232, 711, 711, + 709, 710, 709, 710, 882, 897, 711, 245, + 711, 711, 168, 245] + fp[:] = data + fp[5:6][:,4] = vals + a = asarray(fp[5:6][:,4]) + assert (a == vals).all() + diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -238,15 +238,15 @@ 'getfield_gc': 5, 'getfield_gc_pure': 51, 'guard_class': 3, - 'guard_false': 13, + 'guard_false': 12, 'guard_nonnull': 11, 'guard_nonnull_class': 3, 'guard_not_invalidated': 2, 'guard_true': 10, - 'guard_value': 5, + 'guard_value': 6, 'int_add': 13, 'int_ge': 4, - 'int_is_true': 4, + 'int_is_true': 3, 'int_is_zero': 4, 'int_le': 2, 'int_lt': 3, @@ -616,15 +616,15 @@ 'getfield_gc': 6, 'getfield_gc_pure': 63, 'guard_class': 5, - 'guard_false': 20, + 'guard_false': 19, 'guard_nonnull': 6, 'guard_nonnull_class': 1, 'guard_not_invalidated': 3, 'guard_true': 16, - 'guard_value': 2, + 'guard_value': 3, 'int_add': 24, 'int_ge': 4, - 'int_is_true': 6, + 'int_is_true': 5, 'int_is_zero': 4, 'int_le': 5, 'int_lt': 7, diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -180,13 +180,16 @@ raw_storage_setitem_unaligned(storage, i + offset, value) def read(self, arr, i, offset, dtype=None): - return self.box(self._read(arr.storage, i, offset)) + with arr as storage: + return self.box(self._read(storage, i, offset)) def read_bool(self, arr, i, offset): - return bool(self.for_computation(self._read(arr.storage, i, offset))) + with arr as storage: + return bool(self.for_computation(self._read(storage, i, offset))) def store(self, arr, i, offset, box): - self._write(arr.storage, i, offset, self.unbox(box)) + with arr as storage: + self._write(storage, i, offset, self.unbox(box)) def fill(self, storage, width, box, start, stop, offset): value = self.unbox(box) @@ -1080,8 +1083,9 @@ return bool(real) or bool(imag) def read_bool(self, arr, i, offset): - v = self.for_computation(self._read(arr.storage, i, offset)) - return bool(v[0]) or bool(v[1]) + with arr as storage: + v = self.for_computation(self._read(storage, i, offset)) + return bool(v[0]) or bool(v[1]) def get_element_size(self): return 2 * rffi.sizeof(self.T) @@ -1132,8 +1136,9 @@ return real, imag def read(self, arr, i, offset, dtype=None): - real, imag = self._read(arr.storage, i, offset) - return self.box_complex(real, imag) + with arr as storage: + real, imag = self._read(storage, i, offset) + return self.box_complex(real, imag) def _write(self, storage, i, offset, value): real, imag = value @@ -1144,7 +1149,8 @@ raw_storage_setitem_unaligned(storage, i + offset + rffi.sizeof(self.T), imag) def store(self, arr, i, offset, box): - self._write(arr.storage, i, offset, self.unbox(box)) + with arr as storage: + self._write(storage, i, offset, self.unbox(box)) def fill(self, storage, width, box, start, stop, offset): value = self.unbox(box) @@ -1633,13 +1639,14 @@ assert isinstance(item, boxes.W_FlexibleBox) i = item.ofs end = i + item.dtype.elsize - while i < end: - assert isinstance(item.arr.storage[i], str) - if item.arr.storage[i] == '\x00': - break - builder.append(item.arr.storage[i]) - i += 1 - return builder.build() + with item.arr as storage: + while i < end: + assert isinstance(storage[i], str) + if storage[i] == '\x00': + break + builder.append(storage[i]) + i += 1 + return builder.build() def str_unary_op(func): specialize.argtype(1)(func) @@ -1669,23 +1676,26 @@ w_item = space.wrap('') arg = space.str_w(space.str(w_item)) arr = VoidBoxStorage(dtype.elsize, dtype) - j = min(len(arg), dtype.elsize) - for i in range(j): - arr.storage[i] = arg[i] - for j in range(j, dtype.elsize): - arr.storage[j] = '\x00' - return boxes.W_StringBox(arr, 0, arr.dtype) + with arr as storage: + j = min(len(arg), dtype.elsize) + for i in range(j): + storage[i] = arg[i] + for j in range(j, dtype.elsize): + storage[j] = '\x00' + return boxes.W_StringBox(arr, 0, arr.dtype) def store(self, arr, i, offset, box): assert isinstance(box, boxes.W_StringBox) size = min(arr.dtype.elsize - offset, box.arr.size - box.ofs) - return self._store(arr.storage, i, offset, box, size) + with arr as storage: + return self._store(storage, i, offset, box, size) @jit.unroll_safe def _store(self, storage, i, offset, box, size): assert isinstance(box, boxes.W_StringBox) - for k in range(size): - storage[k + offset + i] = box.arr.storage[k + box.ofs] + with box.arr as box_storage: + for k in range(size): + storage[k + offset + i] = box_storage[k + box.ofs] def read(self, arr, i, offset, dtype=None): if dtype is None: @@ -1802,8 +1812,9 @@ assert i == 0 assert isinstance(box, boxes.W_VoidBox) assert box.dtype is box.arr.dtype - for k in range(box.arr.dtype.elsize): - arr.storage[k + ofs] = box.arr.storage[k + box.ofs] + with arr as arr_storage, box.arr as box_storage: + for k in range(box.arr.dtype.elsize): + arr_storage[k + ofs] = box_storage[k + box.ofs] def readarray(self, arr, i, offset, dtype=None): from pypy.module.micronumpy.base import W_NDimArray @@ -1893,12 +1904,14 @@ def store(self, arr, i, ofs, box): assert isinstance(box, boxes.W_VoidBox) - self._store(arr.storage, i, ofs, box, box.dtype.elsize) + with arr as storage: + self._store(storage, i, ofs, box, box.dtype.elsize) @jit.unroll_safe def _store(self, storage, i, ofs, box, size): - for k in range(size): - storage[k + i + ofs] = box.arr.storage[k + box.ofs] + with box.arr as box_storage: + for k in range(size): + storage[k + i + ofs] = box_storage[k + box.ofs] def fill(self, storage, width, box, start, stop, offset): assert isinstance(box, boxes.W_VoidBox) @@ -1944,9 +1957,10 @@ s1 = v1.dtype.elsize s2 = v2.dtype.elsize assert s1 == s2 - for i in range(s1): - if v1.arr.storage[v1.ofs + i] != v2.arr.storage[v2.ofs + i]: - return False + with v1.arr as v1_storage, v2.arr as v2_storage: + for i in range(s1): + if v1_storage[v1.ofs + i] != v2_storage[v2.ofs + i]: + return False return True def ne(self, v1, v2): diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -13,11 +13,12 @@ from pypy.module.micronumpy.ctors import numpify from pypy.module.micronumpy.nditer import W_NDIter, coalesce_iter from pypy.module.micronumpy.strides import shape_agreement -from pypy.module.micronumpy.support import _parse_signature, product +from pypy.module.micronumpy.support import _parse_signature, product, get_storage_as_int from rpython.rlib.rawstorage import (raw_storage_setitem, free_raw_storage, alloc_raw_storage) from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rarithmetic import LONG_BIT, _get_bitsize +from rpython.rlib.objectmodel import keepalive_until_here def done_if_true(dtype, val): @@ -98,7 +99,9 @@ if out is not None and not isinstance(out, W_NDimArray): raise OperationError(space.w_TypeError, space.wrap( 'output must be an array')) - return self.call(space, args_w, sig, casting, extobj) + retval = self.call(space, args_w, sig, casting, extobj) + keepalive_until_here(args_w) + return retval def descr_accumulate(self, space, w_obj, w_axis=None, w_dtype=None, w_out=None): if space.is_none(w_axis): @@ -804,11 +807,12 @@ assert isinstance(curarg, W_NDimArray) if len(arg_shapes[i]) != curarg.ndims(): # reshape + sz = product(curarg.get_shape()) * curarg.get_dtype().elsize - inargs[i] = W_NDimArray.from_shape_and_storage( - space, arg_shapes[i], curarg.implementation.storage, - curarg.get_dtype(), storage_bytes=sz, w_base=curarg) - pass + with curarg.implementation as storage: + inargs[i] = W_NDimArray.from_shape_and_storage( + space, arg_shapes[i], storage, + curarg.get_dtype(), storage_bytes=sz, w_base=curarg) need_to_cast.append(curarg.get_dtype() != dtypes[i]) for i in range(len(outargs)): j = self.nin + i @@ -819,9 +823,10 @@ elif len(arg_shapes[i]) != curarg.ndims(): # reshape sz = product(curarg.get_shape()) * curarg.get_dtype().elsize - outargs[i] = W_NDimArray.from_shape_and_storage( - space, arg_shapes[i], curarg.implementation.storage, - curarg.get_dtype(), storage_bytes=sz, w_base=curarg) + with curarg.implementation as storage: + outargs[i] = W_NDimArray.from_shape_and_storage( + space, arg_shapes[i], storage, + curarg.get_dtype(), storage_bytes=sz, w_base=curarg) curarg = outargs[i] assert isinstance(curarg, W_NDimArray) need_to_cast.append(curarg.get_dtype() != dtypes[j]) @@ -1406,8 +1411,9 @@ raise OperationError(space.w_NotImplementedError, space.wrap("cannot mix ndarray and %r (arg %d) in call to ufunc" % ( arg_i, i))) - raw_storage_setitem(dataps, CCHARP_SIZE * i, - rffi.cast(rffi.CCHARP, arg_i.implementation.get_storage_as_int(space))) + with arg_i.implementation as storage: + addr = get_storage_as_int(storage, arg_i.get_start()) + raw_storage_setitem(dataps, CCHARP_SIZE * i, rffi.cast(rffi.CCHARP, addr)) #This assumes we iterate over the whole array (it should be a view...) raw_storage_setitem(self.dims, LONG_SIZE * i, rffi.cast(rffi.LONG, arg_i.get_size())) raw_storage_setitem(self.steps, LONG_SIZE * i, rffi.cast(rffi.LONG, arg_i.get_dtype().elsize)) @@ -1415,8 +1421,9 @@ for i in range(len(args_w)): arg_i = args_w[i] assert isinstance(arg_i, W_NDimArray) - raw_storage_setitem(dataps, CCHARP_SIZE * i, - rffi.cast(rffi.CCHARP, arg_i.implementation.get_storage_as_int(space))) + with arg_i.implementation as storage: + addr = get_storage_as_int(storage, arg_i.get_start()) + raw_storage_setitem(dataps, CCHARP_SIZE * i, rffi.cast(rffi.CCHARP, addr)) try: arg1 = rffi.cast(rffi.CArrayPtr(rffi.CCHARP), dataps) arg2 = rffi.cast(npy_intpp, self.dims) @@ -1424,6 +1431,7 @@ self.func(arg1, arg2, arg3, self.data) finally: free_raw_storage(dataps, track_allocation=False) + keepalive_until_here(args_w) def set_dims_and_steps(self, space, dims, steps): if not isinstance(dims, list) or not isinstance(steps, list): 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 @@ -22,6 +22,10 @@ self.check_valid() return MMapBuffer(self.space, self.mmap, True) + def writebuf_w(self, space): + self.check_writeable() + return MMapBuffer(self.space, self.mmap, False) + def close(self): self.mmap.close() 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 @@ -341,7 +341,7 @@ raw_store(i119, 0, i160, descr=<ArrayS 2>) raw_store(i119, 2, i160, descr=<ArrayS 2>) raw_store(i119, 4, i160, descr=<ArrayS 2>) - setfield_gc(p167, i119, descr=<FieldU pypy.module._cffi_backend.cdataobj.W_CData.inst__cdata .+>) + setfield_gc(p167, i119, descr=<FieldU pypy.module._cffi_backend.cdataobj.W_CData.inst__ptr .+>) i123 = arraylen_gc(p67, descr=<ArrayP .>) jump(..., descr=...) """) diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py --- a/pypy/module/sys/test/test_sysmodule.py +++ b/pypy/module/sys/test/test_sysmodule.py @@ -521,9 +521,11 @@ def test_reload_doesnt_override_sys_executable(self): import sys - sys.executable = 'from_test_sysmodule' + if not hasattr(sys, 'executable'): # if not translated + sys.executable = 'from_test_sysmodule' + previous = sys.executable reload(sys) - assert sys.executable == 'from_test_sysmodule' + assert sys.executable == previous def test_settrace(self): import sys diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py --- a/rpython/annotator/annrpython.py +++ b/rpython/annotator/annrpython.py @@ -6,8 +6,8 @@ from rpython.tool.pairtype import pair from rpython.tool.error import (format_blocked_annotation_error, gather_error, source_lines) -from rpython.flowspace.model import (Variable, Constant, FunctionGraph, - c_last_exception, checkgraph) +from rpython.flowspace.model import ( + Variable, Constant, FunctionGraph, checkgraph) from rpython.translator import simplify, transform from rpython.annotator import model as annmodel, signature from rpython.annotator.argument import simple_args @@ -399,16 +399,25 @@ def flowin(self, graph, block): try: - for i, op in enumerate(block.operations): + i = 0 + while i < len(block.operations): + op = block.operations[i] self.bookkeeper.enter((graph, block, i)) try: + new_ops = op.transform(self) + if new_ops is not None: + block.operations[i:i+1] = new_ops + if not new_ops: + continue + new_ops[-1].result = op.result + op = new_ops[0] self.consider_op(op) finally: self.bookkeeper.leave() + i += 1 except BlockedInference as e: - if (e.op is block.operations[-1] and - block.exitswitch == c_last_exception): + if e.op is block.raising_op: # this is the case where the last operation of the block will # always raise an exception which is immediately caught by # an exception handler. We then only follow the exceptional @@ -450,8 +459,8 @@ # filter out those exceptions which cannot # occour for this specific, typed operation. - if block.exitswitch == c_last_exception: - op = block.operations[-1] + if block.canraise: + op = block.raising_op can_only_throw = op.get_can_only_throw(self) if can_only_throw is not None: candidates = can_only_throw diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -2,7 +2,6 @@ Binary operations between SomeValues. """ -import operator from rpython.tool.pairtype import pair, pairtype from rpython.annotator.model import ( SomeObject, SomeInteger, SomeBool, s_Bool, SomeString, SomeChar, SomeList, @@ -14,7 +13,7 @@ read_can_only_throw, add_knowntypedata, merge_knowntypedata,) from rpython.annotator.bookkeeper import immutablevalue -from rpython.flowspace.model import Variable, Constant +from rpython.flowspace.model import Variable, Constant, const from rpython.flowspace.operation import op from rpython.rlib import rarithmetic from rpython.annotator.model import AnnotatorError @@ -689,12 +688,16 @@ return super(thistype, pair(ins1, ins2)).improve() -class __extend__(pairtype(SomeInstance, SomeObject)): - def getitem((s_ins, s_idx)): - return s_ins._emulate_call("__getitem__", s_idx) +@op.getitem.register_transform(SomeInstance, SomeObject) +def getitem_SomeInstance(annotator, v_ins, v_idx): + get_getitem = op.getattr(v_ins, const('__getitem__')) + return [get_getitem, op.simple_call(get_getitem.result, v_idx)] - def setitem((s_ins, s_idx), s_value): - return s_ins._emulate_call("__setitem__", s_idx, s_value) +@op.setitem.register_transform(SomeInstance, SomeObject) +def setitem_SomeInstance(annotator, v_ins, v_idx, v_value): + get_setitem = op.getattr(v_ins, const('__setitem__')) + return [get_setitem, + op.simple_call(get_setitem.result, v_idx, v_value)] class __extend__(pairtype(SomeIterator, SomeIterator)): diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -5,6 +5,7 @@ from __future__ import absolute_import from rpython.flowspace.operation import op +from rpython.flowspace.model import const from rpython.annotator.model import (SomeObject, SomeInteger, SomeBool, SomeString, SomeChar, SomeList, SomeDict, SomeTuple, SomeImpossibleValue, SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod, @@ -686,27 +687,33 @@ if not self.can_be_None: s.const = True - def _emulate_call(self, meth_name, *args_s): - bk = getbookkeeper() - s_attr = self._true_getattr(meth_name) - # record for calltables - bk.emulate_pbc_call(bk.position_key, s_attr, args_s) - return s_attr.call(simple_args(args_s)) +@op.len.register_transform(SomeInstance) +def len_SomeInstance(annotator, v_arg): + get_len = op.getattr(v_arg, const('__len__')) + return [get_len, op.simple_call(get_len.result)] - def iter(self): - return self._emulate_call('__iter__') +@op.iter.register_transform(SomeInstance) +def iter_SomeInstance(annotator, v_arg): + get_iter = op.getattr(v_arg, const('__iter__')) + return [get_iter, op.simple_call(get_iter.result)] - def next(self): - return self._emulate_call('next') +@op.next.register_transform(SomeInstance) +def next_SomeInstance(annotator, v_arg): + get_next = op.getattr(v_arg, const('next')) + return [get_next, op.simple_call(get_next.result)] - def len(self): - return self._emulate_call('__len__') +@op.getslice.register_transform(SomeInstance) +def getslice_SomeInstance(annotator, v_obj, v_start, v_stop): + get_getslice = op.getattr(v_obj, const('__getslice__')) + return [get_getslice, op.simple_call(get_getslice.result, v_start, v_stop)] - def getslice(self, s_start, s_stop): - return self._emulate_call('__getslice__', s_start, s_stop) - def setslice(self, s_start, s_stop, s_iterable): - return self._emulate_call('__setslice__', s_start, s_stop, s_iterable) +@op.setslice.register_transform(SomeInstance) +def setslice_SomeInstance(annotator, v_obj, v_start, v_stop, v_iterable): + get_setslice = op.getattr(v_obj, const('__setslice__')) + return [get_setslice, + op.simple_call(get_setslice.result, v_start, v_stop, v_iterable)] + class __extend__(SomeBuiltin): def call(self, args, implicit_init=False): diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -7,7 +7,6 @@ import __builtin__ from rpython.tool.error import source_lines -from rpython.translator.simplify import eliminate_empty_blocks from rpython.rlib import rstackovf from rpython.flowspace.argument import CallSpec from rpython.flowspace.model import (Constant, Variable, Block, Link, @@ -124,7 +123,6 @@ def guessexception(self, ctx, *cases): block = self.crnt_block - bvars = vars = vars2 = block.getvariables() links = [] for case in [None] + list(cases): if case is not None: diff --git a/rpython/flowspace/model.py b/rpython/flowspace/model.py --- a/rpython/flowspace/model.py +++ b/rpython/flowspace/model.py @@ -190,6 +190,15 @@ txt = "%s(%s)" % (txt, self.exitswitch) return txt + @property + def canraise(self): + return self.exitswitch is c_last_exception + + @property + def raising_op(self): + if self.canraise: + return self.operations[-1] + def getvariables(self): "Return all variables mentioned in this Block." result = self.inputargs[:] @@ -591,11 +600,11 @@ assert len(block.exits) <= 1 if block.exits: assert block.exits[0].exitcase is None - elif block.exitswitch == Constant(last_exception): + elif block.canraise: assert len(block.operations) >= 1 # check if an exception catch is done on a reasonable # operation - assert block.operations[-1].opname not in ("keepalive", + assert block.raising_op.opname not in ("keepalive", "cast_pointer", "same_as") assert len(block.exits) >= 2 diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py --- a/rpython/flowspace/operation.py +++ b/rpython/flowspace/operation.py @@ -57,8 +57,10 @@ setattr(op, cls.opname, cls) if cls.dispatch == 1: cls._registry = {} + cls._transform = {} elif cls.dispatch == 2: cls._registry = DoubleDispatchRegistry() + cls._transform = DoubleDispatchRegistry() class HLOperation(SpaceOperation): @@ -104,6 +106,14 @@ def get_can_only_throw(self, annotator): return None + def get_transformer(self, *args_s): + return lambda *args: None + + def transform(self, annotator): + args_s = [annotator.annotation(arg) for arg in self.args] + transformer = self.get_transformer(*args_s) + return transformer(annotator, *self.args) + class PureOperation(HLOperation): pure = True @@ -185,6 +195,37 @@ except AttributeError: return cls._dispatch(type(s_arg)) + @classmethod + def get_specialization(cls, s_arg, *_ignored): + try: + impl = getattr(s_arg, cls.opname) + + def specialized(annotator, arg, *other_args): + return impl(*[annotator.annotation(x) for x in other_args]) + try: + specialized.can_only_throw = impl.can_only_throw + except AttributeError: + pass + return specialized + except AttributeError: + return cls._dispatch(type(s_arg)) + + @classmethod + def register_transform(cls, Some_cls): + def decorator(func): + cls._transform[Some_cls] = func + return func + return decorator + + @classmethod + def get_transformer(cls, s_arg, *_ignored): + for c in type(s_arg).__mro__: + try: + return cls._transform[c] + except KeyError: + pass + return lambda *args: None + class DoubleDispatchMixin(object): dispatch = 2 @@ -216,6 +257,20 @@ spec = type(self).get_specialization(*args_s) return read_can_only_throw(spec, args_s[0], args_s[1]) + @classmethod + def register_transform(cls, Some1, Some2): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit