Author: Hakan Ardo <ha...@debian.org> Branch: jit-short_from_state Changeset: r46476:407843026514 Date: 2011-08-13 13:52 +0200 http://bitbucket.org/pypy/pypy/changeset/407843026514/
Log: hg merge default diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -59,8 +59,9 @@ if name in anonymous_fields: for subname in value._names: resnames.append(subname) - relpos = startpos + value._fieldtypes[subname].offset - subvalue = value._fieldtypes[subname].ctype + subfield = getattr(value, subname) + relpos = startpos + subfield.offset + subvalue = subfield.ctype fields[subname] = Field(subname, relpos, subvalue._sizeofinstances(), subvalue, i, is_bitfield) @@ -68,7 +69,7 @@ resnames.append(name) names = resnames self._names = names - self._fieldtypes = fields + self.__dict__.update(fields) class Field(object): def __init__(self, name, offset, size, ctype, num, is_bitfield): @@ -82,6 +83,35 @@ return "<Field '%s' offset=%d size=%d>" % (self.name, self.offset, self.size) + def __get__(self, obj, cls=None): + if obj is None: + return self + if self.is_bitfield: + # bitfield member, use direct access + return obj._buffer.__getattr__(self.name) + else: + fieldtype = self.ctype + offset = self.num + suba = obj._subarray(fieldtype, self.name) + return fieldtype._CData_output(suba, obj, offset) + + + def __set__(self, obj, value): + fieldtype = self.ctype + cobj = fieldtype.from_param(value) + if ensure_objects(cobj) is not None: + key = keepalive_key(self.num) + store_reference(obj, key, cobj._objects) + arg = cobj._get_buffer_value() + if fieldtype._fficompositesize is not None: + from ctypes import memmove + dest = obj._buffer.fieldaddress(self.name) + memmove(dest, arg, fieldtype._fficompositesize) + else: + obj._buffer.__setattr__(self.name, arg) + + + # ________________________________________________________________ def _set_shape(tp, rawfields, is_union=False): @@ -90,11 +120,6 @@ tp._ffiargshape = tp._ffishape = (tp._ffistruct, 1) tp._fficompositesize = tp._ffistruct.size -def struct_getattr(self, name): - if name not in ('_fields_', '_fieldtypes'): - if hasattr(self, '_fieldtypes') and name in self._fieldtypes: - return self._fieldtypes[name] - return _CDataMeta.__getattribute__(self, name) def struct_setattr(self, name, value): if name == '_fields_': @@ -138,10 +163,8 @@ if '_fields_' not in self.__dict__: self._fields_ = [] self._names = [] - self._fieldtypes = {} _set_shape(self, [], self._is_union) - __getattr__ = struct_getattr __setattr__ = struct_setattr def from_address(self, address): @@ -211,40 +234,6 @@ A = _rawffi.Array(fieldtype._ffishape) return A.fromaddress(address, 1) - def __setattr__(self, name, value): - try: - field = self._fieldtypes[name] - except KeyError: - return _CData.__setattr__(self, name, value) - fieldtype = field.ctype - cobj = fieldtype.from_param(value) - if ensure_objects(cobj) is not None: - key = keepalive_key(field.num) - store_reference(self, key, cobj._objects) - arg = cobj._get_buffer_value() - if fieldtype._fficompositesize is not None: - from ctypes import memmove - dest = self._buffer.fieldaddress(name) - memmove(dest, arg, fieldtype._fficompositesize) - else: - self._buffer.__setattr__(name, arg) - - def __getattribute__(self, name): - if name == '_fieldtypes': - return _CData.__getattribute__(self, '_fieldtypes') - try: - field = self._fieldtypes[name] - except KeyError: - return _CData.__getattribute__(self, name) - if field.is_bitfield: - # bitfield member, use direct access - return self._buffer.__getattr__(name) - else: - fieldtype = field.ctype - offset = field.num - suba = self._subarray(fieldtype, name) - return fieldtype._CData_output(suba, self, offset) - def _get_buffer_for_param(self): return self diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -48,12 +48,6 @@ .. image:: image/jitviewer.png -We would like to add one level to this hierarchy, by showing the generated -machine code for each jit operation. The necessary information is already in -the log file produced by the JIT, so it is "only" a matter of teaching the -jitviewer to display it. Ideally, the machine code should be hidden by -default and viewable on request. - The jitviewer is a web application based on flask and jinja2 (and jQuery on the client): if you have great web developing skills and want to help PyPy, this is an ideal task to get started, because it does not require any deep diff --git a/pypy/doc/release-1.6.0.rst b/pypy/doc/release-1.6.0.rst --- a/pypy/doc/release-1.6.0.rst +++ b/pypy/doc/release-1.6.0.rst @@ -1,6 +1,6 @@ -=========================== -PyPy 1.6 - faster than ever -=========================== +========================================================= +PyPy 1.6 - XXX thing something out (I like kickass panda) +========================================================= We're pleased to announce the 1.6 release of PyPy. This release brings a lot of bugfixes and performance improvements over 1.5, and improves support for @@ -15,15 +15,15 @@ PyPy is a very compliant Python interpreter, almost a drop-in replacement for CPython 2.7.1. It's fast (`pypy 1.5 and cpython 2.6.2`_ performance comparison) -due to its integrated tracing JIT compiler. XXX: compare to 2.7.1 +due to its integrated tracing JIT compiler. This release supports x86 machines running Linux 32/64 or Mac OS X. Windows 32 is beta (it roughly works but a lot of small issues have not been fixed so far). Windows 64 is not yet supported. -The main topics of this release are speed and stability: on average, PyPy 1.6 -is between 20% and 30% faster than PyPy 1.5, and overall it's 4.3 times faster -than CPython when running our set of benchmarks. +The main topics of this release are speed and stability: on average on +our benchmark suite, PyPy 1.6 is between 20% and 30% faster than PyPy 1.5, +which was already much faster than CPython on our set of benchmarks. The speed improvements have been made possible by optimizing many of the layers which compose PyPy. In particular, we improved: the Garbage Collector, @@ -55,7 +55,8 @@ - optimized dictionaries: the internal representation of dictionaries is now dynamically selected depending on the type of stored objects, resulting in faster code and smaller memory footprint. For example, dictionaries whose - keys are all strings, or all integers. + keys are all strings, or all integers. Other dictionaries are also smaller + due to bugfixes. * JitViewer: this is the first official release which includes the JitViewer, a web-based tool which helps you to see which parts of your Python code have @@ -67,13 +68,14 @@ our `compatibility wiki`_. * Multibyte encoding support: this was of of the last areas in which we were - still behind CPython, but now we fully support them. (XXX: is that true?) + still behind CPython, but now we fully support them. * Preliminary support for NumPy: this release includes a preview of a very fast NumPy module integrated with the PyPy JIT. Unfortunately, this does not mean that you can expect to take an existing NumPy program and run it on PyPy, because the module is still unfinished and supports only some of the - numpy API. However, what works is blazingly fast :-) + numpy API. However, barring some details, what works should be + blazingly fast :-) * Bugfixes: since the 1.5 release we fixed 53 bugs in our `bug tracker`_, not counting the numerous bugs that were found and reported through other @@ -81,5 +83,6 @@ Cheers, -Carl Friedrich Bolz, Laura Creighton, Antonio Cuni, Maciej Fijalkowski, -Amaury Forgeot d'Arc, Alex Gaynor, Armin Rigo and the PyPy team +Hakan Ardo, Carl Friedrich Bolz, Laura Creighton, Antonio Cuni, +Maciej Fijalkowski, Amaury Forgeot d'Arc, Alex Gaynor, +Armin Rigo and the PyPy team diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -80,7 +80,7 @@ self.escaped = True def append_block(self, block): - block.previous = self.lastblock + assert block.previous is self.lastblock self.lastblock = block def pop_block(self): @@ -106,7 +106,8 @@ while i >= 0: block = lst[i] i -= 1 - self.append_block(block) + block.previous = self.lastblock + self.lastblock = block def get_builtin(self): if self.space.config.objspace.honor__builtins__: diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -892,16 +892,16 @@ raise BytecodeCorruption, "old opcode, no longer in use" def SETUP_LOOP(self, offsettoend, next_instr): - block = LoopBlock(self, next_instr + offsettoend) - self.append_block(block) + block = LoopBlock(self, next_instr + offsettoend, self.lastblock) + self.lastblock = block def SETUP_EXCEPT(self, offsettoend, next_instr): - block = ExceptBlock(self, next_instr + offsettoend) - self.append_block(block) + block = ExceptBlock(self, next_instr + offsettoend, self.lastblock) + self.lastblock = block def SETUP_FINALLY(self, offsettoend, next_instr): - block = FinallyBlock(self, next_instr + offsettoend) - self.append_block(block) + block = FinallyBlock(self, next_instr + offsettoend, self.lastblock) + self.lastblock = block def SETUP_WITH(self, offsettoend, next_instr): w_manager = self.peekvalue() @@ -915,8 +915,8 @@ w_exit = self.space.get(w_descr, w_manager) self.settopvalue(w_exit) w_result = self.space.get_and_call_function(w_enter, w_manager) - block = WithBlock(self, next_instr + offsettoend) - self.append_block(block) + block = WithBlock(self, next_instr + offsettoend, self.lastblock) + self.lastblock = block self.pushvalue(w_result) def WITH_CLEANUP(self, oparg, next_instr): @@ -1247,10 +1247,10 @@ _immutable_ = True - def __init__(self, frame, handlerposition): + def __init__(self, frame, handlerposition, previous): self.handlerposition = handlerposition self.valuestackdepth = frame.valuestackdepth - self.previous = None # this makes a linked list of blocks + self.previous = previous # this makes a linked list of blocks def __eq__(self, other): return (self.__class__ is other.__class__ and diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py --- a/pypy/jit/metainterp/pyjitpl.py +++ b/pypy/jit/metainterp/pyjitpl.py @@ -1429,6 +1429,7 @@ # can change from run to run. d = {} for jitcode in self.indirectcalltargets: + assert jitcode.fnaddr not in d d[jitcode.fnaddr] = jitcode self.globaldata.indirectcall_dict = d return d.get(fnaddress, None) diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py --- a/pypy/jit/metainterp/test/test_ajit.py +++ b/pypy/jit/metainterp/test/test_ajit.py @@ -3206,6 +3206,8 @@ self.check_loops(arraylen_gc=2, everywhere=True) def test_release_gil_flush_heap_cache(self): + if sys.platform == "win32": + py.test.skip("needs 'time'") T = rffi.CArrayPtr(rffi.TIME_T) external = rffi.llexternal("time", [T], rffi.TIME_T, threadsafe=True) diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -295,7 +295,6 @@ """ Intermediate class representing a float literal. """ - _immutable_fields_ = ["float_value"] signature = Signature() def __init__(self, float_value): @@ -356,8 +355,6 @@ class Call1(VirtualArray): - _immutable_fields_ = ["function", "values"] - def __init__(self, function, values, signature): VirtualArray.__init__(self, signature) self.function = function @@ -376,8 +373,6 @@ """ Intermediate class for performing binary operations. """ - _immutable_fields_ = ["function", "left", "right"] - def __init__(self, function, left, right, signature): VirtualArray.__init__(self, signature) self.function = function @@ -404,8 +399,6 @@ Class for representing views of arrays, they will reflect changes of parent arrays. Example: slices """ - _immutable_fields_ = ["parent"] - def __init__(self, parent, signature): BaseArray.__init__(self) self.signature = signature @@ -433,7 +426,6 @@ raise NotImplementedError class SingleDimSlice(ViewArray): - _immutable_fields_ = ["start", "stop", "step", "size"] static_signature = Signature() def __init__(self, start, stop, step, slice_length, parent, signature): diff --git a/pypy/module/posix/app_posix.py b/pypy/module/posix/app_posix.py --- a/pypy/module/posix/app_posix.py +++ b/pypy/module/posix/app_posix.py @@ -315,7 +315,7 @@ self._proc = proc def close(self): self._stream.close() - return self._proc.wait() + return self._proc.wait() or None # 0 => None __del__ = close def __getattr__(self, name): return getattr(self._stream, name) diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py --- a/pypy/objspace/flow/flowcontext.py +++ b/pypy/objspace/flow/flowcontext.py @@ -406,8 +406,8 @@ w_exit = self.space.getattr(w_manager, self.space.wrap("__exit__")) self.settopvalue(w_exit) w_result = self.space.call_method(w_manager, "__enter__") - block = WithBlock(self, next_instr + offsettoend) - self.append_block(block) + block = WithBlock(self, next_instr + offsettoend, self.lastblock) + self.lastblock = block self.pushvalue(w_result) # XXX Unimplemented 2.7 opcodes ---------------- diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -215,6 +215,7 @@ # then modify the result. return _decimalstr_to_bigint(s) + @jit.elidable def toint(self): """ Get an integer from a bigint object. @@ -294,6 +295,7 @@ def ne(self, other): return not self.eq(other) + @jit.elidable def lt(self, other): if self.sign > other.sign: return False @@ -1603,7 +1605,7 @@ elif (base & (base - 1)) == 0: # JRH: special case for power-of-2 bases accum = 0 - accumbits = 0 # # of bits in accum + accumbits = 0 # # of bits in accum basebits = 1 # # of bits in base-1 i = base while 1: diff --git a/pypy/rlib/runicode.py b/pypy/rlib/runicode.py --- a/pypy/rlib/runicode.py +++ b/pypy/rlib/runicode.py @@ -1505,17 +1505,16 @@ rffi.free_nonmovingbuffer(s, dataptr) def unicode_encode_mbcs(p, size, errors, errorhandler=None): + if size == 0: + return '' dataptr = rffi.get_nonmoving_unicodebuffer(p) try: # first get the size of the result - if size > 0: - mbcssize = WideCharToMultiByte(CP_ACP, 0, - dataptr, size, None, 0, - None, None) - if mbcssize == 0: - raise rwin32.lastWindowsError() - else: - mbcssize = 0 + mbcssize = WideCharToMultiByte(CP_ACP, 0, + dataptr, size, None, 0, + None, None) + if mbcssize == 0: + raise rwin32.lastWindowsError() raw_buf, gc_buf = rffi.alloc_buffer(mbcssize) try: diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -561,6 +561,7 @@ 'debug_catch_exception': LLOp(), 'debug_reraise_traceback': LLOp(), 'debug_print_traceback': LLOp(), + 'debug_nonnull_pointer': LLOp(canrun=True), # __________ instrumentation _________ 'instrument_count': LLOp(), diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -526,6 +526,9 @@ def op_have_debug_prints(): return debug.have_debug_prints() +def op_debug_nonnull_pointer(x): + assert x + def op_gc_stack_bottom(): pass # marker for trackgcroot.py diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py --- a/pypy/rpython/memory/gc/minimark.py +++ b/pypy/rpython/memory/gc/minimark.py @@ -1699,8 +1699,8 @@ # # Add the roots from the other sources. self.root_walker.walk_roots( - MiniMarkGC._collect_ref, # stack roots - MiniMarkGC._collect_ref, # static in prebuilt non-gc structures + MiniMarkGC._collect_ref_stk, # stack roots + MiniMarkGC._collect_ref_stk, # static in prebuilt non-gc structures None) # we don't need the static in all prebuilt gc objects # # If we are in an inner collection caused by a call to a finalizer, @@ -1717,8 +1717,10 @@ def _collect_obj(obj, objects_to_trace): objects_to_trace.append(obj) - def _collect_ref(self, root): - self.objects_to_trace.append(root.address[0]) + def _collect_ref_stk(self, root): + obj = root.address[0] + llop.debug_nonnull_pointer(lltype.Void, obj) + self.objects_to_trace.append(obj) def _collect_ref_rec(self, root, ignored): self.objects_to_trace.append(root.address[0]) diff --git a/pypy/tool/release/force-builds.py b/pypy/tool/release/force-builds.py --- a/pypy/tool/release/force-builds.py +++ b/pypy/tool/release/force-builds.py @@ -26,7 +26,7 @@ 'pypy-c-app-level-win-x86-32', 'pypy-c-jit-linux-x86-32', 'pypy-c-jit-linux-x86-64', -# 'pypy-c-jit-macosx-x86-32', + 'pypy-c-jit-macosx-x86-64', 'pypy-c-jit-win-x86-32', ] diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py --- a/pypy/tool/release/package.py +++ b/pypy/tool/release/package.py @@ -50,8 +50,8 @@ pypy_c_dir = py.path.local(override_pypy_c).dirname else: pypy_c_dir = basedir.join('pypy', 'translator', 'goal') - pypy_c = pypy_c_dir.join(rename_pypy_c + '.exe') - libpypy_c = pypy_c_dir.join('lib' + rename_pypy_c + '.dll') + pypy_c = pypy_c_dir.join('pypy-c.exe') + libpypy_c = pypy_c_dir.join('libpypy-c.dll') binaries = [(pypy_c, pypy_c.basename), (libpypy_c, libpypy_c.basename), (pypy_c_dir.join('libexpat.dll'), 'libexpat.dll')] diff --git a/pypy/translator/c/funcgen.py b/pypy/translator/c/funcgen.py --- a/pypy/translator/c/funcgen.py +++ b/pypy/translator/c/funcgen.py @@ -823,6 +823,11 @@ cdecl(typename, '')) return result + def OP_DEBUG_NONNULL_POINTER(self, op): + expr = self.expr(op.args[0]) + return 'if ((-8192 <= (long)%s) && (((long)%s) < 8192)) abort();' % ( + expr, expr) + def OP_INSTRUMENT_COUNT(self, op): counter_label = op.args[1].value self.db.instrument_ncounter = max(self.db.instrument_ncounter, diff --git a/pypy/translator/c/gcc/instruction.py b/pypy/translator/c/gcc/instruction.py --- a/pypy/translator/c/gcc/instruction.py +++ b/pypy/translator/c/gcc/instruction.py @@ -68,15 +68,21 @@ class Insn(object): _args_ = [] _locals_ = [] + hack = None def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, + return '%s(%s) --- %r' % (self.__class__.__name__, ', '.join([str(getattr(self, name)) - for name in self._args_])) + for name in self._args_]), + self.hack) def requestgcroots(self, tracker): return {} def source_of(self, localvar, tag): + if tag is None: + if self.hack is None: + self.hack = set() + self.hack.add(localvar) return localvar def all_sources_of(self, localvar): @@ -139,7 +145,7 @@ def source_of(self, localvar, tag): if localvar == self.target: return somenewvalue - return localvar + return Insn.source_of(self, localvar, tag) def all_sources_of(self, localvar): if localvar == self.target: @@ -157,7 +163,7 @@ def source_of(self, localvar, tag): if localvar == self.target: return self.source - return localvar + return Insn.source_of(self, localvar, tag) def all_sources_of(self, localvar): if localvar == self.target: diff --git a/pypy/translator/c/gcc/test/elf64/track_zero.s b/pypy/translator/c/gcc/test/elf64/track_zero.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf64/track_zero.s @@ -0,0 +1,18 @@ + .type pypy_g_do_call_1, @function +pypy_g_do_call_1: + pushq %rbx + pushq %r12 + movq %rdi, %rbx + movq %rsi, %r12 + call number1 + ;; expected {16(%rsp) | 8(%rsp), (%rsp), %r13, %r14, %r15, %rbp | %r12} + testq %rbx, %rbx ; here rbx is an integer, not a gc ref + je .L1 ; if rbx==0, jump to L1, where rbx==NULLGCREF + movq (%rax), %rbx ; else load a gc ref +.L1: + /* GCROOT %rbx */ + /* GCROOT %r12 */ + popq %r12 + popq %rbx + ret + .size pypy_g_do_call_1, .-pypy_g_do_call_1 diff --git a/pypy/translator/c/gcc/test/elf64/track_zero_2.s b/pypy/translator/c/gcc/test/elf64/track_zero_2.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf64/track_zero_2.s @@ -0,0 +1,18 @@ + .type pypy_g_do_call_1, @function +pypy_g_do_call_1: + pushq %rbx + pushq %r12 + movq %rdi, %rbx + movq %rsi, %r12 + call number1 + ;; expected {16(%rsp) | 8(%rsp), (%rsp), %r13, %r14, %r15, %rbp | %rbx, %r12} + testq %rbx, %rbx + je .L1 + movq (%rax), %r12 +.L1: + /* GCROOT %rbx */ + /* GCROOT %r12 */ + popq %r12 + popq %rbx + ret + .size pypy_g_do_call_1, .-pypy_g_do_call_1 diff --git a/pypy/translator/c/gcc/test/elf64/track_zero_3.s b/pypy/translator/c/gcc/test/elf64/track_zero_3.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf64/track_zero_3.s @@ -0,0 +1,14 @@ + .type pypy_g_do_call_1, @function +pypy_g_do_call_1: + pushq %rbx + movq %rdi, %rbx + call number1 + ;; expected {8(%rsp) | (%rsp), %r12, %r13, %r14, %r15, %rbp | %rbx} + testq %rax, %rax + je .L1 + call RPyAssertFailed +.L1: + /* GCROOT %rbx */ + popq %rbx + ret + .size pypy_g_do_call_1, .-pypy_g_do_call_1 diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py --- a/pypy/translator/c/gcc/trackgcroot.py +++ b/pypy/translator/c/gcc/trackgcroot.py @@ -173,6 +173,7 @@ def parse_instructions(self): self.insns = [InsnFunctionStart(self.CALLEE_SAVE_REGISTERS, self.WORD)] + self.tested_for_zero = None ignore_insns = False for lineno, line in enumerate(self.lines): if lineno < self.skip: @@ -186,6 +187,14 @@ elif match: if not ignore_insns: opname = match.group(1) + # + try: + cf = self.OPS_WITH_PREFIXES_CHANGING_FLAGS[opname] + except KeyError: + cf = self.find_missing_changing_flags(opname) + if cf: + self.tested_for_zero = None + # try: meth = getattr(self, 'visit_' + opname) except AttributeError: @@ -222,6 +231,15 @@ raise UnrecognizedOperation(opname) setattr(cls, 'visit_' + opname, cls.visit_nop) + @classmethod + def find_missing_changing_flags(cls, opname): + prefix = opname + while prefix and prefix not in cls.OPS_WITH_PREFIXES_CHANGING_FLAGS: + prefix = prefix[:-1] + cf = cls.OPS_WITH_PREFIXES_CHANGING_FLAGS.get(prefix, False) + cls.OPS_WITH_PREFIXES_CHANGING_FLAGS[opname] = cf + return cf + def list_collecting_call_insns(self): return [insn for insn in self.insns if isinstance(insn, InsnCall) if insn.name not in self.cannot_collect] @@ -467,6 +485,19 @@ 'movz', ]) + # a partial list is hopefully good enough for now; it's all to support + # only one corner case, tested in elf64/track_zero.s + OPS_WITH_PREFIXES_CHANGING_FLAGS = dict.fromkeys([ + 'cmp', 'test', 'lahf', 'cld', 'std', 'rep', + 'ucomi', 'comi', + 'add', 'sub', 'xor', + 'inc', 'dec', 'not', 'neg', 'or', 'and', 'sbb', 'adc', + 'shl', 'shr', 'sal', 'sar', 'rol', 'ror', 'mul', 'imul', 'div', 'idiv', + 'bt', 'call', 'int', + 'jmp', # not really changing flags, but we shouldn't assume + # anything about the operations on the following lines + ], True) + visit_movb = visit_nop visit_movw = visit_nop visit_addb = visit_nop @@ -687,11 +718,13 @@ return InsnRet(self.CALLEE_SAVE_REGISTERS) return InsnStop("jump") - def register_jump_to(self, label): - if not isinstance(self.insns[-1], InsnStop): - self.labels[label].previous_insns.append(self.insns[-1]) + def register_jump_to(self, label, lastinsn=None): + if lastinsn is None: + lastinsn = self.insns[-1] + if not isinstance(lastinsn, InsnStop): + self.labels[label].previous_insns.append(lastinsn) - def conditional_jump(self, line): + def conditional_jump(self, line, je=False, jne=False): match = self.r_jump.match(line) if not match: match = self.r_jump_rel_label.match(line) @@ -708,12 +741,22 @@ i += 1 else: label = match.group(1) - self.register_jump_to(label) - return [InsnCondJump(label)] + prefix = [] + lastinsn = None + postfix = [] + if self.tested_for_zero is not None: + if je: + # generate pseudo-code... + prefix = [InsnCopyLocal(self.tested_for_zero, '%tmp'), + InsnSetLocal(self.tested_for_zero)] + postfix = [InsnCopyLocal('%tmp', self.tested_for_zero)] + lastinsn = prefix[-1] + elif jne: + postfix = [InsnSetLocal(self.tested_for_zero)] + self.register_jump_to(label, lastinsn) + return prefix + [InsnCondJump(label)] + postfix visit_jmpl = visit_jmp - visit_je = conditional_jump - visit_jne = conditional_jump visit_jg = conditional_jump visit_jge = conditional_jump visit_jl = conditional_jump @@ -731,6 +774,20 @@ visit_jc = conditional_jump visit_jnc = conditional_jump + def visit_je(self, line): + return self.conditional_jump(line, je=True) + + def visit_jne(self, line): + return self.conditional_jump(line, jne=True) + + def _visit_test(self, line): + match = self.r_binaryinsn.match(line) + source = match.group("source") + target = match.group("target") + if source == target: + self.tested_for_zero = source + return [] + def _visit_xchg(self, line): # only support the format used in VALGRIND_DISCARD_TRANSLATIONS # which is to use a marker no-op "xchgl %ebx, %ebx" @@ -884,6 +941,7 @@ visit_and = FunctionGcRootTracker._visit_and visit_xchgl = FunctionGcRootTracker._visit_xchg + visit_testl = FunctionGcRootTracker._visit_test # used in "xor reg, reg" to create a NULL GC ptr visit_xorl = FunctionGcRootTracker.binary_insn @@ -942,6 +1000,7 @@ visit_xorq = FunctionGcRootTracker.binary_insn visit_xchgq = FunctionGcRootTracker._visit_xchg + visit_testq = FunctionGcRootTracker._visit_test # FIXME: similar to visit_popl for 32-bit def visit_popq(self, line): diff --git a/pypy/translator/platform/windows.py b/pypy/translator/platform/windows.py --- a/pypy/translator/platform/windows.py +++ b/pypy/translator/platform/windows.py @@ -231,6 +231,9 @@ linkflags = self._args_for_shared(linkflags) + [ '/EXPORT:$(PYPY_MAIN_FUNCTION)'] linkflags += self._exportsymbols_link_flags(eci, relto=path) + # Make sure different functions end up at different addresses! + # This is required for the JIT. + linkflags.append('/opt:noicf') if shared: so_name = exe_name.new(purebasename='lib' + exe_name.purebasename, _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit