Author: Ronan Lamy <ronan.l...@gmail.com> Branch: py3k Changeset: r84911:b56f881df46b Date: 2016-06-03 19:55 +0100 http://bitbucket.org/pypy/pypy/changeset/b56f881df46b/
Log: hg merge default (f731f9ef48f8) diff --git a/pypy/doc/release-pypy2.7-v5.3.0.rst b/pypy/doc/release-pypy2.7-v5.3.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-pypy2.7-v5.3.0.rst @@ -0,0 +1,139 @@ +============ +PyPy2.7 v5.3 +============ + +We have released PyPy2.7 v5.3, about six weeks after PyPy 5.1. +This release includes further improvements for the CAPI compatibility layer +which we call cpyext. In addtion to complete support for lxml, we now pass +most (more than 90%) of the upstream numpy test suite, and much of SciPy is +supported as well. + +We also improved the speed of ... and ... + +We updated cffi_ to ... + +You can download the PyPy2.7 v5.3 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project. + +We would also like to thank our contributors and +encourage new people to join the project. PyPy has many +layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation +improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ +with making RPython's JIT even better. + +.. _`PyPy`: http://doc.pypy.org +.. _`RPython`: https://rpython.readthedocs.org +.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html +.. _`numpy`: https://bitbucket.org/pypy/numpy +.. _cffi: https://cffi.readthedocs.org +.. _`fully support for the IBM s390x`: http://morepypy.blogspot.com/2016/04/pypy-enterprise-edition.html +.. _`blog post`: http://morepypy.blogspot.com/2016/04/warmup-improvements-more-efficient.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`PyPy and CPython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +We also welcome developers of other +`dynamic languages`_ to see what RPython can do for them. + +This release supports: + + * **x86** machines on most common operating systems + (Linux 32/64, Mac OS X 64, Windows 32, OpenBSD, FreeBSD), + + * newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux, + + * big- and little-endian variants of **PPC64** running Linux, + + * **s390x** running Linux + +.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org +.. _`dynamic languages`: http://pypyjs.org + +Other Highlights (since 5.1 released in April 2016) +========================================================= + +* New features: + + * Merge a major expansion of the C-API support in cpyext, here are some of + the highlights: + - allow c-snippet tests to be run with -A so we can verify we are compatible + - fix many edge cases exposed by fixing tests to run with -A + - issequence() logic matches cpython + - make PyStringObject and PyUnicodeObject field names compatible with cpython + - add prelminary support for PyDateTime_* + - support PyComplexObject, PyFloatObject, PyDict_Merge, PyDictProxy, + PyMemoryView_*, _Py_HashDouble, PyFile_AsFile, PyFile_FromFile, + - PyAnySet_CheckExact, PyUnicode_Concat + - improve support for PyGILState_Ensure, PyGILState_Release, and thread + primitives, also find a case where CPython will allow thread creation + before PyEval_InitThreads is run, dissallow on PyPy + - create a PyObject-specific list strategy + - rewrite slot assignment for typeobjects + - improve tracking of PyObject to rpython object mapping + - support tp_as_{number, sequence, mapping, buffer} slots + + * CPyExt tweak: instead of "GIL not held when a CPython C extension module + calls PyXxx", we now silently acquire/release the GIL. Helps with + CPython C extension modules that call some PyXxx() functions without + holding the GIL (arguably, they are theorically buggy). + + * Add rgc.FinalizerQueue, documented in pypy/doc/discussion/finalizer-order.rst. + It is a more flexible way to make RPython finalizers. Use this mechanism to + clean up handling of ``__del__`` methods, fixing issue #2287 + + * Generalize cpyext old-style buffers to more than just str/buffer, add + support for mmap + +* Bug Fixes + + * Issues reported with our previous release were resolved_ after reports from users on + our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at + #pypy + +* Numpy_: + + * Implement ufunc.outer on numpypy + +* Performance improvements: + + * Use bitstrings to compress lists of descriptors that are attached to an + EffectInfo + + * Remove most of the _ovf, _zer and _val operations from RPython. Kills + quite some code internally, and allows the JIT to do better + optimizations: for example, app-level code like ``x / 2`` or ``x % 2`` + can now be turned into ``x >> 1`` or ``x & 1``, even if x is possibly + negative. + + +* Internal refactorings: + + * Reduce the size of generated C sources during translation by + refactoring function declarations + + * Remove a number of translation-time options that were not tested and + never used. Also fix a performance bug in the method cache + + * Reduce the size of generated code by using the same function objects in + all generated subclasses + + * Compile c snippets with -Werror, and fix warnings it exposed + +.. _resolved: http://doc.pypy.org/en/latest/whatsnew-5.3.0.html +.. _Numpy: https://bitbucket.org/pypy/numpy + +Please update, and continue to help us make PyPy better. + +Cheers + +The PyPy Team + diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -669,7 +669,6 @@ self.emit_jump(ops.JUMP_FORWARD, end) self.use_next_block(next_except) self.emit_op(ops.END_FINALLY) # this END_FINALLY will always re-raise - self.is_dead_code() self.use_next_block(otherwise) self.visit_sequence(tr.orelse) self.use_next_block(end) diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,8 +29,8 @@ #define PY_VERSION "3.3.5" /* PyPy version as a string */ -#define PYPY_VERSION "5.2.0-alpha0" -#define PYPY_VERSION_NUM 0x05020000 +#define PYPY_VERSION "5.3.0-alpha0" +#define PYPY_VERSION_NUM 0x05030000 /* Defined to mean a PyPy where cpyext holds more regular references to PyObjects, e.g. staying alive as long as the internal PyPy object diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -10,7 +10,7 @@ #XXX # sync CPYTHON_VERSION with patchlevel.h, package.py CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (5, 2, 0, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (5, 3, 0, "alpha", 0) #XXX # sync patchlevel.h import pypy diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -460,9 +460,8 @@ def _hexstring_to_array(space, s): data = [] length = len(s) - i = -2 + i = 0 while True: - i += 2 while i < length and s[i] == ' ': i += 1 if i >= length: @@ -483,6 +482,7 @@ "non-hexadecimal number found in fromhex() arg at " "position %d", i + 1) data.append(chr(top*16 + bot)) + i += 2 return data diff --git a/rpython/memory/gc/base.py b/rpython/memory/gc/base.py --- a/rpython/memory/gc/base.py +++ b/rpython/memory/gc/base.py @@ -184,7 +184,7 @@ def can_move(self, addr): return False - def malloc_fixedsize_nonmovable(self, typeid): + def malloc_fixed_or_varsize_nonmovable(self, typeid, length): raise MemoryError def pin(self, addr): diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py --- a/rpython/memory/gc/incminimark.py +++ b/rpython/memory/gc/incminimark.py @@ -718,8 +718,9 @@ return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF) - def malloc_fixedsize_nonmovable(self, typeid): - obj = self.external_malloc(typeid, 0, alloc_young=True) + def malloc_fixed_or_varsize_nonmovable(self, typeid, length): + # length==0 for fixedsize + obj = self.external_malloc(typeid, length, alloc_young=True) return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF) diff --git a/rpython/memory/gc/minimark.py b/rpython/memory/gc/minimark.py --- a/rpython/memory/gc/minimark.py +++ b/rpython/memory/gc/minimark.py @@ -628,8 +628,9 @@ return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF) - def malloc_fixedsize_nonmovable(self, typeid): - obj = self.external_malloc(typeid, 0, alloc_young=True) + def malloc_fixed_or_varsize_nonmovable(self, typeid, length): + # length==0 for fixedsize + obj = self.external_malloc(typeid, length, alloc_young=True) return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF) diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -530,9 +530,10 @@ getfn(func, [SomeAddress()], annmodel.s_None) - self.malloc_nonmovable_ptr = getfn(GCClass.malloc_fixedsize_nonmovable, - [s_gc, s_typeid16], - s_gcref) + self.malloc_nonmovable_ptr = getfn( + GCClass.malloc_fixed_or_varsize_nonmovable, + [s_gc, s_typeid16, annmodel.SomeInteger()], + s_gcref) self.register_finalizer_ptr = getfn(GCClass.register_finalizer, [s_gc, @@ -773,12 +774,16 @@ c_has_light_finalizer = rmodel.inputconst(lltype.Bool, has_light_finalizer) + is_varsize = op.opname.endswith('_varsize') or flags.get('varsize') + if flags.get('nonmovable'): - assert op.opname == 'malloc' - assert not flags.get('varsize') + if not is_varsize: + v_length = rmodel.inputconst(lltype.Signed, 0) + else: + v_length = op.args[-1] malloc_ptr = self.malloc_nonmovable_ptr - args = [self.c_const_gc, c_type_id] - elif not op.opname.endswith('_varsize') and not flags.get('varsize'): + args = [self.c_const_gc, c_type_id, v_length] + elif not is_varsize: zero = flags.get('zero', False) if (self.malloc_fast_ptr is not None and not c_has_finalizer.value and diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py --- a/rpython/rlib/rgc.py +++ b/rpython/rlib/rgc.py @@ -1001,3 +1001,259 @@ def specialize_call(self, hop): hop.exception_cannot_occur() return hop.genop('gc_gettypeid', hop.args_v, resulttype=lltype.Signed) + +# ____________________________________________________________ + + +class _rawptr_missing_item(object): + pass +_rawptr_missing_item = _rawptr_missing_item() + + +class _ResizableListSupportingRawPtr(list): + """Calling this class is a no-op after translation. + + Before translation, it returns a new instance of + _ResizableListSupportingRawPtr, on which + rgc.nonmoving_raw_ptr_for_resizable_list() might be + used if needed. For now, only supports lists of chars. + """ + __slots__ = ('_raw_items',) # either None or a rffi.CCHARP + + def __init__(self, lst): + self._raw_items = None + self.__from_list(lst) + + def __resize(self): + """Called before an operation changes the size of the list""" + if self._raw_items is not None: + list.__init__(self, self.__as_list()) + self._raw_items = None + + def __from_list(self, lst): + """Initialize the list from a copy of the list 'lst'.""" + assert isinstance(lst, list) + for x in lst: + assert isinstance(x, str) and len(x) == 1 + if self is lst: + return + if len(self) != len(lst): + self.__resize() + if self._raw_items is None: + list.__init__(self, lst) + else: + assert len(self) == self._raw_items._obj.getlength() == len(lst) + for i in range(len(self)): + self._raw_items[i] = lst[i] + + def __as_list(self): + """Return a list (the same or a different one) which contains the + items in the regular way.""" + if self._raw_items is None: + return self + length = self._raw_items._obj.getlength() + assert length == len(self) + return [self._raw_items[i] for i in range(length)] + + def __getitem__(self, index): + if self._raw_items is None: + return list.__getitem__(self, index) + if index < 0: + index += len(self) + if not (0 <= index < len(self)): + raise IndexError + return self._raw_items[index] + + def __setitem__(self, index, new): + if self._raw_items is None: + return list.__setitem__(self, index, new) + if index < 0: + index += len(self) + if not (0 <= index < len(self)): + raise IndexError + self._raw_items[index] = new + + def __delitem__(self, index): + self.__resize() + list.__delitem__(self, index) + + def __getslice__(self, i, j): + return list.__getslice__(self.__as_list(), i, j) + + def __setslice__(self, i, j, new): + lst = self.__as_list() + list.__setslice__(lst, i, j, new) + self.__from_list(lst) + + def __delslice__(self, i, j): + lst = self.__as_list() + list.__delslice__(lst, i, j) + self.__from_list(lst) + + def __iter__(self): + try: + i = 0 + while True: + yield self[i] + i += 1 + except IndexError: + pass + + def __reversed__(self): + i = len(self) + while i > 0: + i -= 1 + yield self[i] + + def __contains__(self, item): + return list.__contains__(self.__as_list(), item) + + def __add__(self, other): + if isinstance(other, _ResizableListSupportingRawPtr): + other = other.__as_list() + return list.__add__(self.__as_list(), other) + + def __radd__(self, other): + if isinstance(other, _ResizableListSupportingRawPtr): + other = other.__as_list() + return list.__add__(other, self.__as_list()) + + def __iadd__(self, other): + self.__resize() + return list.__iadd__(self, other) + + def __eq__(self, other): + return list.__eq__(self.__as_list(), other) + def __ne__(self, other): + return list.__ne__(self.__as_list(), other) + def __ge__(self, other): + return list.__ge__(self.__as_list(), other) + def __gt__(self, other): + return list.__gt__(self.__as_list(), other) + def __le__(self, other): + return list.__le__(self.__as_list(), other) + def __lt__(self, other): + return list.__lt__(self.__as_list(), other) + + def __mul__(self, other): + return list.__mul__(self.__as_list(), other) + + def __rmul__(self, other): + return list.__mul__(self.__as_list(), other) + + def __imul__(self, other): + self.__resize() + return list.__imul__(self, other) + + def __repr__(self): + return '_ResizableListSupportingRawPtr(%s)' % ( + list.__repr__(self.__as_list()),) + + def append(self, object): + self.__resize() + return list.append(self, object) + + def count(self, value): + return list.count(self.__as_list(), value) + + def extend(self, iterable): + self.__resize() + return list.extend(self, iterable) + + def index(self, value, *start_stop): + return list.index(self.__as_list(), value, *start_stop) + + def insert(self, index, object): + self.__resize() + return list.insert(self, index, object) + + def pop(self, *opt_index): + self.__resize() + return list.pop(self, *opt_index) + + def remove(self, value): + self.__resize() + return list.remove(self, value) + + def reverse(self): + lst = self.__as_list() + list.reverse(lst) + self.__from_list(lst) + + def sort(self, *args, **kwds): + lst = self.__as_list() + list.sort(lst, *args, **kwds) + self.__from_list(lst) + + def _nonmoving_raw_ptr_for_resizable_list(self): + if self._raw_items is None: + existing_items = list(self) + from rpython.rtyper.lltypesystem import lltype, rffi + self._raw_items = lltype.malloc(rffi.CCHARP.TO, len(self), + flavor='raw', immortal=True) + self.__from_list(existing_items) + assert self._raw_items is not None + return self._raw_items + +def resizable_list_supporting_raw_ptr(lst): + return _ResizableListSupportingRawPtr(lst) + +def nonmoving_raw_ptr_for_resizable_list(lst): + assert isinstance(lst, _ResizableListSupportingRawPtr) + return lst._nonmoving_raw_ptr_for_resizable_list() + + +def _check_resizable_list_of_chars(s_list): + from rpython.annotator import model as annmodel + from rpython.rlib import debug + if annmodel.s_None.contains(s_list): + return # "None", will likely be generalized later + if not isinstance(s_list, annmodel.SomeList): + raise Exception("not a list, got %r" % (s_list,)) + if not isinstance(s_list.listdef.listitem.s_value, + (annmodel.SomeChar, annmodel.SomeImpossibleValue)): + raise debug.NotAListOfChars + s_list.listdef.resize() # must be resizable + +class Entry(ExtRegistryEntry): + _about_ = resizable_list_supporting_raw_ptr + + def compute_result_annotation(self, s_list): + _check_resizable_list_of_chars(s_list) + return s_list + + def specialize_call(self, hop): + hop.exception_cannot_occur() + return hop.inputarg(hop.args_r[0], 0) + +class Entry(ExtRegistryEntry): + _about_ = nonmoving_raw_ptr_for_resizable_list + + def compute_result_annotation(self, s_list): + from rpython.rtyper.lltypesystem import lltype, rffi + from rpython.rtyper.llannotation import SomePtr + _check_resizable_list_of_chars(s_list) + return SomePtr(rffi.CCHARP) + + def specialize_call(self, hop): + v_list = hop.inputarg(hop.args_r[0], 0) + hop.exception_cannot_occur() # ignoring MemoryError + return hop.gendirectcall(ll_nonmovable_raw_ptr_for_resizable_list, + v_list) + +def ll_nonmovable_raw_ptr_for_resizable_list(ll_list): + from rpython.rtyper.lltypesystem import lltype, rffi + array = ll_list.items + if can_move(array): + length = ll_list.length + new_array = lltype.malloc(lltype.typeOf(ll_list).TO.items.TO, length, + nonmovable=True) + i = 0 + while i < length: + new_array[i] = array[i] + i += 1 + ll_list.items = new_array + array = new_array + ptr = lltype.direct_arrayitems(array) + # ptr is a Ptr(FixedSizeArray(Char, 1)). Cast it to a rffi.CCHARP + return rffi.cast(rffi.CCHARP, ptr) diff --git a/rpython/rlib/test/test_rgc.py b/rpython/rlib/test/test_rgc.py --- a/rpython/rlib/test/test_rgc.py +++ b/rpython/rlib/test/test_rgc.py @@ -1,6 +1,6 @@ from rpython.rtyper.test.test_llinterp import gengraph, interpret from rpython.rtyper.error import TyperError -from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rlib import rgc # Force registration of gc.collect import gc import py, sys @@ -254,6 +254,153 @@ assert typer.custom_trace_funcs == [(TP, trace_func)] +def test_nonmoving_raw_ptr_for_resizable_list(): + def f(n): + lst = ['a', 'b', 'c'] + lst = rgc.resizable_list_supporting_raw_ptr(lst) + lst.append(chr(n)) + assert lst[3] == chr(n) + assert lst[-1] == chr(n) + # + ptr = rgc.nonmoving_raw_ptr_for_resizable_list(lst) + assert lst[:] == ['a', 'b', 'c', chr(n)] + assert lltype.typeOf(ptr) == rffi.CCHARP + assert [ptr[i] for i in range(4)] == ['a', 'b', 'c', chr(n)] + # + lst[-3] = 'X' + assert ptr[1] == 'X' + ptr[2] = 'Y' + assert lst[-2] == 'Y' + # + addr = rffi.cast(lltype.Signed, ptr) + ptr = rffi.cast(rffi.CCHARP, addr) + rgc.collect() # should not move lst.items + lst[-4] = 'g' + assert ptr[0] == 'g' + ptr[3] = 'H' + assert lst[-1] == 'H' + return lst + # + # direct untranslated run + lst = f(35) + assert isinstance(lst, rgc._ResizableListSupportingRawPtr) + # + # llinterp run + interpret(f, [35]) + # + # compilation with the GC transformer + import subprocess + from rpython.translator.interactive import Translation + # + def main(argv): + f(len(argv)) + print "OK!" + return 0 + # + t = Translation(main, gc="incminimark") + t.disable(['backendopt']) + t.set_backend_extra_options(c_debug_defines=True) + exename = t.compile() + data = subprocess.check_output([str(exename), '.', '.', '.']) + assert data.strip().endswith('OK!') + +def test_ListSupportingRawPtr_direct(): + lst = ['a', 'b', 'c'] + lst = rgc.resizable_list_supporting_raw_ptr(lst) + + def check_nonresizing(): + assert lst[1] == lst[-2] == 'b' + lst[1] = 'X' + assert lst[1] == 'X' + lst[-1] = 'Y' + assert lst[1:3] == ['X', 'Y'] + assert lst[-2:9] == ['X', 'Y'] + lst[1:2] = 'B' + assert lst[:] == ['a', 'B', 'Y'] + assert list(iter(lst)) == ['a', 'B', 'Y'] + assert list(reversed(lst)) == ['Y', 'B', 'a'] + assert 'B' in lst + assert 'b' not in lst + assert p[0] == 'a' + assert p[1] == 'B' + assert p[2] == 'Y' + assert lst + ['*'] == ['a', 'B', 'Y', '*'] + assert ['*'] + lst == ['*', 'a', 'B', 'Y'] + assert lst + lst == ['a', 'B', 'Y', 'a', 'B', 'Y'] + base = ['8'] + base += lst + assert base == ['8', 'a', 'B', 'Y'] + assert lst == ['a', 'B', 'Y'] + assert ['a', 'B', 'Y'] == lst + assert ['a', 'B', 'Z'] != lst + assert ['a', 'B', 'Z'] > lst + assert ['a', 'B', 'Z'] >= lst + assert lst * 2 == ['a', 'B', 'Y', 'a', 'B', 'Y'] + assert 2 * lst == ['a', 'B', 'Y', 'a', 'B', 'Y'] + assert lst.count('B') == 1 + assert lst.index('Y') == 2 + lst.reverse() + assert lst == ['Y', 'B', 'a'] + lst.sort() + assert lst == ['B', 'Y', 'a'] + lst.sort(reverse=True) + assert lst == ['a', 'Y', 'B'] + lst[1] = 'b' + lst[2] = 'c' + assert list(lst) == ['a', 'b', 'c'] + + p = lst + check_nonresizing() + assert lst._raw_items is None + lst._nonmoving_raw_ptr_for_resizable_list() + p = lst._raw_items + check_nonresizing() + assert lst._raw_items == p + assert p[0] == 'a' + assert p[1] == 'b' + assert p[2] == 'c' + + def do_resizing_operation(): + del lst[1] + yield ['a', 'c'] + + lst[:2] = ['X'] + yield ['X', 'c'] + + del lst[:2] + yield ['c'] + + x = lst + x += ['t'] + yield ['a', 'b', 'c', 't'] + + x = lst + x *= 3 + yield ['a', 'b', 'c'] * 3 + + lst.append('f') + yield ['a', 'b', 'c', 'f'] + + lst.extend('fg') + yield ['a', 'b', 'c', 'f', 'g'] + + lst.insert(1, 'k') + yield ['a', 'k', 'b', 'c'] + + n = lst.pop(1) + assert n == 'b' + yield ['a', 'c'] + + lst.remove('c') + yield ['a', 'b'] + + assert lst == ['a', 'b', 'c'] + for expect in do_resizing_operation(): + assert lst == expect + assert lst._raw_items is None + lst = ['a', 'b', 'c'] + lst = rgc.resizable_list_supporting_raw_ptr(lst) + lst._nonmoving_raw_ptr_for_resizable_list() # ____________________________________________________________ @@ -368,7 +515,6 @@ assert fq._triggered == 1 def test_finalizer_trigger_calls_too_much(self): - from rpython.rtyper.lltypesystem import lltype, rffi external_func = rffi.llexternal("foo", [], lltype.Void) # ^^^ with release_gil=True class X(object): diff --git a/rpython/rtyper/lltypesystem/lltype.py b/rpython/rtyper/lltypesystem/lltype.py --- a/rpython/rtyper/lltypesystem/lltype.py +++ b/rpython/rtyper/lltypesystem/lltype.py @@ -2174,7 +2174,8 @@ def malloc(T, n=None, flavor='gc', immortal=False, zero=False, - track_allocation=True, add_memory_pressure=False): + track_allocation=True, add_memory_pressure=False, + nonmovable=False): assert flavor in ('gc', 'raw') if zero or immortal: initialization = 'example' @@ -2200,7 +2201,8 @@ @analyzer_for(malloc) def ann_malloc(s_T, s_n=None, s_flavor=None, s_zero=None, - s_track_allocation=None, s_add_memory_pressure=None): + s_track_allocation=None, s_add_memory_pressure=None, + s_nonmovable=None): assert (s_n is None or s_n.knowntype == int or issubclass(s_n.knowntype, base_int)) assert s_T.is_constant() @@ -2218,6 +2220,7 @@ assert s_track_allocation is None or s_track_allocation.is_constant() assert (s_add_memory_pressure is None or s_add_memory_pressure.is_constant()) + assert s_nonmovable is None or s_nonmovable.is_constant() # not sure how to call malloc() for the example 'p' in the # presence of s_extraargs r = SomePtr(Ptr(s_T.const)) diff --git a/rpython/rtyper/lltypesystem/test/test_lltype.py b/rpython/rtyper/lltypesystem/test/test_lltype.py --- a/rpython/rtyper/lltypesystem/test/test_lltype.py +++ b/rpython/rtyper/lltypesystem/test/test_lltype.py @@ -659,6 +659,7 @@ a[3] = 30 a[4] = 40 b0 = direct_arrayitems(a) + assert typeOf(b0) == Ptr(FixedSizeArray(Signed, 1)) b1 = direct_ptradd(b0, 1) b2 = direct_ptradd(b1, 1) b3 = direct_ptradd(b0, 3) diff --git a/rpython/rtyper/rbuiltin.py b/rpython/rtyper/rbuiltin.py --- a/rpython/rtyper/rbuiltin.py +++ b/rpython/rtyper/rbuiltin.py @@ -348,7 +348,7 @@ @typer_for(lltype.malloc) def rtype_malloc(hop, i_flavor=None, i_zero=None, i_track_allocation=None, - i_add_memory_pressure=None): + i_add_memory_pressure=None, i_nonmovable=None): assert hop.args_s[0].is_constant() vlist = [hop.inputarg(lltype.Void, arg=0)] opname = 'malloc' @@ -357,8 +357,10 @@ (i_flavor, lltype.Void), (i_zero, None), (i_track_allocation, None), - (i_add_memory_pressure, None)) - (v_flavor, v_zero, v_track_allocation, v_add_memory_pressure) = kwds_v + (i_add_memory_pressure, None), + (i_nonmovable, None)) + (v_flavor, v_zero, v_track_allocation, + v_add_memory_pressure, v_nonmovable) = kwds_v flags = {'flavor': 'gc'} if v_flavor is not None: flags['flavor'] = v_flavor.value @@ -368,6 +370,8 @@ flags['track_allocation'] = v_track_allocation.value if i_add_memory_pressure is not None: flags['add_memory_pressure'] = v_add_memory_pressure.value + if i_nonmovable is not None: + flags['nonmovable'] = v_nonmovable vlist.append(hop.inputconst(lltype.Void, flags)) assert 1 <= hop.nb_args <= 2 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit