Commits

Armin Rigo committed 6fa38d8

Test and (90% of a) fix.

Comments (0)

Files changed (5)

pypy/translator/c/gcc/instruction.py

 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):
     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:
     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:

pypy/translator/c/gcc/test/elf64/track_zero.s

+	.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

pypy/translator/c/gcc/test/elf64/track_zero_2.s

+	.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

pypy/translator/c/gcc/test/elf64/track_zero_3.s

+	.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

pypy/translator/c/gcc/trackgcroot.py

 
     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:
             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:
                 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]
         '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
             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)
                 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
     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"
     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
 
     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):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.