Author: mattip <matti.pi...@gmail.com> Branch: ufuncapi Changeset: r73995:f5247fd471a9 Date: 2014-10-16 08:59 -0500 http://bitbucket.org/pypy/pypy/changeset/f5247fd471a9/
Log: merge default into branch diff too long, truncating to 2000 out of 6186 lines diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -3,8 +3,8 @@ Except when otherwise stated (look for LICENSE files in directories or information at the beginning of each file) all software and documentation in -the 'rpython', 'pypy', 'ctype_configure', 'dotviewer', 'demo', and 'lib_pypy' -directories is licensed as follows: +the 'rpython', 'pypy', 'ctype_configure', 'dotviewer', 'demo', 'lib_pypy', +'py', and '_pytest' directories is licensed as follows: The MIT License diff --git a/pypy/doc/release-pypy3-2.4.0.rst b/pypy/doc/release-pypy3-2.4.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-pypy3-2.4.0.rst @@ -0,0 +1,126 @@ +================================================= +PyPy3 2.4 - Snow White +================================================= + +We're pleased to announce PyPy3 2.4, which contains significant performance +enhancements and bug fixes. + +You can download the PyPy3 2.4.0 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project, and for those who donate to our three sub-projects. +We've shown quite a bit of progress, but we're slowly running out of funds. +Please consider donating more, or even better convince your employer to donate, +so we can finish those projects! The three sub-projects are: + +* `Py3k`_ (supporting Python 3.x): This is a Python 3.2.5 compatible + version we call PyPy3 2.4, and we are working toward a Python 3.3 + compatible version + +* `STM`_ (software transactional memory): We have released a first working version, + and continue to try out new promising paths of achieving a fast multithreaded Python + +* `NumPy`_ which requires installation of our fork of upstream numpy, + available `on bitbucket`_ + +.. _`Py3k`: http://pypy.org/py3donate.html +.. _`STM`: http://pypy.org/tmdonate2.html +.. _`NumPy`: http://pypy.org/numpydonate.html +.. _`on bitbucket`: https://www.bitbucket.org/pypy/numpy + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7 or 3.2.5. It's fast (`pypy 2.4 and cpython 2.7.x`_ performance +comparison) due to its integrated tracing JIT compiler. + +This release supports **x86** machines on most common operating systems +(Linux 32/64, Mac OS X 64, Windows, and OpenBSD), +as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux. + +While we support 32 bit python on Windows, work on the native Windows 64 +bit python is still stalling, we would welcome a volunteer +to `handle that`_. + +.. _`pypy 2.4 and cpython 2.7.x`: http://speed.pypy.org +.. _`handle that`: http://doc.pypy.org/en/latest/windows.html#what-is-missing-for-a-full-64-bit-translation + +PyPy3 Highlights +================ + +Issues reported with our previous release were fixed after reports from users on +our new issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at +#pypy. Here is a summary of the user-facing PyPy3 specific changes: + +* Better Windows compatibility, e.g. the nt module functions _getfinalpathname + & _getfileinformation are now supported (the former is required for the + popular pathlib library for example) + +* Various fsencode PEP 383 related fixes to the posix module (readlink, uname, + ttyname and ctermid) and improved locale handling + +* Switched default binary name os POSIX distributions to 'pypy3' (which + symlinks to to 'pypy3.2') + +* Fixed a couple different crashes related to parsing Python 3 source code + +Further Highlights (shared w/ PyPy2) +==================================== + +Benchmarks improved after internal enhancements in string and +bytearray handling, and a major rewrite of the GIL handling. This means +that external calls are now a lot faster, especially the CFFI ones. It also +means better performance in a lot of corner cases with handling strings or +bytearrays. The main bugfix is handling of many socket objects in your +program which in the long run used to "leak" memory. + +We fixed a memory leak in IO in the sandbox_ code + +We welcomed more than 12 new contributors, and conducted two Google +Summer of Code projects, as well as other student projects not +directly related to Summer of Code. + +* Reduced internal copying of bytearray operations + +* Tweak the internal structure of StringBuilder to speed up large string + handling, which becomes advantageous on large programs at the cost of slightly + slower small *benchmark* type programs. + +* Boost performance of thread-local variables in both unjitted and jitted code, + this mostly affects errno handling on linux, which makes external calls + faster. + +* Move to a mixed polling and mutex GIL model that make mutlithreaded jitted + code run *much* faster + +* Optimize errno handling in linux (x86 and x86-64 only) + +* Remove ctypes pythonapi and ctypes.PyDLL, which never worked on PyPy + +* Classes in the ast module are now distinct from structures used by + the compiler, which simplifies and speeds up translation of our + source code to the PyPy binary interpreter + +* Win32 now links statically to zlib, expat, bzip, and openssl-1.0.1i. + No more missing DLLs + +* Many issues were resolved_ since the 2.3.1 release in June + +.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.4.0.html +.. _resolved: https://bitbucket.org/pypy/pypy/issues?status=resolved +.. _sandbox: http://doc.pypy.org/en/latest/sandbox.html + +We have further improvements on the way: rpython file handling, +numpy linalg compatibility, as well +as improved GC and many smaller improvements. + +Please try it out and let us know what you think. We especially welcome +success stories, we know you are using PyPy, please tell us about it! + +Cheers + +The PyPy Team + 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 @@ -15,3 +15,10 @@ .. branch: rtyper-stuff Small internal refactorings in the rtyper. + +.. branch: var-in-Some +Store annotations on the Variable objects, rather than in a big dict. +Introduce a new framework for double-dispatched annotation implementations. + +.. branch: ClassRepr +Refactor ClassRepr and make normalizecalls independent of the rtyper. diff --git a/pypy/doc/whatsnew-pypy3-2.4.0.rst b/pypy/doc/whatsnew-pypy3-2.4.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/whatsnew-pypy3-2.4.0.rst @@ -0,0 +1,6 @@ +========================= +What's new in PyPy3 2.4.0 +========================= + +.. this is a revision shortly after pypy3-release-2.4.x +.. startrev: 12b940544622 diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -251,6 +251,7 @@ enable_translationmodules(config) config.translation.suggest(check_str_without_nul=True) + config.translation.suggest(shared=True) if config.translation.thread: config.objspace.usemodules.thread = True diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py --- a/pypy/interpreter/astcompiler/ast.py +++ b/pypy/interpreter/astcompiler/ast.py @@ -22,9 +22,11 @@ def get_field(space, w_node, name, optional): w_obj = w_node.getdictvalue(space, name) - if w_obj is None and not optional: - raise oefmt(space.w_TypeError, + if w_obj is None: + if not optional: + raise oefmt(space.w_TypeError, "required field \"%s\" missing from %T", name, w_node) + w_obj = space.w_None return w_obj diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py --- a/pypy/interpreter/astcompiler/tools/asdl_py.py +++ b/pypy/interpreter/astcompiler/tools/asdl_py.py @@ -405,9 +405,11 @@ def get_field(space, w_node, name, optional): w_obj = w_node.getdictvalue(space, name) - if w_obj is None and not optional: - raise oefmt(space.w_TypeError, + if w_obj is None: + if not optional: + raise oefmt(space.w_TypeError, "required field \"%s\" missing from %T", name, w_node) + w_obj = space.w_None return w_obj diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py --- a/pypy/module/_ast/test/test_ast.py +++ b/pypy/module/_ast/test/test_ast.py @@ -425,3 +425,8 @@ str_node2 = copy.deepcopy(str_node) dict_res = str_node2.__dict__ assert dict_res == {'n':2, 'lineno':2} + + def test_bug_null_in_objspace_type(self): + import ast + code = ast.Expression(lineno=1, col_offset=1, body=ast.ListComp(lineno=1, col_offset=1, elt=ast.Call(lineno=1, col_offset=1, func=ast.Name(lineno=1, col_offset=1, id='str', ctx=ast.Load(lineno=1, col_offset=1)), args=[ast.Name(lineno=1, col_offset=1, id='x', ctx=ast.Load(lineno=1, col_offset=1))], keywords=[]), generators=[ast.comprehension(lineno=1, col_offset=1, target=ast.Name(lineno=1, col_offset=1, id='x', ctx=ast.Store(lineno=1, col_offset=1)), iter=ast.List(lineno=1, col_offset=1, elts=[ast.Num(lineno=1, col_offset=1, n=23)], ctx=ast.Load(lineno=1, col_offset=1, )), ifs=[])])) + compile(code, '<template>', 'eval') diff --git a/pypy/module/micronumpy/test/test_arrayops.py b/pypy/module/micronumpy/test/test_arrayops.py --- a/pypy/module/micronumpy/test/test_arrayops.py +++ b/pypy/module/micronumpy/test/test_arrayops.py @@ -211,7 +211,7 @@ assert np.result_type(1.) is np.dtype('float64') assert np.result_type(1+2j) is np.dtype('complex128') assert np.result_type(1, 1.) is np.dtype('float64') - assert np.result_type(np.array([1, 2])) is np.dtype('int64') + assert np.result_type(np.array([1, 2])) is np.dtype('int') assert np.result_type(np.array([1, 2]), 1, 1+2j) is np.dtype('complex128') assert np.result_type(np.array([1, 2]), 1, 'float64') is np.dtype('float64') assert np.result_type(np.array([1, 2]), 1, None) is np.dtype('float64') diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -7,7 +7,7 @@ from pypy.interpreter.error import OperationError from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance, hlstr -from rpython.rtyper.lltypesystem.rclass import OBJECT +from rpython.rtyper.rclass import OBJECT from rpython.jit.metainterp.resoperation import rop from rpython.rlib.nonconst import NonConstant from rpython.rlib import jit_hooks diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -9,7 +9,7 @@ from rpython.rtyper.annlowlevel import (cast_instance_to_base_ptr, cast_base_ptr_to_instance) from rpython.rtyper.lltypesystem import lltype, llmemory -from rpython.rtyper.lltypesystem.rclass import OBJECT +from rpython.rtyper.rclass import OBJECT from pypy.module.pypyjit.interp_jit import pypyjitdriver from pypy.module.pypyjit.policy import pypy_hooks from rpython.jit.tool.oparser import parse 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 @@ -4,6 +4,7 @@ import_from_mixin, newlist_hint, resizelist_hint, specialize) from rpython.rlib.buffer import Buffer from rpython.rlib.rstring import StringBuilder, ByteListBuilder +from rpython.rlib.debug import check_list_of_chars from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt @@ -22,6 +23,7 @@ import_from_mixin(StringMethods) def __init__(self, data): + check_list_of_chars(data) self.data = data def __repr__(self): diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py --- a/rpython/annotator/annrpython.py +++ b/rpython/annotator/annrpython.py @@ -17,7 +17,6 @@ log = py.log.Producer("annrpython") py.log.setconsumer("annrpython", ansi_log) -FAIL = object() class RPythonAnnotator(object): """Block annotator for RPython. @@ -33,7 +32,6 @@ translator.annotator = self self.translator = translator self.pendingblocks = {} # map {block: graph-containing-it} - self.bindings = {} # map Variables to SomeValues self.annotated = {} # set of blocks already seen self.added_blocks = None # see processblock() below self.links_followed = {} # set of links that have ever been followed @@ -54,7 +52,7 @@ self.bookkeeper = bookkeeper def __getstate__(self): - attrs = """translator pendingblocks bindings annotated links_followed + attrs = """translator pendingblocks annotated links_followed notify bookkeeper frozen policy added_blocks""".split() ret = self.__dict__.copy() for key, value in ret.items(): @@ -143,7 +141,7 @@ # recursively proceed until no more pending block is left if complete_now: self.complete() - return self.binding(flowgraph.getreturnvar(), None) + return self.annotation(flowgraph.getreturnvar()) def gettype(self, variable): """Return the known type of a control flow graph variable, @@ -151,9 +149,9 @@ if isinstance(variable, Constant): return type(variable.value) elif isinstance(variable, Variable): - cell = self.bindings.get(variable) - if cell: - return cell.knowntype + s_variable = variable.annotation + if s_variable: + return s_variable.knowntype else: return object else: @@ -221,37 +219,39 @@ raise annmodel.AnnotatorError(text) for graph in newgraphs: v = graph.getreturnvar() - if v not in self.bindings: + if v.annotation is None: self.setbinding(v, annmodel.s_ImpossibleValue) # policy-dependent computation self.bookkeeper.compute_at_fixpoint() - def binding(self, arg, default=FAIL): + def annotation(self, arg): "Gives the SomeValue corresponding to the given Variable or Constant." if isinstance(arg, Variable): - try: - return self.bindings[arg] - except KeyError: - if default is not FAIL: - return default - else: - raise + return arg.annotation elif isinstance(arg, Constant): return self.bookkeeper.immutablevalue(arg.value) else: raise TypeError('Variable or Constant expected, got %r' % (arg,)) + def binding(self, arg): + "Gives the SomeValue corresponding to the given Variable or Constant." + s_arg = self.annotation(arg) + if s_arg is None: + raise KeyError + return s_arg + def typeannotation(self, t): return signature.annotation(t, self.bookkeeper) def setbinding(self, arg, s_value): - if arg in self.bindings: - assert s_value.contains(self.bindings[arg]) - self.bindings[arg] = s_value + s_old = arg.annotation + if s_old is not None: + assert s_value.contains(s_old) + arg.annotation = s_value def transfer_binding(self, v_target, v_source): - assert v_source in self.bindings - self.bindings[v_target] = self.bindings[v_source] + assert v_source.annotation is not None + v_target.annotation = v_source.annotation def warning(self, msg, pos=None): if pos is None: @@ -290,7 +290,7 @@ # get the (current) return value v = graph.getreturnvar() try: - return self.bindings[v] + return self.binding(v) except KeyError: # the function didn't reach any return statement so far. # (some functions actually never do, they always raise exceptions) @@ -328,7 +328,7 @@ # * block not in self.annotated: # never seen the block. # * self.annotated[block] == False: - # the input variables of the block are in self.bindings but we + # the input variables of the block have bindings but we # still have to consider all the operations in the block. # * self.annotated[block] == graph-containing-block: # analysis done (at least until we find we must generalize the @@ -443,7 +443,7 @@ # is known exits = block.exits if isinstance(block.exitswitch, Variable): - s_exitswitch = self.bindings[block.exitswitch] + s_exitswitch = self.binding(block.exitswitch) if s_exitswitch.is_constant(): exits = [link for link in exits if link.exitcase == s_exitswitch.const] @@ -452,20 +452,7 @@ # occour for this specific, typed operation. if block.exitswitch == c_last_exception: op = block.operations[-1] - if op.dispatch == 2: - arg1 = self.binding(op.args[0]) - arg2 = self.binding(op.args[1]) - binop = getattr(pair(arg1, arg2), op.opname, None) - can_only_throw = annmodel.read_can_only_throw(binop, arg1, arg2) - elif op.dispatch == 1: - arg1 = self.binding(op.args[0]) - opname = op.opname - if opname == 'contains': opname = 'op_contains' - unop = getattr(arg1, opname, None) - can_only_throw = annmodel.read_can_only_throw(unop, arg1) - else: - can_only_throw = None - + can_only_throw = op.get_can_only_throw(self) if can_only_throw is not None: candidates = can_only_throw candidate_exits = exits @@ -482,8 +469,10 @@ # mapping (exitcase, variable) -> s_annotation # that can be attached to booleans, exitswitches - knowntypedata = getattr(self.bindings.get(block.exitswitch), - "knowntypedata", {}) + knowntypedata = {} + if isinstance(block.exitswitch, Variable): + knowntypedata = getattr(self.binding(block.exitswitch), + "knowntypedata", {}) for link in exits: self.follow_link(graph, link, knowntypedata) if block in self.notify: @@ -578,22 +567,19 @@ self.links_followed[link] = True self.addpendingblock(graph, link.target, cells) - #___ creating the annotations based on operations ______ def consider_op(self, op): - argcells = [self.binding(a) for a in op.args] - # let's be careful about avoiding propagated SomeImpossibleValues # to enter an op; the latter can result in violations of the # more general results invariant: e.g. if SomeImpossibleValue enters is_ # is_(SomeImpossibleValue, None) -> SomeBool # is_(SomeInstance(not None), None) -> SomeBool(const=False) ... # boom -- in the assert of setbinding() - for arg in argcells: - if isinstance(arg, annmodel.SomeImpossibleValue): + for arg in op.args: + if isinstance(self.annotation(arg), annmodel.SomeImpossibleValue): raise BlockedInference(self, op, -1) - resultcell = op.consider(self, *argcells) + resultcell = op.consider(self, *op.args) if resultcell is None: resultcell = annmodel.s_ImpossibleValue elif resultcell == annmodel.s_ImpossibleValue: diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -13,7 +13,7 @@ SomeLongFloat, SomeType, SomeConstantType, unionof, UnionError, read_can_only_throw, add_knowntypedata, merge_knowntypedata,) -from rpython.annotator.bookkeeper import getbookkeeper, immutablevalue +from rpython.annotator.bookkeeper import immutablevalue from rpython.flowspace.model import Variable, Constant from rpython.flowspace.operation import op from rpython.rlib import rarithmetic @@ -23,6 +23,54 @@ if oper.dispatch == 2]) +@op.is_.register(SomeObject, SomeObject) +def is__default(annotator, obj1, obj2): + r = SomeBool() + s_obj1 = annotator.annotation(obj1) + s_obj2 = annotator.annotation(obj2) + if s_obj2.is_constant(): + if s_obj1.is_constant(): + r.const = s_obj1.const is s_obj2.const + if s_obj2.const is None and not s_obj1.can_be_none(): + r.const = False + elif s_obj1.is_constant(): + if s_obj1.const is None and not s_obj2.can_be_none(): + r.const = False + knowntypedata = {} + bk = annotator.bookkeeper + + def bind(src_obj, tgt_obj): + s_src = annotator.annotation(src_obj) + s_tgt = annotator.annotation(tgt_obj) + if hasattr(s_tgt, 'is_type_of') and s_src.is_constant(): + add_knowntypedata( + knowntypedata, True, + s_tgt.is_type_of, + bk.valueoftype(s_src.const)) + add_knowntypedata(knowntypedata, True, [tgt_obj], s_src) + s_nonnone = s_tgt + if (s_src.is_constant() and s_src.const is None and + s_tgt.can_be_none()): + s_nonnone = s_tgt.nonnoneify() + add_knowntypedata(knowntypedata, False, [tgt_obj], s_nonnone) + + bind(obj2, obj1) + bind(obj1, obj2) + r.set_knowntypedata(knowntypedata) + return r + +def _make_cmp_annotator_default(cmp_op): + @cmp_op.register(SomeObject, SomeObject) + def default_annotate(annotator, obj1, obj2): + s_1, s_2 = annotator.annotation(obj1), annotator.annotation(obj2) + if s_1.is_immutable_constant() and s_2.is_immutable_constant(): + return immutablevalue(cmp_op.pyfunc(s_1.const, s_2.const)) + else: + return s_Bool + +for cmp_op in [op.lt, op.le, op.eq, op.ne, op.gt, op.ge]: + _make_cmp_annotator_default(cmp_op) + class __extend__(pairtype(SomeObject, SomeObject)): def union((obj1, obj2)): @@ -51,87 +99,12 @@ inplace_floordiv.can_only_throw = [ZeroDivisionError] inplace_mod.can_only_throw = [ZeroDivisionError] - def lt((obj1, obj2)): - if obj1.is_immutable_constant() and obj2.is_immutable_constant(): - return immutablevalue(obj1.const < obj2.const) - else: - return s_Bool - - def le((obj1, obj2)): - if obj1.is_immutable_constant() and obj2.is_immutable_constant(): - return immutablevalue(obj1.const <= obj2.const) - else: - return s_Bool - - def eq((obj1, obj2)): - if obj1.is_immutable_constant() and obj2.is_immutable_constant(): - return immutablevalue(obj1.const == obj2.const) - else: - return s_Bool - - def ne((obj1, obj2)): - if obj1.is_immutable_constant() and obj2.is_immutable_constant(): - return immutablevalue(obj1.const != obj2.const) - else: - return s_Bool - - def gt((obj1, obj2)): - if obj1.is_immutable_constant() and obj2.is_immutable_constant(): - return immutablevalue(obj1.const > obj2.const) - else: - return s_Bool - - def ge((obj1, obj2)): - if obj1.is_immutable_constant() and obj2.is_immutable_constant(): - return immutablevalue(obj1.const >= obj2.const) - else: - return s_Bool - def cmp((obj1, obj2)): if obj1.is_immutable_constant() and obj2.is_immutable_constant(): return immutablevalue(cmp(obj1.const, obj2.const)) else: return SomeInteger() - def is_((obj1, obj2)): - r = SomeBool() - if obj2.is_constant(): - if obj1.is_constant(): - r.const = obj1.const is obj2.const - if obj2.const is None and not obj1.can_be_none(): - r.const = False - elif obj1.is_constant(): - if obj1.const is None and not obj2.can_be_none(): - r.const = False - # XXX HACK HACK HACK - # XXX HACK HACK HACK - # XXX HACK HACK HACK - bk = getbookkeeper() - if bk is not None: # for testing - op = bk._find_current_op("is_", 2) - knowntypedata = {} - annotator = bk.annotator - - def bind(src_obj, tgt_obj, tgt_arg): - if hasattr(tgt_obj, 'is_type_of') and src_obj.is_constant(): - add_knowntypedata(knowntypedata, True, tgt_obj.is_type_of, - bk.valueoftype(src_obj.const)) - - assert annotator.binding(op.args[tgt_arg]) == tgt_obj - add_knowntypedata(knowntypedata, True, [op.args[tgt_arg]], src_obj) - - nonnone_obj = tgt_obj - if src_obj.is_constant() and src_obj.const is None and tgt_obj.can_be_none(): - nonnone_obj = tgt_obj.nonnoneify() - - add_knowntypedata(knowntypedata, False, [op.args[tgt_arg]], nonnone_obj) - - bind(obj2, obj1, 0) - bind(obj1, obj2, 1) - r.set_knowntypedata(knowntypedata) - - return r - def divmod((obj1, obj2)): return SomeTuple([pair(obj1, obj2).div(), pair(obj1, obj2).mod()]) @@ -271,10 +244,14 @@ return SomeInteger(nonneg=int1.nonneg, knowntype=int1.knowntype) rshift.can_only_throw = [] - def _compare_helper((int1, int2), opname, operation): + +def _make_cmp_annotator_int(cmp_op): + @cmp_op.register(SomeInteger, SomeInteger) + def _compare_helper(annotator, int1, int2): r = SomeBool() - if int1.is_immutable_constant() and int2.is_immutable_constant(): - r.const = operation(int1.const, int2.const) + s_int1, s_int2 = annotator.annotation(int1), annotator.annotation(int2) + if s_int1.is_immutable_constant() and s_int2.is_immutable_constant(): + r.const = cmp_op.pyfunc(s_int1.const, s_int2.const) # # The rest of the code propagates nonneg information between # the two arguments. @@ -286,45 +263,38 @@ # nonneg then "assert x>=y" will let the annotator know that # x is nonneg too, but it will not work if y is unsigned. # - if not (rarithmetic.signedtype(int1.knowntype) and - rarithmetic.signedtype(int2.knowntype)): + if not (rarithmetic.signedtype(s_int1.knowntype) and + rarithmetic.signedtype(s_int2.knowntype)): return r knowntypedata = {} - op = getbookkeeper()._find_current_op(opname=opname, arity=2) - def tointtype(int0): - if int0.knowntype is bool: + def tointtype(s_int0): + if s_int0.knowntype is bool: return int - return int0.knowntype - if int1.nonneg and isinstance(op.args[1], Variable): - case = opname in ('lt', 'le', 'eq') - - add_knowntypedata(knowntypedata, case, [op.args[1]], - SomeInteger(nonneg=True, knowntype=tointtype(int2))) - if int2.nonneg and isinstance(op.args[0], Variable): - case = opname in ('gt', 'ge', 'eq') - add_knowntypedata(knowntypedata, case, [op.args[0]], - SomeInteger(nonneg=True, knowntype=tointtype(int1))) + return s_int0.knowntype + if s_int1.nonneg and isinstance(int2, Variable): + case = cmp_op.opname in ('lt', 'le', 'eq') + add_knowntypedata(knowntypedata, case, [int2], + SomeInteger(nonneg=True, knowntype=tointtype(s_int2))) + if s_int2.nonneg and isinstance(int1, Variable): + case = cmp_op.opname in ('gt', 'ge', 'eq') + add_knowntypedata(knowntypedata, case, [int1], + SomeInteger(nonneg=True, knowntype=tointtype(s_int1))) r.set_knowntypedata(knowntypedata) # a special case for 'x < 0' or 'x >= 0', # where 0 is a flow graph Constant # (in this case we are sure that it cannot become a r_uint later) - if (isinstance(op.args[1], Constant) and - type(op.args[1].value) is int and # filter out Symbolics - op.args[1].value == 0): - if int1.nonneg: - if opname == 'lt': + if (isinstance(int2, Constant) and + type(int2.value) is int and # filter out Symbolics + int2.value == 0): + if s_int1.nonneg: + if cmp_op.opname == 'lt': r.const = False - if opname == 'ge': + if cmp_op.opname == 'ge': r.const = True return r - def lt(intint): return intint._compare_helper('lt', operator.lt) - def le(intint): return intint._compare_helper('le', operator.le) - def eq(intint): return intint._compare_helper('eq', operator.eq) - def ne(intint): return intint._compare_helper('ne', operator.ne) - def gt(intint): return intint._compare_helper('gt', operator.gt) - def ge(intint): return intint._compare_helper('ge', operator.ge) - +for cmp_op in [op.lt, op.le, op.eq, op.ne, op.gt, op.ge]: + _make_cmp_annotator_int(cmp_op) class __extend__(pairtype(SomeBool, SomeBool)): @@ -746,25 +716,26 @@ return SomeBuiltinMethod(bltn1.analyser, s_self, methodname=bltn1.methodname) +@op.is_.register(SomePBC, SomePBC) +def is__PBC_PBC(annotator, pbc1, pbc2): + s = is__default(annotator, pbc1, pbc2) + if not s.is_constant(): + s_pbc1 = annotator.annotation(pbc1) + s_pbc2 = annotator.annotation(pbc2) + if not s_pbc1.can_be_None or not s_pbc2.can_be_None: + for desc in s_pbc1.descriptions: + if desc in s_pbc2.descriptions: + break + else: + s.const = False # no common desc in the two sets + return s + class __extend__(pairtype(SomePBC, SomePBC)): - def union((pbc1, pbc2)): d = pbc1.descriptions.copy() d.update(pbc2.descriptions) return SomePBC(d, can_be_None = pbc1.can_be_None or pbc2.can_be_None) - def is_((pbc1, pbc2)): - thistype = pairtype(SomePBC, SomePBC) - s = super(thistype, pair(pbc1, pbc2)).is_() - if not s.is_constant(): - if not pbc1.can_be_None or not pbc2.can_be_None: - for desc in pbc1.descriptions: - if desc in pbc2.descriptions: - break - else: - s.const = False # no common desc in the two sets - return s - class __extend__(pairtype(SomeImpossibleValue, SomeObject)): def union((imp1, obj2)): return obj2 diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py --- a/rpython/annotator/bookkeeper.py +++ b/rpython/annotator/bookkeeper.py @@ -29,7 +29,7 @@ def analyzer_for(func): def wrapped(ann_func): BUILTIN_ANALYZERS[func] = ann_func - return func + return ann_func return wrapped class Bookkeeper(object): @@ -89,14 +89,14 @@ newblocks = self.annotator.added_blocks if newblocks is None: newblocks = self.annotator.annotated # all of them - binding = self.annotator.binding + annotation = self.annotator.annotation for block in newblocks: for op in block.operations: if op.opname in ('simple_call', 'call_args'): yield op # some blocks are partially annotated - if binding(op.result, None) is None: + if annotation(op.result) is None: break # ignore the unannotated part for call_op in call_sites(): @@ -144,15 +144,17 @@ def consider_call_site(self, call_op): from rpython.rtyper.llannotation import SomeLLADTMeth, lltype_to_annotation - binding = self.annotator.binding - s_callable = binding(call_op.args[0]) - args_s = [binding(arg) for arg in call_op.args[1:]] + annotation = self.annotator.annotation + s_callable = annotation(call_op.args[0]) + args_s = [annotation(arg) for arg in call_op.args[1:]] if isinstance(s_callable, SomeLLADTMeth): adtmeth = s_callable s_callable = self.immutablevalue(adtmeth.func) args_s = [lltype_to_annotation(adtmeth.ll_ptrtype)] + args_s if isinstance(s_callable, SomePBC): - s_result = binding(call_op.result, s_ImpossibleValue) + s_result = annotation(call_op.result) + if s_result is None: + s_result = s_ImpossibleValue args = call_op.build_args(args_s) self.consider_call_site_for_pbc(s_callable, args, s_result, call_op) @@ -500,8 +502,9 @@ # needed by some kinds of specialization. fn, block, i = self.position_key op = block.operations[i] - s_previous_result = self.annotator.binding(op.result, - s_ImpossibleValue) + s_previous_result = self.annotator.annotation(op.result) + if s_previous_result is None: + s_previous_result = s_ImpossibleValue else: if emulated is True: whence = None diff --git a/rpython/annotator/classdef.py b/rpython/annotator/classdef.py --- a/rpython/annotator/classdef.py +++ b/rpython/annotator/classdef.py @@ -154,6 +154,8 @@ self.subdefs = [] self.attr_sources = {} # {name: list-of-sources} self.read_locations_of__class__ = {} + self.repr = None + self.extra_access_sets = {} if classdesc.basedesc: self.basedef = classdesc.basedesc.getuniqueclassdef() diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -857,7 +857,11 @@ s = a.build_types(snippet.harmonic, [int]) assert s.knowntype == float # check that the list produced by range() is not mutated or resized - for s_value in a.bindings.values(): + graph = graphof(a, snippet.harmonic) + all_vars = set().union(*[block.getvariables() for block in graph.iterblocks()]) + print all_vars + for var in all_vars: + s_value = var.annotation if isinstance(s_value, annmodel.SomeList): assert not s_value.listdef.listitem.resized assert not s_value.listdef.listitem.mutated @@ -2767,8 +2771,8 @@ a = self.RPythonAnnotator() a.build_types(f, []) v1, v2 = graphof(a, readout).getargs() - assert not a.bindings[v1].is_constant() - assert not a.bindings[v2].is_constant() + assert not a.binding(v1).is_constant() + assert not a.binding(v2).is_constant() def test_prebuilt_mutables_dont_use_eq(self): # test that __eq__ is not called during annotation, at least diff --git a/rpython/annotator/test/test_model.py b/rpython/annotator/test/test_model.py --- a/rpython/annotator/test/test_model.py +++ b/rpython/annotator/test/test_model.py @@ -20,25 +20,6 @@ class C(object): pass -class DummyClassDef: - def __init__(self, cls=C): - self.cls = cls - self.name = cls.__name__ - -si0 = SomeInstance(DummyClassDef(), True) -si1 = SomeInstance(DummyClassDef()) -sTrue = SomeBool() -sTrue.const = True -sFalse = SomeBool() -sFalse.const = False - -def test_is_None(): - assert pair(s_None, s_None).is_() == sTrue - assert pair(si1, s_None).is_() == sFalse - assert pair(si0, s_None).is_() != sTrue - assert pair(si0, s_None).is_() != sFalse - assert pair(si0, s_None).is_() == SomeBool() - def test_equality(): assert s1 != s2 != s3 != s4 != s5 != s6 assert s1 == SomeType() diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -19,19 +19,41 @@ UNARY_OPERATIONS = set([oper.opname for oper in op.__dict__.values() if oper.dispatch == 1]) +UNARY_OPERATIONS.remove('contains') +@op.type.register(SomeObject) +def type_SomeObject(annotator, arg): + r = SomeType() + r.is_type_of = [arg] + return r + +@op.bool.register(SomeObject) +def bool_SomeObject(annotator, obj): + r = SomeBool() + annotator.annotation(obj).bool_behavior(r) + s_nonnone_obj = annotator.annotation(obj) + if s_nonnone_obj.can_be_none(): + s_nonnone_obj = s_nonnone_obj.nonnoneify() + knowntypedata = {} + add_knowntypedata(knowntypedata, True, [obj], s_nonnone_obj) + r.set_knowntypedata(knowntypedata) + return r + +@op.contains.register(SomeObject) +def contains_SomeObject(annotator, obj, element): + return s_Bool +contains_SomeObject.can_only_throw = [] + +@op.simple_call.register(SomeObject) +def simple_call_SomeObject(annotator, func, *args): + return annotator.annotation(func).call(simple_args([annotator.annotation(arg) for arg in args])) + +@op.call_args.register(SomeObject) +def call_args(annotator, func, *args): + return annotator.annotation(func).call(complex_args([annotator.annotation(arg) for arg in args])) class __extend__(SomeObject): - def type(self, *moreargs): - if moreargs: - raise Exception('type() called with more than one argument') - r = SomeType() - bk = getbookkeeper() - op = bk._find_current_op(opname="type", arity=1, pos=0, s_type=self) - r.is_type_of = [op.args[0]] - return r - def issubtype(self, s_cls): if hasattr(self, 'is_type_of'): vars = self.is_type_of @@ -53,21 +75,6 @@ if s_len.is_immutable_constant(): s.const = s_len.const > 0 - def bool(s_obj): - r = SomeBool() - s_obj.bool_behavior(r) - - bk = getbookkeeper() - knowntypedata = {} - op = bk._find_current_op(opname="bool", arity=1) - arg = op.args[0] - s_nonnone_obj = s_obj - if s_obj.can_be_none(): - s_nonnone_obj = s_obj.nonnoneify() - add_knowntypedata(knowntypedata, True, [arg], s_nonnone_obj) - r.set_knowntypedata(knowntypedata) - return r - def hash(self): raise AnnotatorError("cannot use hash() in RPython") @@ -133,19 +140,9 @@ def bind_callables_under(self, classdef, name): return self # default unbound __get__ implementation - def simple_call(self, *args_s): - return self.call(simple_args(args_s)) - - def call_args(self, *args_s): - return self.call(complex_args(args_s)) - def call(self, args, implicit_init=False): raise AnnotatorError("Cannot prove that the object is callable") - def op_contains(self, s_element): - return s_Bool - op_contains.can_only_throw = [] - def hint(self, *args_s): return self @@ -249,6 +246,12 @@ items = self.items[s_start.const:s_stop.const] return SomeTuple(items) +@op.contains.register(SomeList) +def contains_SomeList(annotator, obj, element): + annotator.annotation(obj).listdef.generalize(annotator.annotation(element)) + return s_Bool +contains_SomeList.can_only_throw = [] + class __extend__(SomeList): @@ -296,11 +299,6 @@ def getanyitem(self): return self.listdef.read_item() - def op_contains(self, s_element): - self.listdef.generalize(s_element) - return s_Bool - op_contains.can_only_throw = [] - def hint(self, *args_s): hints = args_s[-1].const if 'maxlength' in hints: @@ -340,6 +338,21 @@ raise AnnotatorError("%s: not proven to have non-negative stop" % error) +def _can_only_throw(s_dct, *ignore): + if s_dct.dictdef.dictkey.custom_eq_hash: + return None # r_dict: can throw anything + return [] # else: no possible exception + +@op.contains.register(SomeDict) +def contains_SomeDict(annotator, dct, element): + annotator.annotation(dct).dictdef.generalize_key(annotator.annotation(element)) + if annotator.annotation(dct)._is_empty(): + s_bool = SomeBool() + s_bool.const = False + return s_bool + return s_Bool +contains_SomeDict.can_only_throw = _can_only_throw + class __extend__(SomeDict): def _is_empty(self): @@ -421,19 +434,19 @@ self.dictdef.generalize_value(s_dfl) return self.dictdef.read_value() - def _can_only_throw(self, *ignore): - if self.dictdef.dictkey.custom_eq_hash: - return None # r_dict: can throw anything - return [] # else: no possible exception - - def op_contains(self, s_element): - self.dictdef.generalize_key(s_element) - if self._is_empty(): - s_bool = SomeBool() - s_bool.const = False - return s_bool - return s_Bool - op_contains.can_only_throw = _can_only_throw +@op.contains.register(SomeString) +@op.contains.register(SomeUnicodeString) +def contains_String(annotator, string, char): + if annotator.annotation(char).is_constant() and annotator.annotation(char).const == "\0": + r = SomeBool() + knowntypedata = {} + add_knowntypedata(knowntypedata, False, [string], + annotator.annotation(string).nonnulify()) + r.set_knowntypedata(knowntypedata) + return r + else: + return contains_SomeObject(annotator, string, char) +contains_String.can_only_throw = [] class __extend__(SomeString, @@ -508,19 +521,6 @@ result = self.basestringclass(no_nul=self.no_nul) return result - def op_contains(self, s_element): - if s_element.is_constant() and s_element.const == "\0": - r = SomeBool() - bk = getbookkeeper() - op = bk._find_current_op(opname="contains", arity=2, pos=0, s_type=self) - knowntypedata = {} - add_knowntypedata(knowntypedata, False, [op.args[0]], self.nonnulify()) - r.set_knowntypedata(knowntypedata) - return r - else: - return SomeObject.op_contains(self, s_element) - op_contains.can_only_throw = [] - def method_format(self, *args): raise AnnotatorError("Method format() is not RPython") @@ -709,9 +709,6 @@ return self._emulate_call('__setslice__', s_start, s_stop, s_iterable) class __extend__(SomeBuiltin): - def simple_call(self, *args): - return self.analyser(*args) - def call(self, args, implicit_init=False): args_s, kwds = args.unpack() # prefix keyword arguments with 's_' diff --git a/rpython/flowspace/model.py b/rpython/flowspace/model.py --- a/rpython/flowspace/model.py +++ b/rpython/flowspace/model.py @@ -10,29 +10,6 @@ from rpython.tool.sourcetools import PY_IDENTIFIER, nice_repr_for_func -""" - memory size before and after introduction of __slots__ - using targetpypymain with -no-c - - slottified annotation ann+genc - ------------------------------------------- - nothing 321 MB 442 MB - Var/Const/SpaceOp 205 MB 325 MB - + Link 189 MB 311 MB - + Block 185 MB 304 MB - - Dropping Variable.instances and using - just an instancenames dict brought - annotation down to 160 MB. - Computing the Variable.renamed attribute - and dropping Variable.instancenames - got annotation down to 109 MB. - Probably an effect of less fragmentation. -""" - -__metaclass__ = type - - class FunctionGraph(object): def __init__(self, name, startblock, return_var=None): self.name = name # function name (possibly mangled already) @@ -273,7 +250,7 @@ class Variable(object): - __slots__ = ["_name", "_nr", "concretetype"] + __slots__ = ["_name", "_nr", "annotation", "concretetype"] dummyname = 'v' namesdict = {dummyname: (dummyname, 0)} @@ -296,6 +273,7 @@ def __init__(self, name=None): self._name = self.dummyname self._nr = -1 + self.annotation = None # numbers are bound lazily, when the name is requested if name is not None: self.rename(name) @@ -334,6 +312,15 @@ def foldable(self): return False + def copy(self): + """Make a copy of the Variable, preserving annotations and concretetype.""" + newvar = Variable(self) + newvar.annotation = self.annotation + if hasattr(self, 'concretetype'): + newvar.concretetype = self.concretetype + return newvar + + class Constant(Hashable): __slots__ = ["concretetype"] diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py --- a/rpython/flowspace/operation.py +++ b/rpython/flowspace/operation.py @@ -7,13 +7,14 @@ import operator import sys import types -from rpython.tool.pairtype import pair +from rpython.tool.pairtype import pair, DoubleDispatchRegistry from rpython.rlib.unroll import unrolling_iterable, _unroller from rpython.tool.sourcetools import compile2 from rpython.flowspace.model import (Constant, WrapException, const, Variable, SpaceOperation) from rpython.flowspace.specialcase import register_flow_sc -from rpython.annotator.model import SomeTuple +from rpython.annotator.model import ( + SomeTuple, AnnotatorError, read_can_only_throw) from rpython.annotator.argument import ArgumentsForTranslation from rpython.flowspace.specialcase import SPECIAL_CASES @@ -54,6 +55,11 @@ type.__init__(cls, name, bases, attrdict) if hasattr(cls, 'opname'): setattr(op, cls.opname, cls) + if cls.dispatch == 1: + cls._registry = {} + elif cls.dispatch == 2: + cls._registry = DoubleDispatchRegistry() + class HLOperation(SpaceOperation): __metaclass__ = HLOperationMeta @@ -90,11 +96,13 @@ def constfold(self): return None - def consider(self, annotator, *argcells): - consider_meth = getattr(annotator, 'consider_op_' + self.opname, None) - if not consider_meth: - raise Exception("unknown op: %r" % op) - return consider_meth(*argcells) + def consider(self, annotator, *args): + args_s = [annotator.annotation(arg) for arg in args] + spec = type(self).get_specialization(*args_s) + return spec(annotator, *args) + + def get_can_only_throw(self, annotator): + return None class PureOperation(HLOperation): pure = True @@ -141,16 +149,72 @@ class SingleDispatchMixin(object): dispatch = 1 - def consider(self, annotator, arg, *other_args): - impl = getattr(arg, self.opname) - return impl(*other_args) + @classmethod + def register(cls, Some_cls): + def decorator(func): + cls._registry[Some_cls] = func + return func + return decorator + + @classmethod + def _dispatch(cls, Some_cls): + for c in Some_cls.__mro__: + try: + return cls._registry[c] + except KeyError: + pass + raise AnnotatorError("Unknown operation") + + def get_can_only_throw(self, annotator): + args_s = [annotator.annotation(v) for v in self.args] + spec = type(self).get_specialization(*args_s) + return read_can_only_throw(spec, args_s[0]) + + @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)) + class DoubleDispatchMixin(object): dispatch = 2 - def consider(self, annotator, arg1, arg2, *other_args): - impl = getattr(pair(arg1, arg2), self.opname) - return impl(*other_args) + @classmethod + def register(cls, Some1, Some2): + def decorator(func): + cls._registry[Some1, Some2] = func + return func + return decorator + + @classmethod + def get_specialization(cls, s_arg1, s_arg2, *_ignored): + try: + impl = getattr(pair(s_arg1, s_arg2), cls.opname) + + def specialized(annotator, arg1, arg2, *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._registry[type(s_arg1), type(s_arg2)] + + def get_can_only_throw(self, annotator): + args_s = [annotator.annotation(v) for v in self.args] + spec = type(self).get_specialization(*args_s) + return read_can_only_throw(spec, args_s[0], args_s[1]) def add_operator(name, arity, dispatch=None, pyfunc=None, pure=False, ovf=False): @@ -368,14 +432,15 @@ add_operator('newslice', 3) add_operator('hint', None, dispatch=1) -class Contains(PureOperation): +class Contains(SingleDispatchMixin, PureOperation): opname = 'contains' arity = 2 pyfunc = staticmethod(operator.contains) - # XXX "contains" clash with SomeObject method - def consider(self, annotator, seq, elem): - return seq.op_contains(elem) + # XXX "contains" clashes with SomeObject method + @classmethod + def get_specialization(cls, s_seq, s_elem): + return cls._dispatch(type(s_seq)) class NewDict(HLOperation): @@ -392,7 +457,7 @@ canraise = [] def consider(self, annotator, *args): - return SomeTuple(items=args) + return SomeTuple(items=[annotator.annotation(arg) for arg in args]) class NewList(HLOperation): @@ -400,7 +465,7 @@ canraise = [] def consider(self, annotator, *args): - return annotator.bookkeeper.newlist(*args) + return annotator.bookkeeper.newlist(*[annotator.annotation(arg) for arg in args]) class Pow(PureOperation): diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -1221,17 +1221,29 @@ length_box.getint() <= 14 and # same limit as GCC itemsize in (4, 2, 1)): # Inline a series of STR operations, starting at 'dstaddr_loc'. - # XXX we could optimize STRB/STRH into STR, but this needs care: - # XXX it only works if startindex_loc is a constant, otherwise - # XXX we'd be doing unaligned accesses + next_group = -1 + if itemsize < 4 and startindex >= 0: + # we optimize STRB/STRH into STR, but this needs care: + # it only works if startindex_loc is a constant, otherwise + # we'd be doing unaligned accesses. + next_group = (-startindex * itemsize) & 3 + # self.mc.gen_load_int(r.ip.value, 0) - for i in range(length_box.getint()): - if itemsize == 4: - self.mc.STR_ri(r.ip.value, dstaddr_loc.value, imm=i*4) - elif itemsize == 2: - self.mc.STRH_ri(r.ip.value, dstaddr_loc.value, imm=i*2) + i = 0 + total_size = length_box.getint() * itemsize + while i < total_size: + sz = itemsize + if i == next_group: + next_group += 4 + if next_group <= total_size: + sz = 4 + if sz == 4: + self.mc.STR_ri(r.ip.value, dstaddr_loc.value, imm=i) + elif sz == 2: + self.mc.STRH_ri(r.ip.value, dstaddr_loc.value, imm=i) else: - self.mc.STRB_ri(r.ip.value, dstaddr_loc.value, imm=i*1) + self.mc.STRB_ri(r.ip.value, dstaddr_loc.value, imm=i) + i += sz else: if isinstance(length_box, ConstInt): diff --git a/rpython/jit/backend/arm/test/test_regalloc.py b/rpython/jit/backend/arm/test/test_regalloc.py --- a/rpython/jit/backend/arm/test/test_regalloc.py +++ b/rpython/jit/backend/arm/test/test_regalloc.py @@ -15,7 +15,8 @@ from rpython.jit.tool.oparser import parse from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper.annlowlevel import llhelper -from rpython.rtyper.lltypesystem import rclass, rstr +from rpython.rtyper.lltypesystem import rstr +from rpython.rtyper import rclass from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter import longlong from rpython.jit.backend.llsupport.test.test_regalloc_integration import BaseTestRegalloc @@ -333,7 +334,7 @@ ''' self.interpret(ops, [0, 0, 3, 0]) assert self.getints(3) == [1, -3, 10] - + def test_compare_memory_result_survives(self): ops = ''' [i0, i1, i2, i3] diff --git a/rpython/jit/backend/arm/test/test_runner.py b/rpython/jit/backend/arm/test/test_runner.py --- a/rpython/jit/backend/arm/test/test_runner.py +++ b/rpython/jit/backend/arm/test/test_runner.py @@ -6,7 +6,8 @@ BoxInt) from rpython.jit.metainterp.resoperation import ResOperation, rop from rpython.jit.tool.oparser import parse -from rpython.rtyper.lltypesystem import lltype, llmemory, rclass +from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rtyper import rclass from rpython.rtyper.annlowlevel import llhelper from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.metainterp.history import JitCellToken, TargetToken diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py --- a/rpython/jit/backend/llgraph/runner.py +++ b/rpython/jit/backend/llgraph/runner.py @@ -11,7 +11,8 @@ from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.rtyper.llinterp import LLInterpreter, LLException -from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rclass, rstr +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr +from rpython.rtyper import rclass from rpython.rlib.clibffi import FFI_DEFAULT_ABI from rpython.rlib.rarithmetic import ovfcheck, r_uint, r_ulonglong diff --git a/rpython/jit/backend/llgraph/symbolic.py b/rpython/jit/backend/llgraph/symbolic.py --- a/rpython/jit/backend/llgraph/symbolic.py +++ b/rpython/jit/backend/llgraph/symbolic.py @@ -1,4 +1,5 @@ -from rpython.rtyper.lltypesystem import lltype, rffi, rclass +from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper import rclass Size2Type = [None] * 100 diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py --- a/rpython/jit/backend/llsupport/gc.py +++ b/rpython/jit/backend/llsupport/gc.py @@ -2,7 +2,8 @@ from rpython.rlib import rgc from rpython.rlib.objectmodel import we_are_translated, specialize from rpython.rlib.rarithmetic import ovfcheck -from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rclass, rstr +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr +from rpython.rtyper import rclass from rpython.rtyper.lltypesystem import llgroup from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref @@ -548,12 +549,6 @@ type_id = self.layoutbuilder.get_type_id(A) descr.tid = llop.combine_ushort(lltype.Signed, type_id, 0) - def _set_tid(self, gcptr, tid): - hdr_addr = llmemory.cast_ptr_to_adr(gcptr) - hdr_addr -= self.gcheaderbuilder.size_gc_header - hdr = llmemory.cast_adr_to_ptr(hdr_addr, self.HDRPTR) - hdr.tid = tid - def can_use_nursery_malloc(self, size): return size < self.max_size_of_young_obj @@ -565,7 +560,7 @@ def get_malloc_slowpath_array_addr(self): return self.get_malloc_fn_addr('malloc_array') - + # ____________________________________________________________ def get_ll_description(gcdescr, translator=None, rtyper=None): diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -1,4 +1,5 @@ -from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rclass, rstr +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr +from rpython.rtyper import rclass from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rtyper.llinterp import LLInterpreter from rpython.rtyper.annlowlevel import llhelper, MixLevelHelperAnnotator diff --git a/rpython/jit/backend/llsupport/test/test_regalloc_integration.py b/rpython/jit/backend/llsupport/test/test_regalloc_integration.py --- a/rpython/jit/backend/llsupport/test/test_regalloc_integration.py +++ b/rpython/jit/backend/llsupport/test/test_regalloc_integration.py @@ -12,7 +12,8 @@ from rpython.jit.tool.oparser import parse from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rtyper.annlowlevel import llhelper -from rpython.rtyper.lltypesystem import rclass, rstr +from rpython.rtyper.lltypesystem import rstr +from rpython.rtyper import rclass from rpython.jit.codewriter import longlong from rpython.jit.codewriter.effectinfo import EffectInfo diff --git a/rpython/jit/backend/llsupport/test/test_rewrite.py b/rpython/jit/backend/llsupport/test/test_rewrite.py --- a/rpython/jit/backend/llsupport/test/test_rewrite.py +++ b/rpython/jit/backend/llsupport/test/test_rewrite.py @@ -9,7 +9,8 @@ from rpython.jit.metainterp.optimizeopt.util import equaloplists from rpython.jit.codewriter.heaptracker import register_known_gctype from rpython.jit.metainterp.history import JitCellToken, FLOAT -from rpython.rtyper.lltypesystem import lltype, rclass, rffi +from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper import rclass from rpython.jit.backend.x86.arch import WORD class Evaluator(object): diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -11,7 +11,8 @@ from rpython.jit.metainterp.typesystem import deref from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.tool.oparser import parse -from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi, rclass +from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi +from rpython.rtyper import rclass from rpython.rtyper.annlowlevel import llhelper from rpython.rtyper.llinterp import LLException from rpython.jit.codewriter import heaptracker, longlong @@ -2296,7 +2297,7 @@ for i in range(5): called = [] - + FUNC = self.FuncType([lltype.Signed] * i, lltype.Void) func_ptr = llhelper(lltype.Ptr(FUNC), func_void) calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, @@ -4450,7 +4451,7 @@ def test_zero_ptr_field(self): from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU - + if not isinstance(self.cpu, AbstractLLCPU): py.test.skip("llgraph can't do zero_ptr_field") T = lltype.GcStruct('T') @@ -4478,7 +4479,7 @@ if not isinstance(self.cpu, AbstractLLCPU): py.test.skip("llgraph does not do zero_ptr_field") - + from rpython.jit.backend.llsupport import symbolic S = lltype.GcStruct('S', ('x', lltype.Signed), ('p', llmemory.GCREF), @@ -4503,7 +4504,7 @@ if not isinstance(self.cpu, AbstractLLCPU): py.test.skip("llgraph does not do zero_array") - + PAIR = lltype.Struct('PAIR', ('a', lltype.Signed), ('b', lltype.Signed)) for OF in [lltype.Signed, rffi.INT, rffi.SHORT, rffi.UCHAR, PAIR]: A = lltype.GcArray(OF) diff --git a/rpython/jit/backend/test/test_ll_random.py b/rpython/jit/backend/test/test_ll_random.py --- a/rpython/jit/backend/test/test_ll_random.py +++ b/rpython/jit/backend/test/test_ll_random.py @@ -1,5 +1,6 @@ import py -from rpython.rtyper.lltypesystem import lltype, llmemory, rclass, rffi, rstr +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr +from rpython.rtyper import rclass from rpython.jit.backend.test import test_random from rpython.jit.metainterp.resoperation import ResOperation, rop from rpython.jit.metainterp.history import ConstInt, ConstPtr @@ -561,7 +562,7 @@ subset = builder.subset_of_intvars(r) funcargs = ", ".join(['arg_%d' % i for i in range(len(subset))]) S, v = builder.get_structptr_var(r, must_have_vtable=True) - + code = py.code.Source(""" def f(%s): raise LLException(vtable, ptr) diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py --- a/rpython/jit/backend/test/test_random.py +++ b/rpython/jit/backend/test/test_random.py @@ -10,7 +10,8 @@ from rpython.jit.metainterp.executor import execute_nonspec from rpython.jit.metainterp.resoperation import opname from rpython.jit.codewriter import longlong -from rpython.rtyper.lltypesystem import lltype, rstr, rclass +from rpython.rtyper.lltypesystem import lltype, rstr +from rpython.rtyper import rclass class PleaseRewriteMe(Exception): pass @@ -234,7 +235,7 @@ ', '.join([names[v] for v in fail_args])) print >>s, ' operations = [' for op in self.loop.operations: - self.process_operation(s, op, names) + self.process_operation(s, op, names) print >>s, ' ]' for i, op in enumerate(self.loop.operations): if op.is_guard(): diff --git a/rpython/jit/backend/x86/test/test_regalloc2.py b/rpython/jit/backend/x86/test/test_regalloc2.py --- a/rpython/jit/backend/x86/test/test_regalloc2.py +++ b/rpython/jit/backend/x86/test/test_regalloc2.py @@ -5,7 +5,8 @@ from rpython.jit.backend.detect_cpu import getcpuclass from rpython.jit.backend.x86.arch import WORD from rpython.jit.tool.oparser import parse -from rpython.rtyper.lltypesystem import lltype, rffi, rclass, llmemory, rstr +from rpython.rtyper.lltypesystem import lltype, rffi, llmemory, rstr +from rpython.rtyper import rclass from rpython.rtyper.llinterp import LLException from rpython.rtyper.annlowlevel import llhelper from rpython.jit.codewriter.effectinfo import EffectInfo @@ -319,7 +320,7 @@ raise LLException(vtableptr, xptr) fptr, funcdescr = getllhelper(cpu, f, [lltype.Signed] * count, lltype.Void) - + return heaptracker.adr2int(llmemory.cast_ptr_to_adr(vtableptr)), fptr, funcdescr def getnoexception(cpu, count): diff --git a/rpython/jit/codewriter/assembler.py b/rpython/jit/codewriter/assembler.py --- a/rpython/jit/codewriter/assembler.py +++ b/rpython/jit/codewriter/assembler.py @@ -6,7 +6,8 @@ from rpython.jit.codewriter import heaptracker, longlong from rpython.rlib.objectmodel import ComputedIntSymbolic from rpython.flowspace.model import Constant -from rpython.rtyper.lltypesystem import lltype, llmemory, rclass, rffi +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi +from rpython.rtyper import rclass class AssemblerError(Exception): diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py --- a/rpython/jit/codewriter/effectinfo.py +++ b/rpython/jit/codewriter/effectinfo.py @@ -1,5 +1,5 @@ from rpython.jit.metainterp.typesystem import deref, fieldType, arrayItem -from rpython.rtyper.lltypesystem.rclass import OBJECT +from rpython.rtyper.rclass import OBJECT from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.translator.backendopt.graphanalyze import BoolGraphAnalyzer diff --git a/rpython/jit/codewriter/heaptracker.py b/rpython/jit/codewriter/heaptracker.py --- a/rpython/jit/codewriter/heaptracker.py +++ b/rpython/jit/codewriter/heaptracker.py @@ -1,4 +1,5 @@ -from rpython.rtyper.lltypesystem import lltype, llmemory, rclass +from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rtyper import rclass from rpython.rlib.objectmodel import we_are_translated @@ -125,7 +126,7 @@ vtable = descr.as_vtable_size_descr()._corresponding_vtable vtable = llmemory.cast_ptr_to_adr(vtable) return adr2int(vtable) - + def gc_fielddescrs(gccache, STRUCT, res=None): from rpython.jit.backend.llsupport import descr diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py --- a/rpython/jit/codewriter/jtransform.py +++ b/rpython/jit/codewriter/jtransform.py @@ -12,8 +12,9 @@ from rpython.rlib import objectmodel from rpython.rlib.jit import _we_are_jitted from rpython.rlib.rgc import lltype_is_gc -from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rclass, rffi +from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi from rpython.rtyper.lltypesystem import rbytearray +from rpython.rtyper import rclass from rpython.rtyper.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY from rpython.translator.unsimplify import varoftype @@ -1653,41 +1654,34 @@ self._get_list_nonneg_canraise_flags(op) def _get_initial_newlist_length(self, op, args): - # normalize number of arguments to the 'newlist' function - if len(args) > 1: - v_default = args[1] # initial value: must be 0 or NULL - ARRAY = deref(op.result.concretetype) - if (not isinstance(v_default, Constant) or - v_default.value != arrayItem(ARRAY)._defl()): - raise NotSupported("variable or non-null initial value") - if len(args) >= 1: - return args[0] + assert len(args) <= 1 + if len(args) == 1: + v_length = args[0] + assert v_length.concretetype is lltype.Signed + return v_length else: return Constant(0, lltype.Signed) # length: default to 0 # ---------- fixed lists ---------- def do_fixed_newlist(self, op, args, arraydescr): + # corresponds to rtyper.lltypesystem.rlist.newlist: + # the items may be uninitialized. v_length = self._get_initial_newlist_length(op, args) - assert v_length.concretetype is lltype.Signed - ops = [] - if isinstance(v_length, Constant): - if v_length.value >= 0: - v = v_length - else: - v = Constant(0, lltype.Signed) - else: - v = Variable('new_length') - v.concretetype = lltype.Signed - ops.append(SpaceOperation('int_force_ge_zero', [v_length], v)) ARRAY = op.result.concretetype.TO if ((isinstance(ARRAY.OF, lltype.Ptr) and ARRAY.OF._needsgc()) or isinstance(ARRAY.OF, lltype.Struct)): opname = 'new_array_clear' else: opname = 'new_array' - ops.append(SpaceOperation(opname, [v, arraydescr], op.result)) - return ops + return SpaceOperation(opname, [v_length, arraydescr], op.result) + + def do_fixed_newlist_clear(self, op, args, arraydescr): + # corresponds to rtyper.rlist.ll_alloc_and_clear: + # needs to clear the items. + v_length = self._get_initial_newlist_length(op, args) + return SpaceOperation('new_array_clear', [v_length, arraydescr], + op.result) def do_fixed_list_len(self, op, args, arraydescr): if args[0] in self.vable_array_vars: # virtualizable array @@ -1757,6 +1751,14 @@ arraydescr], op.result) + def do_resizable_newlist_clear(self, op, args, arraydescr, lengthdescr, + itemsdescr, structdescr): + v_length = self._get_initial_newlist_length(op, args) + return SpaceOperation('newlist_clear', + [v_length, structdescr, lengthdescr, itemsdescr, + arraydescr], + op.result) + def do_resizable_newlist_hint(self, op, args, arraydescr, lengthdescr, itemsdescr, structdescr): v_hint = self._get_initial_newlist_length(op, args) diff --git a/rpython/jit/codewriter/support.py b/rpython/jit/codewriter/support.py --- a/rpython/jit/codewriter/support.py +++ b/rpython/jit/codewriter/support.py @@ -14,7 +14,8 @@ from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator from rpython.rtyper.extregistry import ExtRegistryEntry from rpython.rtyper.llinterp import LLInterpreter -from rpython.rtyper.lltypesystem import lltype, rclass, rffi, llmemory, rstr as ll_rstr, rdict as ll_rdict +from rpython.rtyper.lltypesystem import lltype, rffi, llmemory, rstr as ll_rstr, rdict as ll_rdict +from rpython.rtyper import rclass from rpython.rtyper.lltypesystem import rordereddict from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rtyper.lltypesystem.module import ll_math @@ -180,11 +181,11 @@ return LIST.ll_newlist(0) def _ll_1_newlist(LIST, count): return LIST.ll_newlist(count) -def _ll_2_newlist(LIST, count, item): - return rlist.ll_alloc_and_set(LIST, count, item) _ll_0_newlist.need_result_type = True _ll_1_newlist.need_result_type = True -_ll_2_newlist.need_result_type = True + +_ll_1_newlist_clear = rlist._ll_alloc_and_clear +_ll_1_newlist_clear.need_result_type = True def _ll_1_newlist_hint(LIST, hint): return LIST.ll_newlist_hint(hint) diff --git a/rpython/jit/codewriter/test/test_codewriter.py b/rpython/jit/codewriter/test/test_codewriter.py --- a/rpython/jit/codewriter/test/test_codewriter.py +++ b/rpython/jit/codewriter/test/test_codewriter.py @@ -232,18 +232,3 @@ assert 'setarrayitem_raw_i' in s assert 'getarrayitem_raw_i' in s assert 'residual_call_ir_v $<* fn _ll_1_raw_free__arrayPtr>' in s - -def test_newlist_negativ(): - def f(n): - l = [0] * n - return len(l) - - rtyper = support.annotate(f, [-1]) - jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0]) - cw = CodeWriter(FakeCPU(rtyper), [jitdriver_sd]) - graphs = cw.find_all_graphs(FakePolicy()) - backend_optimizations(rtyper.annotator.translator, graphs=graphs) - cw.make_jitcodes(verbose=True) - s = jitdriver_sd.mainjitcode.dump() - assert 'int_force_ge_zero' in s - assert 'new_array' in s diff --git a/rpython/jit/codewriter/test/test_effectinfo.py b/rpython/jit/codewriter/test/test_effectinfo.py --- a/rpython/jit/codewriter/test/test_effectinfo.py +++ b/rpython/jit/codewriter/test/test_effectinfo.py @@ -4,7 +4,7 @@ EffectInfo, VirtualizableAnalyzer) from rpython.rlib import jit from rpython.rtyper.lltypesystem import lltype -from rpython.rtyper.lltypesystem.rclass import OBJECT +from rpython.rtyper.rclass import OBJECT from rpython.translator.translator import TranslationContext, graphof diff --git a/rpython/jit/codewriter/test/test_flatten.py b/rpython/jit/codewriter/test/test_flatten.py --- a/rpython/jit/codewriter/test/test_flatten.py +++ b/rpython/jit/codewriter/test/test_flatten.py @@ -6,7 +6,8 @@ from rpython.jit.codewriter import longlong from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.metainterp.history import AbstractDescr -from rpython.rtyper.lltypesystem import lltype, rclass, rstr, rffi +from rpython.rtyper.lltypesystem import lltype, rstr, rffi +from rpython.rtyper import rclass from rpython.flowspace.model import SpaceOperation, Variable, Constant from rpython.translator.unsimplify import varoftype from rpython.rlib.rarithmetic import ovfcheck, r_uint, r_longlong, r_ulonglong diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py --- a/rpython/jit/codewriter/test/test_jtransform.py +++ b/rpython/jit/codewriter/test/test_jtransform.py @@ -17,7 +17,8 @@ from rpython.flowspace.model import FunctionGraph, Block, Link from rpython.flowspace.model import SpaceOperation, Variable, Constant -from rpython.rtyper.lltypesystem import lltype, llmemory, rclass, rstr, rffi +from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi +from rpython.rtyper import rclass from rpython.rtyper.lltypesystem.module import ll_math from rpython.translator.unsimplify import varoftype from rpython.jit.codewriter import heaptracker, effectinfo @@ -1346,7 +1347,7 @@ assert op2 is None def test_threadlocalref_get(): - from rpython.rtyper.lltypesystem import rclass + from rpython.rtyper import rclass from rpython.rlib.rthread import ThreadLocalReference OS_THREADLOCALREF_GET = effectinfo.EffectInfo.OS_THREADLOCALREF_GET class Foo: pass diff --git a/rpython/jit/codewriter/test/test_list.py b/rpython/jit/codewriter/test/test_list.py --- a/rpython/jit/codewriter/test/test_list.py +++ b/rpython/jit/codewriter/test/test_list.py @@ -87,20 +87,10 @@ """new_array $0, <ArrayDescr> -> %r0""") builtin_test('newlist', [Constant(5, lltype.Signed)], FIXEDLIST, """new_array $5, <ArrayDescr> -> %r0""") - builtin_test('newlist', [Constant(-2, lltype.Signed)], FIXEDLIST, - """new_array $0, <ArrayDescr> -> %r0""") builtin_test('newlist', [varoftype(lltype.Signed)], FIXEDLIST, - """int_force_ge_zero %i0 -> %i1\n""" - """new_array %i1, <ArrayDescr> -> %r0""") - builtin_test('newlist', [Constant(5, lltype.Signed), - Constant(0, lltype.Signed)], FIXEDLIST, - """new_array $5, <ArrayDescr> -> %r0""") - builtin_test('newlist', [Constant(5, lltype.Signed), - Constant(1, lltype.Signed)], FIXEDLIST, - NotSupported) - builtin_test('newlist', [Constant(5, lltype.Signed), - varoftype(lltype.Signed)], FIXEDLIST, - NotSupported) + """new_array %i0, <ArrayDescr> -> %r0""") + builtin_test('newlist_clear', [Constant(5, lltype.Signed)], FIXEDLIST, + """new_array_clear $5, <ArrayDescr> -> %r0""") builtin_test('newlist', [], FIXEDPTRLIST, """new_array_clear $0, <ArrayDescr> -> %r0""") @@ -179,15 +169,8 @@ """newlist $5, """+alldescrs+""" -> %r0""") builtin_test('newlist', [varoftype(lltype.Signed)], VARLIST, """newlist %i0, """+alldescrs+""" -> %r0""") - builtin_test('newlist', [Constant(5, lltype.Signed), - Constant(0, lltype.Signed)], VARLIST, - """newlist $5, """+alldescrs+""" -> %r0""") - builtin_test('newlist', [Constant(5, lltype.Signed), - Constant(1, lltype.Signed)], VARLIST, - NotSupported) - builtin_test('newlist', [Constant(5, lltype.Signed), - varoftype(lltype.Signed)], VARLIST, - NotSupported) + builtin_test('newlist_clear', [Constant(5, lltype.Signed)], VARLIST, + """newlist_clear $5, """+alldescrs+""" -> %r0""") def test_resizable_getitem(): builtin_test('list.getitem/NONNEG', diff --git a/rpython/jit/codewriter/test/test_regalloc.py b/rpython/jit/codewriter/test/test_regalloc.py --- a/rpython/jit/codewriter/test/test_regalloc.py +++ b/rpython/jit/codewriter/test/test_regalloc.py @@ -7,7 +7,8 @@ from rpython.flowspace.model import Variable, Constant, SpaceOperation from rpython.flowspace.model import FunctionGraph, Block, Link from rpython.flowspace.model import c_last_exception -from rpython.rtyper.lltypesystem import lltype, llmemory, rclass +from rpython.rtyper.lltypesystem import lltype, llmemory +from rpython.rtyper import rclass from rpython.rlib.rarithmetic import ovfcheck diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py --- a/rpython/jit/metainterp/blackhole.py +++ b/rpython/jit/metainterp/blackhole.py @@ -8,7 +8,8 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck from rpython.rlib.unroll import unrolling_iterable -from rpython.rtyper.lltypesystem import lltype, llmemory, rclass, rffi +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi +from rpython.rtyper import rclass from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.jit_libffi import CIF_DESCRIPTION_P @@ -1017,6 +1018,15 @@ return result @arguments("cpu", "i", "d", "d", "d", "d", returns="r") + def bhimpl_newlist_clear(cpu, length, structdescr, lengthdescr, + itemsdescr, arraydescr): + result = cpu.bh_new(structdescr) + cpu.bh_setfield_gc_i(result, length, lengthdescr) + items = cpu.bh_new_array_clear(length, arraydescr) + cpu.bh_setfield_gc_r(result, items, itemsdescr) + return result + + @arguments("cpu", "i", "d", "d", "d", "d", returns="r") def bhimpl_newlist_hint(cpu, lengthhint, structdescr, lengthdescr, itemsdescr, arraydescr): result = cpu.bh_new(structdescr) @@ -1163,7 +1173,7 @@ @arguments("cpu", "i", "d", returns="r") def bhimpl_new_array_clear(cpu, length, arraydescr): - return cpu.bh_new_array_clear(length, arraydescr) + return cpu.bh_new_array_clear(length, arraydescr) @arguments("cpu", "r", "i", "d", returns="i") def bhimpl_getarrayitem_gc_i(cpu, array, index, arraydescr): diff --git a/rpython/jit/metainterp/jitexc.py b/rpython/jit/metainterp/jitexc.py --- a/rpython/jit/metainterp/jitexc.py +++ b/rpython/jit/metainterp/jitexc.py @@ -1,6 +1,7 @@ from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance -from rpython.rtyper.lltypesystem import lltype, rclass +from rpython.rtyper.lltypesystem import lltype +from rpython.rtyper import rclass from rpython.rtyper.llinterp import LLException from rpython.rlib.objectmodel import we_are_translated from rpython.jit.codewriter import longlong diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -8293,6 +8293,22 @@ self.optimize_loop(ops, expected) def test_licm_boxed_opaque_getitem_unknown_class(self): + # Explanation: the getfield_gc(p2) is done on what starts as + # an opaque object. The getfield_gc(p1) is moved out of the + # (non-preamble) loop. It looks like the getfield_gc(p2) + # should also move out. However, moving the getfield_gc(p2) + # earlier can be dangerous with opaque pointers: we can't move + # it before other guards that indirectly check for which type + # of object is in p2. (In this simple test there are no guard + # at all between the start of the loop and the + # getfield_gc(p2), but in general there are.) + # + # There are two cases: (1) moving the getfield_gc(p2) out of + # the loop into the preamble: this does not look like a + # problem because we already have a getfield_gc(p2) there, on + # the same p2. Case (2) is moving the getfield_gc(p2) into + # the short preamble: this is more problematic because the + # short preamble can't do the indirect checking on p1. ops = """ [p1] p2 = getfield_gc(p1, descr=nextdescr) @@ -8326,6 +8342,7 @@ self.optimize_loop(ops, expected) def test_licm_unboxed_opaque_getitem_unknown_class(self): + # see test_licm_boxed_opaque_getitem_unknown_class ops = """ [p2] mark_opaque_ptr(p2) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py --- a/rpython/jit/metainterp/optimizeopt/test/test_util.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py @@ -1,8 +1,9 @@ import py, random -from rpython.rtyper.lltypesystem import lltype, llmemory, rclass, rffi -from rpython.rtyper.lltypesystem.rclass import OBJECT, OBJECT_VTABLE -from rpython.rtyper.rclass import FieldListAccessor, IR_QUASIIMMUTABLE +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi +from rpython.rtyper import rclass +from rpython.rtyper.rclass import ( + OBJECT, OBJECT_VTABLE, FieldListAccessor, IR_QUASIIMMUTABLE) from rpython.jit.backend.llgraph import runner from rpython.jit.metainterp.history import (BoxInt, BoxPtr, ConstInt, ConstPtr, diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -764,9 +764,12 @@ def optimize_GETARRAYITEM_GC(self, op): value = self.getvalue(op.getarg(0)) if value.is_virtual(): + assert isinstance(value, VArrayValue) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit