[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