[pypy-svn] r69471 - in pypy/branch/shorter-guard-path/pypy/jit/backend/x86: . test

arigo at codespeak.net arigo at codespeak.net
Fri Nov 20 16:25:34 CET 2009


Author: arigo
Date: Fri Nov 20 16:25:34 2009
New Revision: 69471

Modified:
   pypy/branch/shorter-guard-path/pypy/jit/backend/x86/assembler.py
   pypy/branch/shorter-guard-path/pypy/jit/backend/x86/test/test_assembler.py
Log:
Current status: wrote a test, painfully.


Modified: pypy/branch/shorter-guard-path/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/shorter-guard-path/pypy/jit/backend/x86/assembler.py	(original)
+++ pypy/branch/shorter-guard-path/pypy/jit/backend/x86/assembler.py	Fri Nov 20 16:25:34 2009
@@ -86,7 +86,7 @@
         self.fail_boxes_int = NonmovableGrowableArraySigned()
         self.fail_boxes_ptr = NonmovableGrowableArrayGCREF()
         self.fail_boxes_float = NonmovableGrowableArrayFloat()
-        self.failure_recovery_code = [0, 0]
+        self.setup_failure_recovery()
 
     def leave_jitted_hook(self):
         # XXX BIG FAT WARNING XXX
@@ -812,149 +812,58 @@
             mc.writechr(n)
         mc.writechr(self.DESCR_STOP)
 
+    def setup_failure_recovery(self):
+
+        def failure_recovery_func(registers):
+            pass  #...
+
+        self.failure_recovery_func = failure_recovery_func
+        self.failure_recovery_code = [0, 0]
+
+    _FAILURE_RECOVERY_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP],
+                                                        lltype.Signed))
+
     def _build_failure_recovery(self, exc):
-        """
-           PUSH edi
-           PUSH esi
-           PUSH ebp
-           PUSH 0      # for ESP, not used
-           PUSH ebx
-           PUSH edx
-           PUSH ecx
-           PUSH eax
-           MOV esi, [esp+32]
-           CLD
-           MOV edi, -1
-
-        loop:
-           INC edi
-           LODSB
-           CMP al, 4*8
-           MOVZX edx, al
-           JB decode_register
-           JL decode_multibyte
-
-        decode_edx:
-           TEST edx, 3
-           JZ decode_ptr
-           TEST edx, 2
-           JNZ decode_float
-
-        decode_int:
-           # (edx & 3) == 1
-           NEG edx
-           MOV eax, [ebp + edx + 1 - 16]
-
-        got_value_int:
-           MOV [fail_boxes_int + 4*edi], eax
-           JMP loop
-
-        decode_ptr:
-           # (edx & 3) == 0
-           NEG edx
-           MOV eax, [ebp + edx - 16]
-
-        got_value_ptr:
-           MOV [fail_boxes_ptr + 4*edi], eax
-           JMP loop
-
-        decode_float:
-           # (edx & 3) == 2
-           NEG edx
-           MOV eax, [ebp + edx - 2 - 16]
-           MOV [fail_boxes_float + 8*edi], eax
-           MOV eax, [ebp + edx + 2 - 16]
-           MOV [fail_boxes_float + 8*edi + 4], eax
-           JMP loop
-
-        decode_multibyte:
-           MOV cl, 7
-           AND edx, 0x7F
-           JMP innerloop
-
-           innerloop_morebytes:
-              AND eax, 0x7F
-              SHL eax, cl
-              OR edx, eax
-              ADD cl, 7
-           innerloop:
-              LODSB
-              CMP al, 0
-              MOVZX eax, al
-              JL innerloop_morebytes
-
-           SHL eax, cl
-           OR edx, eax
-           JMP decode_edx
-
-        decode_register:
-           TEST al, 2
-           JNZ decode_register_float
-           CMP al, DESCR_STOP
-           JE stop
-           AND edx, 0x3C
-           TEST al, 1
-           MOV eax, [esp+edx]
-           JNZ got_value_int
-           MOV [fail_boxes_ptr + 4*edi], eax
-           JMP loop
-
-        decode_register_float:
-           CMP al, 0x10
-           JB case_0123
-           CMP al, 0x18
-           JB case_45
-           CMP al, 0x1C
-           JB case_6
-        case_7:
-           MOVSD [fail_boxes_float + 8*edi], xmm7
-           JMP loop
-        case_6:
-           MOVSD [fail_boxes_float + 8*edi], xmm6
-           JMP loop
-        case_45:
-           CMP al, 0x14
-           JB case_4
-        case_5:
-           MOVSD [fail_boxes_float + 8*edi], xmm5
-           JMP loop
-        case_4:
-           MOVSD [fail_boxes_float + 8*edi], xmm4
-           JMP loop
-        case_0123:
-           CMP al, 0x08
-           JB case_01
-           CMP al, 0x0C
-           JB case_2
-        case_3:
-           MOVSD [fail_boxes_float + 8*edi], xmm3
-           JMP loop
-        case_2:
-           MOVSD [fail_boxes_float + 8*edi], xmm2
-           JMP loop
-        case_01:
-           CMP al, 0x04
-           JB case_0
-        case_1:
-           MOVSD [fail_boxes_float + 8*edi], xmm1
-           JMP loop
-        case_0:
-           MOVSD [fail_boxes_float + 8*edi], xmm0
-           JMP loop
-
-        stop:
-           CALL on_leave_jitted
-           MOV eax, [esp+36]    # fail_index
-           LEA esp, [ebp-12]
-           POP edi
-           POP esi
-           POP ebx
-           POP ebp
-           RET
-        """
-        ...
-        ...
-        self.failure_recovery_code[exc] = code
+        failure_recovery_func = llhelper(self._FAILURE_RECOVERY_FUNC,
+                                         self.failure_recovery_func)
+        failure_recovery_func = rffi.cast(lltype.Signed,
+                                          failure_recovery_func)
+        mc = self.mc2._mc
+        # Assume that we are called at the beginning, when there is no risk
+        # that 'mc' runs out of space.  Checked by asserts in mc.write().
+        addr = mc.tell()
+        mc.PUSH(edi)
+        mc.PUSH(esi)
+        mc.PUSH(ebp)
+        mc.PUSH(esp)    # not really used, but needed to take up the space
+        mc.PUSH(ebx)
+        mc.PUSH(edx)
+        mc.PUSH(ecx)
+        mc.PUSH(eax)
+        mc.MOV(eax, esp)
+        mc.PUSH(eax)
+        mc.CALL(rel32(failure_recovery_func))
+
+        # we call a provided function that will
+        # - call our on_leave_jitted_hook which will mark
+        #   the fail_boxes_ptr array as pointing to young objects to
+        #   avoid unwarranted freeing
+        # - optionally save exception depending on the flag
+        addr = self.cpu.get_on_leave_jitted_int(save_exception=exc)
+        mc.PUSH(eax)
+        mc.CALL(rel32(addr))
+        mc.POP(eax)
+
+        # now we return from the complete frame, which starts from
+        # _assemble_bootstrap_code().  The LEA below throws away most
+        # of the frame, including all the PUSHes that we did just above.
+        mc.LEA(esp, addr_add(ebp, imm((-RET_BP + 2) * WORD)))
+        mc.POP(edi)
+        mc.POP(esi)
+        mc.POP(ebx)
+        mc.POP(ebp)
+        mc.RET()
+        self.failure_recovery_code[exc] = addr
 
     def generate_failure(self, mc, fail_index, locs, exc, locs_are_ref):
         for i in range(len(locs)):
@@ -994,7 +903,7 @@
 
         # don't break the following code sequence!
         mc = mc._mc
-        mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD))
+        mc.LEA(esp, addr_add(ebp, imm((-RET_BP + 2) * WORD)))
         mc.MOV(eax, imm(fail_index))
         mc.POP(edi)
         mc.POP(esi)

Modified: pypy/branch/shorter-guard-path/pypy/jit/backend/x86/test/test_assembler.py
==============================================================================
--- pypy/branch/shorter-guard-path/pypy/jit/backend/x86/test/test_assembler.py	(original)
+++ pypy/branch/shorter-guard-path/pypy/jit/backend/x86/test/test_assembler.py	Fri Nov 20 16:25:34 2009
@@ -2,6 +2,8 @@
 from pypy.jit.backend.x86.assembler import Assembler386
 from pypy.jit.backend.x86.regalloc import X86StackManager
 from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat
+from pypy.rlib.rarithmetic import intmask
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 
 
 class FakeCPU:
@@ -28,18 +30,126 @@
             esi,
             xmm2]
     assembler.write_failure_recovery_description(mc, failargs, locs)
-    nums = [0 + 4*(8+0),
-            1 + 4*(8+1),
-            2 + 4*(8+10),
-            0 + 4*(8+100),
-            1 + 4*(8+101),
-            2 + 4*(8+110),
-            0 + 4*ebx.op,
-            1 + 4*esi.op,
-            2 + 4*xmm2.op]
+    nums = [Assembler386.DESCR_INT   + 4*(8+0),
+            Assembler386.DESCR_REF   + 4*(8+1),
+            Assembler386.DESCR_FLOAT + 4*(8+10),
+            Assembler386.DESCR_INT   + 4*(8+100),
+            Assembler386.DESCR_REF   + 4*(8+101),
+            Assembler386.DESCR_FLOAT + 4*(8+110),
+            Assembler386.DESCR_INT   + 4*ebx.op,
+            Assembler386.DESCR_REF   + 4*esi.op,
+            Assembler386.DESCR_FLOAT + 4*xmm2.op]
     double_byte_nums = []
     for num in nums[3:6]:
         double_byte_nums.append((num & 0x7F) | 0x80)
         double_byte_nums.append(num >> 7)
     assert mc.content == (nums[:3] + double_byte_nums + nums[6:] +
                           [assembler.DESCR_STOP])
+
+def test_failure_recovery_func():
+    import random
+    S = lltype.GcStruct('S')
+
+    def get_random_int():
+        return random.randrange(-10000, 10000)
+
+    def get_random_ptr():
+        return lltype.cast_opaque_ptr(llmemory.GCREF, lltype.malloc(S))
+
+    def get_random_float():
+        return random.random() - 0.5
+
+    # memory locations: 30 integers, 30 pointers, 26 floats
+    # main registers: half of them as signed and the other half as ptrs
+    # xmm registers: all floats, from xmm0 to xmm7
+    locations = []
+    baseloc = 4
+    for i in range(30+30+26):
+        if baseloc < 128:
+            baseloc += random.randrange(2, 20)
+        else:
+            baseloc += random.randrange(2, 1000)
+        locations.append(baseloc)
+    random.shuffle(locations)
+    content = ([('int', locations.pop()) for _ in range(30)] +
+               [('ptr', locations.pop()) for _ in range(30)] +
+               [('float', locations.pop()) for _ in range(26)] +
+               [(['int', 'ptr'][random.randrange(0, 2)], reg)
+                         for reg in [eax, ecx, edx, ebx, esi, edi]] +
+               [('float', reg) for reg in [xmm0, xmm1, xmm2, xmm3,
+                                           xmm4, xmm5, xmm6, xmm7]])
+    assert len(content) == 100
+    random.shuffle(content)
+
+    # prepare the expected target arrays, the descr_bytecode,
+    # the 'registers' and the 'stack' arrays according to 'content'
+    registers = lltype.malloc(rffi.LONGP.TO, 9, flavor='raw')
+    xmmregisters = [0.0] * 8
+    stacklen = baseloc + 3
+    stack = lltype.malloc(rffi.LONGP.TO, stacklen, flavor='raw')
+    expected_ints = [0] * 100
+    expected_ptrs = [lltype.nullptr(llmemory.GCREF.TO)] * 100
+    expected_floats = [0.0] * 100
+
+    descr_bytecode = []
+    for i, (kind, loc) in enumerate(content):
+        if kind == 'float':
+            value = get_random_float()
+            expected_floats[i] = value
+            kind = Assembler386.DESCR_FLOAT
+            if isinstance(loc, REG):
+                xmmregisters[loc.op] = value
+            else:
+                tmp = lltype.malloc(rffi.LONGP.TO, 2, flavor='raw')
+                rffi.cast(rffi.DOUBLEP, tmp)[0] = value
+                stack[stacklen - loc] = tmp[1]
+                stack[stacklen - (loc+1)] = tmp[0]
+        else:
+            if kind == 'int':
+                value = get_random_int()
+                expected_ints[i] = value
+                kind = Assembler386.DESCR_INT
+            elif kind == 'ptr':
+                value = get_random_ptr()
+                expected_ptrs[i] = value
+                kind = Assembler386.DESCR_REF
+                value = rffi.cast(rffi.LONG, value)
+            else:
+                assert 0, kind
+            if isinstance(loc, REG):
+                registers[loc.op] = value
+            else:
+                stack[stacklen - loc] = value
+
+        if isinstance(loc, REG):
+            num = kind + 4*loc.op
+        else:
+            num = kind + 4*(8+loc)
+        while num >= 0x80:
+            descr_bytecode.append((num & 0x7F) | 0x80)
+            num >>= 7
+        descr_bytecode.append(num)
+
+    descr_bytecode.append(Assembler386.DESCR_STOP)
+    descr_bytecode.append(0xC3)   # fail_index = 0x1C3
+    descr_bytecode.append(0x01)
+    descr_bytecode.append(0x00)
+    descr_bytecode.append(0x00)
+    descr_bytecode.append(0xCC)   # end marker
+    descr_bytes = lltype.malloc(rffi.UCHARP.TO, len(descr_bytecode),
+                                flavor='raw')
+    for i in range(len(descr_bytecode)):
+        assert 0 <= descr_bytecode[i] <= 255
+        descr_bytes[i] = rffi.cast(rffi.UCHAR, descr_bytecode[i])
+    registers[8] = rffi.cast(rffi.LONG, descr_bytes)
+
+    # run!
+    assembler = Assembler386(FakeCPU())
+    res = assembler.failure_recovery_func(registers)
+    assert res == 0x1C3
+
+    # check the fail_boxes
+    for i in range(100):
+        assert assembler.fail_boxes_int.getitem(i) == expected_ints[i]
+        assert assembler.fail_boxes_ptr.getitem(i) == expected_ptrs[i]
+        assert assembler.fail_boxes_float.getitem(i) == expected_floats[i]



More information about the Pypy-commit mailing list