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

Reply via email to