Author: Armin Rigo <ar...@tunes.org> Branch: release-1.6.x Changeset: r46499:dbeb9dd992ab Date: 2011-08-14 17:31 +0000 http://bitbucket.org/pypy/pypy/changeset/dbeb9dd992ab/
Log: merge heads diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -891,7 +891,8 @@ self.statement = c_void_p() next_char = c_char_p() - ret = sqlite.sqlite3_prepare_v2(self.con.db, sql, -1, byref(self.statement), byref(next_char)) + sql_char = c_char_p(sql) + ret = sqlite.sqlite3_prepare_v2(self.con.db, sql_char, -1, byref(self.statement), byref(next_char)) if ret == SQLITE_OK and self.statement.value is None: # an empty statement, we work around that, as it's the least trouble ret = sqlite.sqlite3_prepare_v2(self.con.db, "select 42", -1, byref(self.statement), byref(next_char)) @@ -902,6 +903,7 @@ self.con._remember_statement(self) if _check_remaining_sql(next_char.value): raise Warning, "One and only one statement required" + # sql_char should remain alive until here self._build_row_cast_map() 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/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py --- a/pypy/jit/backend/x86/assembler.py +++ b/pypy/jit/backend/x86/assembler.py @@ -92,6 +92,7 @@ self.datablockwrapper = None self.stack_check_slowpath = 0 self.propagate_exception_path = 0 + self.gcrootmap_retaddr_forced = 0 self.teardown() def leave_jitted_hook(self): @@ -357,6 +358,7 @@ self.stack_check_slowpath = rawstart @staticmethod + @rgc.no_collect def _release_gil_asmgcc(css): # similar to trackgcroot.py:pypy_asm_stackwalk, first part from pypy.rpython.memory.gctransform import asmgcroot @@ -372,6 +374,7 @@ before() @staticmethod + @rgc.no_collect def _reacquire_gil_asmgcc(css): # first reacquire the GIL after = rffi.aroundstate.after @@ -386,12 +389,14 @@ next.prev = prev @staticmethod + @rgc.no_collect def _release_gil_shadowstack(): before = rffi.aroundstate.before if before: before() @staticmethod + @rgc.no_collect def _reacquire_gil_shadowstack(): after = rffi.aroundstate.after if after: @@ -2218,13 +2223,27 @@ css = get_ebp_ofs(pos + use_words - 1) self._regalloc.close_stack_struct = css # The location where the future CALL will put its return address - # will be [ESP-WORD], so save that as the next frame's top address - self.mc.LEA_rs(eax.value, -WORD) # LEA EAX, [ESP-4] + # will be [ESP-WORD]. But we can't use that as the next frame's + # top address! As the code after releasegil() runs without the + # GIL, it might not be set yet by the time we need it (very + # unlikely), or it might be overwritten by the following call + # to reaquiregil() (much more likely). So we hack even more + # and use a dummy location containing a dummy value (a pointer + # to itself) which we pretend is the return address :-/ :-/ :-/ + # It prevents us to store any %esp-based stack locations but we + # don't so far. + adr = self.datablockwrapper.malloc_aligned(WORD, WORD) + rffi.cast(rffi.CArrayPtr(lltype.Signed), adr)[0] = adr + self.gcrootmap_retaddr_forced = adr frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) - self.mc.MOV_br(frame_ptr, eax.value) # MOV [css.frame], EAX + if rx86.fits_in_32bits(adr): + self.mc.MOV_bi(frame_ptr, adr) # MOV [css.frame], adr + else: + self.mc.MOV_ri(eax.value, adr) # MOV EAX, adr + self.mc.MOV_br(frame_ptr, eax.value) # MOV [css.frame], EAX # Save ebp index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) - self.mc.MOV_br(index_of_ebp, ebp.value) # MOV [css.ebp], EBP + self.mc.MOV_br(index_of_ebp, ebp.value) # MOV [css.ebp], EBP # Call the closestack() function (also releasing the GIL) if IS_X86_32: reg = eax @@ -2252,6 +2271,9 @@ if gcrootmap.is_shadow_stack: args = [] else: + assert self.gcrootmap_retaddr_forced == -1, ( + "missing mark_gc_roots() in CALL_RELEASE_GIL") + self.gcrootmap_retaddr_forced = 0 css = self._regalloc.close_stack_struct assert css != 0 if IS_X86_32: @@ -2502,7 +2524,13 @@ if gcrootmap.is_shadow_stack: gcrootmap.write_callshape(mark, force_index) else: - self.mc.insert_gcroot_marker(mark) + if self.gcrootmap_retaddr_forced == 0: + self.mc.insert_gcroot_marker(mark) # common case + else: + assert self.gcrootmap_retaddr_forced != -1, ( + "two mark_gc_roots() in a CALL_RELEASE_GIL") + gcrootmap.put(self.gcrootmap_retaddr_forced, mark) + self.gcrootmap_retaddr_forced = -1 def target_arglocs(self, loop_token): return loop_token._x86_arglocs diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py --- a/pypy/jit/codewriter/jtransform.py +++ b/pypy/jit/codewriter/jtransform.py @@ -198,7 +198,6 @@ self.vable_array_vars[op.result]= self.vable_array_vars[op.args[0]] rewrite_op_cast_pointer = rewrite_op_same_as - rewrite_op_cast_opaque_ptr = rewrite_op_same_as # rlib.rerased def rewrite_op_cast_bool_to_int(self, op): pass def rewrite_op_cast_bool_to_uint(self, op): pass def rewrite_op_cast_char_to_int(self, op): pass diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py --- a/pypy/jit/metainterp/blackhole.py +++ b/pypy/jit/metainterp/blackhole.py @@ -500,6 +500,9 @@ @arguments("r", returns="i") def bhimpl_ptr_nonzero(a): return bool(a) + @arguments("r", returns="r") + def bhimpl_cast_opaque_ptr(a): + return a @arguments("i", returns="i") def bhimpl_int_copy(a): diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -264,6 +264,7 @@ self.posponedop = None self.exception_might_have_happened = False self.quasi_immutable_deps = None + self.opaque_pointers = {} self.newoperations = [] if loop is not None: self.call_pure_results = loop.call_pure_results @@ -555,6 +556,11 @@ def optimize_DEBUG_MERGE_POINT(self, op): self.emit_operation(op) + def optimize_CAST_OPAQUE_PTR(self, op): + value = self.getvalue(op.getarg(0)) + self.opaque_pointers[value] = True + self.make_equal_to(op.result, value) + dispatch_opt = make_dispatcher_method(Optimizer, 'optimize_', default=Optimizer.optimize_default) diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py --- a/pypy/jit/metainterp/optimizeopt/simplify.py +++ b/pypy/jit/metainterp/optimizeopt/simplify.py @@ -25,6 +25,8 @@ # but it's a bit hard to implement robustly if heap.py is also run pass + optimize_CAST_OPAQUE_PTR = optimize_VIRTUAL_REF + dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_', default=OptSimplify.emit_operation) diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py b/pypy/jit/metainterp/optimizeopt/unroll.py --- a/pypy/jit/metainterp/optimizeopt/unroll.py +++ b/pypy/jit/metainterp/optimizeopt/unroll.py @@ -513,6 +513,9 @@ def safe_to_move(self, op): opnum = op.getopnum() descr = op.getdescr() + for box in op.getarglist(): + if self.optimizer.getvalue(box) in self.optimizer.opaque_pointers: + return False if op.is_always_pure() or op.is_foldable_guard(): return True elif opnum == rop.JUMP: 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 @@ -233,6 +233,10 @@ return self.execute(rop.PTR_EQ, box, history.CONST_NULL) @arguments("box") + def opimpl_cast_opaque_ptr(self, box): + return self.execute(rop.CAST_OPAQUE_PTR, box) + + @arguments("box") def _opimpl_any_return(self, box): self.metainterp.finishframe(box) diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py --- a/pypy/jit/metainterp/resoperation.py +++ b/pypy/jit/metainterp/resoperation.py @@ -437,6 +437,7 @@ # 'PTR_EQ/2b', 'PTR_NE/2b', + 'CAST_OPAQUE_PTR/1b', # 'ARRAYLEN_GC/1d', 'STRLEN/1', 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/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py --- a/pypy/module/posix/interp_posix.py +++ b/pypy/module/posix/interp_posix.py @@ -473,7 +473,7 @@ FIELDS = PORTABLE_STAT_FIELDS else: FIELDS = STAT_FIELDS # also when not translating at all - return space.newlist([space.wrap(name) for name, _ in FIELDS]) + return space.newlist([space.wrap(name) for _, (name, _) in FIELDS]) class State: 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/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/rffi.py b/pypy/rpython/lltypesystem/rffi.py --- a/pypy/rpython/lltypesystem/rffi.py +++ b/pypy/rpython/lltypesystem/rffi.py @@ -749,21 +749,18 @@ return hlstrtype(gc_buf) new_buf = lltype.malloc(STRTYPE, needed_size) - try: - str_chars_offset = (offsetof(STRTYPE, 'chars') + \ - itemoffsetof(STRTYPE.chars, 0)) - if gc_buf: - src = cast_ptr_to_adr(gc_buf) + str_chars_offset - else: - src = cast_ptr_to_adr(raw_buf) + itemoffsetof(TYPEP.TO, 0) - dest = cast_ptr_to_adr(new_buf) + str_chars_offset - ## FIXME: This is bad, because dest could potentially move - ## if there are threads involved. - raw_memcopy(src, dest, - llmemory.sizeof(ll_char_type) * needed_size) - return hlstrtype(new_buf) - finally: - keepalive_until_here(new_buf) + str_chars_offset = (offsetof(STRTYPE, 'chars') + \ + itemoffsetof(STRTYPE.chars, 0)) + if gc_buf: + src = cast_ptr_to_adr(gc_buf) + str_chars_offset + else: + src = cast_ptr_to_adr(raw_buf) + itemoffsetof(TYPEP.TO, 0) + dest = cast_ptr_to_adr(new_buf) + str_chars_offset + raw_memcopy(src, dest, + llmemory.sizeof(ll_char_type) * needed_size) + keepalive_until_here(gc_buf) + keepalive_until_here(new_buf) + return hlstrtype(new_buf) # (char*, str) -> None def keep_buffer_alive_until_here(raw_buf, gc_buf): @@ -1068,4 +1065,4 @@ [VOIDP, VOIDP, SIZE_T], lltype.Void, threadsafe=False -) \ No newline at end of file +) diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py --- a/pypy/rpython/lltypesystem/rstr.py +++ b/pypy/rpython/lltypesystem/rstr.py @@ -3,6 +3,7 @@ from pypy.rpython.error import TyperError from pypy.rlib.objectmodel import malloc_zero_filled, we_are_translated from pypy.rlib.objectmodel import _hash_string, enforceargs +from pypy.rlib.objectmodel import keepalive_until_here from pypy.rlib.debug import ll_assert from pypy.rlib.jit import elidable, we_are_jitted, dont_look_inside from pypy.rlib.rarithmetic import ovfcheck @@ -67,6 +68,8 @@ src = llmemory.cast_ptr_to_adr(src) + _str_ofs(srcstart) dst = llmemory.cast_ptr_to_adr(dst) + _str_ofs(dststart) llmemory.raw_memcopy(src, dst, llmemory.sizeof(CHAR_TP) * length) + keepalive_until_here(src) + keepalive_until_here(dst) copy_string_contents._always_inline_ = True #copy_string_contents.oopspec = ( # '%s.copy_contents(src, dst, srcstart, dststart, length)' % name) 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/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/test/elf64/track_zero_4.s b/pypy/translator/c/gcc/test/elf64/track_zero_4.s new file mode 100644 --- /dev/null +++ b/pypy/translator/c/gcc/test/elf64/track_zero_4.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 + movq %r12, %rbx + je .L1 + movq (%rax), %rbx +.L1: + /* GCROOT %rbx */ + popq %r12 + 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 @@ -163,6 +163,9 @@ # Add the instruction to the list, and link it to the previous one. previnsn = self.insns[-1] self.insns.append(insn) + if (isinstance(insn, (InsnSetLocal, InsnCopyLocal)) and + insn.target == self.tested_for_zero): + self.tested_for_zero = None try: lst = insn.previous_insns @@ -173,6 +176,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 +190,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 +234,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 +488,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 +721,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 +744,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 +777,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 +944,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 +1003,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