Author: anton_gulenko <[email protected]> Branch: Changeset: r76870:fe4c27d34d37 Date: 2015-03-07 16:20 +0100 http://bitbucket.org/pypy/pypy/changeset/fe4c27d34d37/
Log: Merged pypy/pypy into default diff too long, truncating to 2000 out of 4777 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/lib_pypy/gdbm.py b/lib_pypy/gdbm.py --- a/lib_pypy/gdbm.py +++ b/lib_pypy/gdbm.py @@ -20,9 +20,11 @@ } datum; datum gdbm_fetch(void*, datum); +datum pygdbm_fetch(void*, char*, int); int gdbm_delete(void*, datum); int gdbm_store(void*, datum, datum, int); int gdbm_exists(void*, datum); +int pygdbm_exists(void*, char*, int); int gdbm_reorganize(void*); @@ -37,19 +39,29 @@ ''') try: + verify_code = ''' + #include "gdbm.h" + + static datum pygdbm_fetch(GDBM_FILE gdbm_file, char *dptr, int dsize) { + datum key = {dptr, dsize}; + return gdbm_fetch(gdbm_file, key); + } + + static int pygdbm_exists(GDBM_FILE gdbm_file, char *dptr, int dsize) { + datum key = {dptr, dsize}; + return gdbm_exists(gdbm_file, key); + } + + ''' if sys.platform.startswith('freebsd'): import os.path _localbase = os.environ.get('LOCALBASE', '/usr/local') - lib = ffi.verify(''' - #include "gdbm.h" - ''', libraries=['gdbm'], + lib = ffi.verify(verify_code, libraries=['gdbm'], include_dirs=[os.path.join(_localbase, 'include')], library_dirs=[os.path.join(_localbase, 'lib')] ) else: - lib = ffi.verify(''' - #include "gdbm.h" - ''', libraries=['gdbm']) + lib = ffi.verify(verify_code, libraries=['gdbm']) except cffi.VerificationError as e: # distutils does not preserve the actual message, # but the verification is simple enough that the @@ -59,6 +71,13 @@ class error(Exception): pass +def _checkstr(key): + if isinstance(key, unicode): + key = key.encode("ascii") + if not isinstance(key, str): + raise TypeError("gdbm mappings have string indices only") + return key + def _fromstr(key): if isinstance(key, unicode): key = key.encode("ascii") @@ -107,12 +126,14 @@ def __contains__(self, key): self._check_closed() - return lib.gdbm_exists(self.ll_dbm, _fromstr(key)) + key = _checkstr(key) + return lib.pygdbm_exists(self.ll_dbm, key, len(key)) has_key = __contains__ def __getitem__(self, key): self._check_closed() - drec = lib.gdbm_fetch(self.ll_dbm, _fromstr(key)) + key = _checkstr(key) + drec = lib.pygdbm_fetch(self.ll_dbm, key, len(key)) if not drec.dptr: raise KeyError(key) res = str(ffi.buffer(drec.dptr, drec.dsize)) diff --git a/lib_pypy/pyrepl/readline.py b/lib_pypy/pyrepl/readline.py --- a/lib_pypy/pyrepl/readline.py +++ b/lib_pypy/pyrepl/readline.py @@ -73,7 +73,6 @@ assume_immutable_completions = False use_brackets = False sort_in_column = True - tab_insert_spaces_if_stem_is_empty = False def error(self, msg="none"): pass # don't show error messages by default @@ -87,7 +86,7 @@ return ''.join(b[p+1:self.pos]) def get_completions(self, stem): - if len(stem) == 0 and self.tab_insert_spaces_if_stem_is_empty: + if len(stem) == 0 and self.more_lines is not None: b = self.buffer p = self.pos while p > 0 and b[p - 1] != '\n': @@ -141,12 +140,16 @@ def collect_keymap(self): return super(ReadlineAlikeReader, self).collect_keymap() + ( - (r'\n', 'maybe-accept'),) + (r'\n', 'maybe-accept'), + (r'\<backspace>', 'backspace-dedent'), + ) def __init__(self, console): super(ReadlineAlikeReader, self).__init__(console) self.commands['maybe_accept'] = maybe_accept self.commands['maybe-accept'] = maybe_accept + self.commands['backspace_dedent'] = backspace_dedent + self.commands['backspace-dedent'] = backspace_dedent def after_command(self, cmd): super(ReadlineAlikeReader, self).after_command(cmd) @@ -164,6 +167,28 @@ if self.pos > len(self.buffer): self.pos = len(self.buffer) +def _get_this_line_indent(buffer, pos): + indent = 0 + while pos > 0 and buffer[pos - 1] in " \t": + indent += 1 + pos -= 1 + if pos > 0 and buffer[pos - 1] == "\n": + return indent + return 0 + +def _get_previous_line_indent(buffer, pos): + prevlinestart = pos + while prevlinestart > 0 and buffer[prevlinestart - 1] != "\n": + prevlinestart -= 1 + prevlinetext = prevlinestart + while prevlinetext < pos and buffer[prevlinetext] in " \t": + prevlinetext += 1 + if prevlinetext == pos: + indent = None + else: + indent = prevlinetext - prevlinestart + return prevlinestart, indent + class maybe_accept(commands.Command): def do(self): r = self.reader @@ -172,13 +197,39 @@ # if there are already several lines and the cursor # is not on the last one, always insert a new \n. text = r.get_unicode() - if "\n" in r.buffer[r.pos:]: + if ("\n" in r.buffer[r.pos:] or + (r.more_lines is not None and r.more_lines(text))): + # + # auto-indent the next line like the previous line + prevlinestart, indent = _get_previous_line_indent(r.buffer, r.pos) r.insert("\n") - elif r.more_lines is not None and r.more_lines(text): - r.insert("\n") + if indent: + for i in range(prevlinestart, prevlinestart + indent): + r.insert(r.buffer[i]) else: self.finish = 1 +class backspace_dedent(commands.Command): + def do(self): + r = self.reader + b = r.buffer + if r.pos > 0: + repeat = 1 + if b[r.pos - 1] != "\n": + indent = _get_this_line_indent(b, r.pos) + if indent > 0: + ls = r.pos - indent + while ls > 0: + ls, pi = _get_previous_line_indent(b, ls - 1) + if pi is not None and pi < indent: + repeat = indent - pi + break + r.pos -= repeat + del b[r.pos:r.pos + repeat] + r.dirty = 1 + else: + self.reader.error("can't backspace at start") + # ____________________________________________________________ class _ReadlineWrapper(object): @@ -212,15 +263,14 @@ boolean value is true. """ reader = self.get_reader() - saved = reader.more_lines, reader.tab_insert_spaces_if_stem_is_empty + saved = reader.more_lines try: reader.more_lines = more_lines reader.ps1 = reader.ps2 = ps1 reader.ps3 = reader.ps4 = ps2 - reader.tab_insert_spaces_if_stem_is_empty = True return reader.readline(returns_unicode=returns_unicode) finally: - reader.more_lines, reader.tab_insert_spaces_if_stem_is_empty = saved + reader.more_lines = saved def parse_and_bind(self, string): pass # XXX we don't support parsing GNU-readline-style init files diff --git a/pypy/conftest.py b/pypy/conftest.py --- a/pypy/conftest.py +++ b/pypy/conftest.py @@ -36,7 +36,7 @@ def pytest_addoption(parser): from rpython.conftest import pytest_addoption pytest_addoption(parser) - + group = parser.getgroup("pypy options") group.addoption('-A', '--runappdirect', action="store_true", default=False, dest="runappdirect", @@ -44,6 +44,9 @@ group.addoption('--direct', action="store_true", default=False, dest="rundirect", help="run pexpect tests directly") + group.addoption('--raise-operr', action="store_true", + default=False, dest="raise_operr", + help="Show the interp-level OperationError in app-level tests") def pytest_funcarg__space(request): from pypy.tool.pytest.objspace import gettestobjspace diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst --- a/pypy/doc/embedding.rst +++ b/pypy/doc/embedding.rst @@ -36,7 +36,8 @@ "PyPy home directory". The arguments are: * ``home``: NULL terminated path to an executable inside the pypy directory - (can be a .so name, can be made up) + (can be a .so name, can be made up). Used to look up the standard + library, and is also set as ``sys.executable``. * ``verbose``: if non-zero, it will print error messages to stderr diff --git a/pypy/doc/jit-hooks.rst b/pypy/doc/jit-hooks.rst --- a/pypy/doc/jit-hooks.rst +++ b/pypy/doc/jit-hooks.rst @@ -39,3 +39,30 @@ Reason is a string, the meaning of other arguments is the same as attributes on JitLoopInfo object +.. function:: enable_debug() + + Start recording debugging counters for ``get_stats_snapshot`` + +.. function:: disable_debug() + + Stop recording debugging counters for ``get_stats_snapshot`` + +.. function:: get_stats_snapshot() + + Get the jit status in the specific moment in time. Note that this + is eager - the attribute access is not lazy, if you need new stats + you need to call this function again. You might want to call + ``enable_debug`` to get more information. It returns an instance + of ``JitInfoSnapshot`` + +.. class:: JitInfoSnapshot + + A class describing current snapshot. Usable attributes: + + * ``counters`` - internal JIT integer counters + + * ``counter_times`` - internal JIT float counters, notably time spent + TRACING and in the JIT BACKEND + + * ``loop_run_times`` - counters for number of times loops are run, only + works when ``enable_debug`` is called. 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 @@ -30,3 +30,10 @@ .. branch: alt_errno Add an alternative location to save LastError, errno around ctypes, cffi external calls so things like pdb will not overwrite it + +.. 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/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -106,6 +106,9 @@ space.call_function(w_pathsetter, w_path) # import site try: + space.setattr(space.getbuiltinmodule('sys'), + space.wrap('executable'), + space.wrap(home)) import_ = space.getattr(space.getbuiltinmodule('__builtin__'), space.wrap('__import__')) space.call_function(import_, space.wrap('site')) diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -1,5 +1,5 @@ #! /usr/bin/env python -# App-level version of py.py. +# This is pure Python code that handles the main entry point into "pypy". # See test/test_app_main. # Missing vs CPython: -d, -t, -v, -x, -3 @@ -157,10 +157,13 @@ current = group raise SystemExit +def get_sys_executable(): + return getattr(sys, 'executable', 'pypy') + def print_help(*args): import os print 'usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...' % ( - sys.executable,) + get_sys_executable(),) print USAGE1, if 'pypyjit' in sys.builtin_module_names: print "--jit options: advanced JIT options: try 'off' or 'help'" @@ -171,7 +174,7 @@ try: import pypyjit except ImportError: - print >> sys.stderr, "No jit support in %s" % (sys.executable,) + print >> sys.stderr, "No jit support in %s" % (get_sys_executable(),) return items = sorted(pypyjit.defaults.items()) print 'Advanced JIT options: a comma-separated list of OPTION=VALUE:' @@ -209,7 +212,7 @@ raise SystemExit if 'pypyjit' not in sys.builtin_module_names: print >> sys.stderr, ("Warning: No jit support in %s" % - (sys.executable,)) + (get_sys_executable(),)) else: import pypyjit pypyjit.set_param(jitparam) @@ -219,8 +222,8 @@ def print_error(msg): print >> sys.stderr, msg - print >> sys.stderr, 'usage: %s [options]' % (sys.executable,) - print >> sys.stderr, 'Try `%s -h` for more information.' % (sys.executable,) + print >> sys.stderr, 'usage: %s [options]' % (get_sys_executable(),) + print >> sys.stderr, 'Try `%s -h` for more information.' % (get_sys_executable(),) def fdopen(fd, mode, bufsize=-1): try: @@ -514,6 +517,10 @@ elif not sys.stdout.isatty(): set_fully_buffered_io() + if we_are_translated(): + import __pypy__ + __pypy__.save_module_content_for_future_reload(sys) + mainmodule = type(sys)('__main__') sys.modules['__main__'] = mainmodule diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py --- a/pypy/interpreter/mixedmodule.py +++ b/pypy/interpreter/mixedmodule.py @@ -55,7 +55,10 @@ if self.w_initialdict is None: Module.init(self, space) if not self.lazy and self.w_initialdict is None: - self.w_initialdict = space.call_method(self.w_dict, 'items') + self.save_module_content_for_future_reload() + + def save_module_content_for_future_reload(self): + self.w_initialdict = self.space.call_method(self.w_dict, 'items') def get_applevel_name(cls): @@ -119,7 +122,7 @@ w_value = self.get(name) space.setitem(self.w_dict, space.new_interned_str(name), w_value) self.lazy = False - self.w_initialdict = space.call_method(self.w_dict, 'items') + self.save_module_content_for_future_reload() return self.w_dict def _cleanup_(self): diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py --- a/pypy/interpreter/test/test_objspace.py +++ b/pypy/interpreter/test/test_objspace.py @@ -373,7 +373,7 @@ config = make_config(None) space = make_objspace(config) w_executable = space.wrap('executable') - assert space.str_w(space.getattr(space.sys, w_executable)) == 'py.py' + assert space.findattr(space.sys, w_executable) is None space.setattr(space.sys, w_executable, space.wrap('foobar')) assert space.str_w(space.getattr(space.sys, w_executable)) == 'foobar' space.startup() diff --git a/pypy/interpreter/test/test_targetpypy.py b/pypy/interpreter/test/test_targetpypy.py --- a/pypy/interpreter/test/test_targetpypy.py +++ b/pypy/interpreter/test/test_targetpypy.py @@ -8,7 +8,7 @@ entry_point = get_entry_point(config)[0] entry_point(['pypy-c' , '-S', '-c', 'print 3']) -def test_exeucte_source(space): +def test_execute_source(space): _, d = create_entry_point(space, None) execute_source = d['pypy_execute_source'] lls = rffi.str2charp("import sys; sys.modules['xyz'] = 3") diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -82,6 +82,8 @@ 'strategy' : 'interp_magic.strategy', # dict,set,list 'set_debug' : 'interp_magic.set_debug', 'locals_to_fast' : 'interp_magic.locals_to_fast', + 'save_module_content_for_future_reload': + 'interp_magic.save_module_content_for_future_reload', } if sys.platform == 'win32': interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp' diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -1,6 +1,7 @@ from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.pyframe import PyFrame +from pypy.interpreter.mixedmodule import MixedModule from rpython.rlib.objectmodel import we_are_translated from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.listobject import W_ListObject @@ -130,3 +131,7 @@ def locals_to_fast(space, w_frame): assert isinstance(w_frame, PyFrame) w_frame.locals2fast() + +@unwrap_spec(w_module=MixedModule) +def save_module_content_for_future_reload(space, w_module): + w_module.save_module_content_for_future_reload() diff --git a/pypy/module/__pypy__/test/test_magic.py b/pypy/module/__pypy__/test/test_magic.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_magic.py @@ -0,0 +1,15 @@ + +class AppTestMagic: + spaceconfig = dict(usemodules=['__pypy__']) + + def test_save_module_content_for_future_reload(self): + import sys, __pypy__ + d = sys.dont_write_bytecode + sys.dont_write_bytecode = "hello world" + __pypy__.save_module_content_for_future_reload(sys) + sys.dont_write_bytecode = d + reload(sys) + assert sys.dont_write_bytecode == "hello world" + # + sys.dont_write_bytecode = d + __pypy__.save_module_content_for_future_reload(sys) 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/_rawffi/array.py b/pypy/module/_rawffi/array.py --- a/pypy/module/_rawffi/array.py +++ b/pypy/module/_rawffi/array.py @@ -15,7 +15,7 @@ from pypy.module._rawffi.interp_rawffi import unpack_shape_with_length from pypy.module._rawffi.interp_rawffi import read_ptr, write_ptr from rpython.rlib.rarithmetic import r_uint -from rpython.rlib import rgc +from rpython.rlib import rgc, clibffi class W_Array(W_DataShape): @@ -84,14 +84,11 @@ class W_ArrayInstance(W_DataInstance): def __init__(self, space, shape, length, address=r_uint(0)): - # Workaround for a strange behavior of libffi: make sure that - # we always have at least 8 bytes. For W_ArrayInstances that are - # used as the result value of a function call, ffi_call() writes - # 8 bytes into it even if the function's result type asks for less. - # This strange behavior is documented. memsize = shape.size * length - if memsize < 8: - memsize = 8 + # For W_ArrayInstances that are used as the result value of a + # function call, ffi_call() writes 8 bytes into it even if the + # function's result type asks for less. + memsize = clibffi.adjust_return_size(memsize) W_DataInstance.__init__(self, space, memsize, address) self.length = length self.shape = shape diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -495,6 +495,7 @@ try: if self.resshape is not None: result = self.resshape.allocate(space, 1, autofree=True) + # adjust_return_size() was used here on result.ll_buffer self.ptr.call(args_ll, result.ll_buffer) return space.wrap(result) else: 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 @@ -1,4 +1,4 @@ -from rpython.rlib import jit +from rpython.rlib import jit, rgc from rpython.rlib.buffer import Buffer from rpython.rlib.objectmodel import keepalive_until_here from rpython.rlib.rarithmetic import ovfcheck, widen @@ -698,11 +698,9 @@ self.space.wrap(msg)) return result + @rgc.must_be_light_finalizer def __del__(self): - # note that we don't call clear_all_weakrefs here because - # an array with freed buffer is ok to see - it's just empty with 0 - # length - self.setlen(0) + lltype.free(self.buffer, flavor='raw') def setlen(self, size, zero=False, overallocate=True): if size > 0: 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) _______________________________________________ pypy-commit mailing list [email protected] https://mail.python.org/mailman/listinfo/pypy-commit
