[pypy-commit] pypy release-1.6.x: merge heads
arigo
noreply at buildbot.pypy.org
Sun Aug 14 19:29:55 CEST 2011
Author: Armin Rigo <arigo at 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,
More information about the pypy-commit
mailing list