[pypy-commit] pypy ppc-jit-backend: (edelsohn, bivab): import and adapt gc tests from the x86 backend

bivab noreply at buildbot.pypy.org
Fri Jul 13 15:47:53 CEST 2012


Author: bivab
Branch: ppc-jit-backend
Changeset: r56066:33f2077efd93
Date: 2012-07-13 06:35 -0700
http://bitbucket.org/pypy/pypy/changeset/33f2077efd93/

Log:	(edelsohn, bivab): import and adapt gc tests from the x86 backend

diff --git a/pypy/jit/backend/ppc/test/test_gc_integration.py b/pypy/jit/backend/ppc/test/test_gc_integration.py
--- a/pypy/jit/backend/ppc/test/test_gc_integration.py
+++ b/pypy/jit/backend/ppc/test/test_gc_integration.py
@@ -11,24 +11,24 @@
 from pypy.jit.backend.llsupport.descr import GcCache, FieldDescr, FLAG_SIGNED
 from pypy.jit.backend.llsupport.gc import GcLLDescription
 from pypy.jit.backend.detect_cpu import getcpuclass
-from pypy.jit.backend.x86.regalloc import RegAlloc
-from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE
+from pypy.jit.backend.ppc.regalloc import Regalloc
+from pypy.jit.backend.ppc.arch import WORD
 from pypy.jit.tool.oparser import parse
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rpython.lltypesystem import rclass, rstr
 from pypy.jit.backend.llsupport.gc import GcLLDescr_framework
 
-from pypy.jit.backend.x86.test.test_regalloc import MockAssembler
-from pypy.jit.backend.x86.test.test_regalloc import BaseTestRegalloc
-from pypy.jit.backend.x86.regalloc import X86RegisterManager, X86FrameManager,\
-     X86XMMRegisterManager
+from pypy.jit.backend.arm.test.test_regalloc import MockAssembler
+from pypy.jit.backend.ppc.test.test_regalloc import BaseTestRegalloc
+from pypy.jit.backend.ppc.regalloc import PPCRegisterManager, PPCFrameManager,\
+     FPRegisterManager
 
 CPU = getcpuclass()
 
 class MockGcRootMap(object):
     is_shadow_stack = False
-    def get_basic_shape(self, is_64_bit):
+    def get_basic_shape(self):
         return ['shape']
     def add_frame_offset(self, shape, offset):
         shape.append(offset)
@@ -52,41 +52,6 @@
     _record_constptrs = GcLLDescr_framework._record_constptrs.im_func
     rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func
 
-class TestRegallocDirectGcIntegration(object):
-
-    def test_mark_gc_roots(self):
-        cpu = CPU(None, None)
-        cpu.setup_once()
-        regalloc = RegAlloc(MockAssembler(cpu, MockGcDescr(False)))
-        regalloc.assembler.datablockwrapper = 'fakedatablockwrapper'
-        boxes = [BoxPtr() for i in range(len(X86RegisterManager.all_regs))]
-        longevity = {}
-        for box in boxes:
-            longevity[box] = (0, 1)
-        regalloc.fm = X86FrameManager()
-        regalloc.rm = X86RegisterManager(longevity, regalloc.fm,
-                                         assembler=regalloc.assembler)
-        regalloc.xrm = X86XMMRegisterManager(longevity, regalloc.fm,
-                                             assembler=regalloc.assembler)
-        cpu = regalloc.assembler.cpu
-        for box in boxes:
-            regalloc.rm.try_allocate_reg(box)
-        TP = lltype.FuncType([], lltype.Signed)
-        calldescr = cpu.calldescrof(TP, TP.ARGS, TP.RESULT,
-                                    EffectInfo.MOST_GENERAL)
-        regalloc.rm._check_invariants()
-        box = boxes[0]
-        regalloc.position = 0
-        regalloc.consider_call(ResOperation(rop.CALL, [box], BoxInt(),
-                                            calldescr))
-        assert len(regalloc.assembler.movs) == 3
-        #
-        mark = regalloc.get_mark_gc_roots(cpu.gc_ll_descr.gcrootmap)
-        assert mark[0] == 'compressed'
-        base = -WORD * FRAME_FIXED_SIZE
-        expected = ['ebx', 'esi', 'edi', base, base-WORD, base-WORD*2]
-        assert dict.fromkeys(mark[1:]) == dict.fromkeys(expected)
-
 class TestRegallocGcIntegration(BaseTestRegalloc):
     
     cpu = CPU(None, None)
@@ -184,6 +149,8 @@
         self.addrs[1] = self.addrs[0] + 64
         self.calls = []
         def malloc_slowpath(size):
+            if self.gcrootmap is not None:   # hook
+                self.gcrootmap.hook_malloc_slowpath()
             self.calls.append(size)
             # reset the nursery
             nadr = rffi.cast(lltype.Signed, self.nursery)
@@ -257,3 +224,180 @@
         assert gc_ll_descr.addrs[0] == nurs_adr + 24
         # this should call slow path once
         assert gc_ll_descr.calls == [24]
+
+class MockShadowStackRootMap(MockGcRootMap):
+    is_shadow_stack = True
+    MARKER_FRAME = 88       # this marker follows the frame addr
+    S1 = lltype.GcStruct('S1')
+
+    def __init__(self):
+        self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 20,
+                                   flavor='raw')
+        # root_stack_top
+        self.addrs[0] = rffi.cast(lltype.Signed, self.addrs) + 3*WORD
+        # random stuff
+        self.addrs[1] = 123456
+        self.addrs[2] = 654321
+        self.check_initial_and_final_state()
+        self.callshapes = {}
+        self.should_see = []
+
+    def check_initial_and_final_state(self):
+        assert self.addrs[0] == rffi.cast(lltype.Signed, self.addrs) + 3*WORD
+        assert self.addrs[1] == 123456
+        assert self.addrs[2] == 654321
+
+    def get_root_stack_top_addr(self):
+        return rffi.cast(lltype.Signed, self.addrs)
+
+    def compress_callshape(self, shape, datablockwrapper):
+        assert shape[0] == 'shape'
+        return ['compressed'] + shape[1:]
+
+    def write_callshape(self, mark, force_index):
+        assert mark[0] == 'compressed'
+        assert force_index not in self.callshapes
+        assert force_index == 42 + len(self.callshapes)
+        self.callshapes[force_index] = mark
+
+    def hook_malloc_slowpath(self):
+        num_entries = self.addrs[0] - rffi.cast(lltype.Signed, self.addrs)
+        assert num_entries == 5*WORD    # 3 initially, plus 2 by the asm frame
+        assert self.addrs[1] == 123456  # unchanged
+        assert self.addrs[2] == 654321  # unchanged
+        frame_addr = self.addrs[3]                   # pushed by the asm frame
+        assert self.addrs[4] == self.MARKER_FRAME    # pushed by the asm frame
+        #
+        from pypy.jit.backend.ppc.arch import FORCE_INDEX_OFS
+        addr = rffi.cast(rffi.CArrayPtr(lltype.Signed),
+                         frame_addr + FORCE_INDEX_OFS)
+        force_index = addr[0]
+        assert force_index == 43    # in this test: the 2nd call_malloc_nursery
+        #
+        # The callshapes[43] saved above should list addresses both in the
+        # COPY_AREA and in the "normal" stack, where all the 16 values p1-p16
+        # of test_save_regs_at_correct_place should have been stored.  Here
+        # we replace them with new addresses, to emulate a moving GC.
+        shape = self.callshapes[force_index]
+        assert len(shape[1:]) == len(self.should_see)
+        new_objects = [None] * len(self.should_see)
+        for ofs in shape[1:]:
+            assert isinstance(ofs, int)    # not a register at all here
+            addr = rffi.cast(rffi.CArrayPtr(lltype.Signed), frame_addr + ofs)
+            contains = addr[0]
+            for j in range(len(self.should_see)):
+                obj = self.should_see[j]
+                if contains == rffi.cast(lltype.Signed, obj):
+                    assert new_objects[j] is None   # duplicate?
+                    break
+            else:
+                assert 0   # the value read from the stack looks random?
+            new_objects[j] = lltype.malloc(self.S1)
+            addr[0] = rffi.cast(lltype.Signed, new_objects[j])
+        self.should_see[:] = new_objects
+
+
+class TestMallocShadowStack(BaseTestRegalloc):
+
+    def setup_method(self, method):
+        cpu = CPU(None, None)
+        cpu.gc_ll_descr = GCDescrFastpathMalloc()
+        cpu.gc_ll_descr.gcrootmap = MockShadowStackRootMap()
+        cpu.setup_once()
+        for i in range(42):
+            cpu.reserve_some_free_fail_descr_number()
+        self.cpu = cpu
+
+    def test_save_regs_at_correct_place(self):
+        cpu = self.cpu
+        gc_ll_descr = cpu.gc_ll_descr
+        S1 = gc_ll_descr.gcrootmap.S1
+        S2 = lltype.GcStruct('S2', ('s0', lltype.Ptr(S1)),
+                                   ('s1', lltype.Ptr(S1)),
+                                   ('s2', lltype.Ptr(S1)),
+                                   ('s3', lltype.Ptr(S1)),
+                                   ('s4', lltype.Ptr(S1)),
+                                   ('s5', lltype.Ptr(S1)),
+                                   ('s6', lltype.Ptr(S1)),
+                                   ('s7', lltype.Ptr(S1)),
+                                   ('s8', lltype.Ptr(S1)),
+                                   ('s9', lltype.Ptr(S1)),
+                                   ('s10', lltype.Ptr(S1)),
+                                   ('s11', lltype.Ptr(S1)),
+                                   ('s12', lltype.Ptr(S1)),
+                                   ('s13', lltype.Ptr(S1)),
+                                   ('s14', lltype.Ptr(S1)),
+                                   ('s15', lltype.Ptr(S1)),
+                                   ('s16', lltype.Ptr(S1)),
+                                   ('s17', lltype.Ptr(S1)),
+                                   ('s18', lltype.Ptr(S1)),
+                                   ('s19', lltype.Ptr(S1)),
+                                   ('s20', lltype.Ptr(S1)),
+                                   ('s21', lltype.Ptr(S1)),
+                                   ('s22', lltype.Ptr(S1)),
+                                   ('s23', lltype.Ptr(S1)),
+                                   ('s24', lltype.Ptr(S1)),
+                                   ('s25', lltype.Ptr(S1)),
+                                   ('s26', lltype.Ptr(S1)),
+                                   ('s27', lltype.Ptr(S1)))
+        self.namespace = self.namespace.copy()
+        for i in range(28):
+            self.namespace['ds%i' % i] = cpu.fielddescrof(S2, 's%d' % i)
+        ops = '''
+        [p0]
+        p1 = getfield_gc(p0, descr=ds0)
+        p2 = getfield_gc(p0, descr=ds1)
+        p3 = getfield_gc(p0, descr=ds2)
+        p4 = getfield_gc(p0, descr=ds3)
+        p5 = getfield_gc(p0, descr=ds4)
+        p6 = getfield_gc(p0, descr=ds5)
+        p7 = getfield_gc(p0, descr=ds6)
+        p8 = getfield_gc(p0, descr=ds7)
+        p9 = getfield_gc(p0, descr=ds8)
+        p10 = getfield_gc(p0, descr=ds9)
+        p11 = getfield_gc(p0, descr=ds10)
+        p12 = getfield_gc(p0, descr=ds11)
+        p13 = getfield_gc(p0, descr=ds12)
+        p14 = getfield_gc(p0, descr=ds13)
+        p15 = getfield_gc(p0, descr=ds14)
+        p16 = getfield_gc(p0, descr=ds15)
+        p17 = getfield_gc(p0, descr=ds16)
+        p18 = getfield_gc(p0, descr=ds17)
+        p19 = getfield_gc(p0, descr=ds18)
+        p20 = getfield_gc(p0, descr=ds19)
+        p21 = getfield_gc(p0, descr=ds20)
+        p22 = getfield_gc(p0, descr=ds21)
+        p23 = getfield_gc(p0, descr=ds22)
+        p24 = getfield_gc(p0, descr=ds23)
+        p25 = getfield_gc(p0, descr=ds24)
+        p26 = getfield_gc(p0, descr=ds25)
+        p27 = getfield_gc(p0, descr=ds26)
+        p28 = getfield_gc(p0, descr=ds27)
+        #
+        # now all registers are in use
+        p29 = call_malloc_nursery(40)
+        p30 = call_malloc_nursery(40)     # overflow
+        #
+        finish(p1, p2, p3, p4, p5, p6, p7, p8,         \
+               p9, p10, p11, p12, p13, p14, p15, p16,  \
+               p17, p18, p19, p20, p21, p22, p23, p24, \
+               p25, p26, p27, p28)
+        '''
+        s2 = lltype.malloc(S2)
+        for i in range(28):
+            s1 = lltype.malloc(S1)
+            setattr(s2, 's%d' % i, s1)
+            gc_ll_descr.gcrootmap.should_see.append(s1)
+        s2ref = lltype.cast_opaque_ptr(llmemory.GCREF, s2)
+        #
+        self.interpret(ops, [s2ref])
+        gc_ll_descr.check_nothing_in_nursery()
+        assert gc_ll_descr.calls == [40]
+        gc_ll_descr.gcrootmap.check_initial_and_final_state()
+        # check the returned pointers
+        for i in range(28):
+            s1ref = self.cpu.get_latest_value_ref(i)
+            s1 = lltype.cast_opaque_ptr(lltype.Ptr(S1), s1ref)
+            for j in range(28):
+                assert s1 != getattr(s2, 's%d' % j)
+            assert s1 == gc_ll_descr.gcrootmap.should_see[i]
diff --git a/pypy/jit/backend/ppc/test/test_regalloc.py b/pypy/jit/backend/ppc/test/test_regalloc.py
--- a/pypy/jit/backend/ppc/test/test_regalloc.py
+++ b/pypy/jit/backend/ppc/test/test_regalloc.py
@@ -1,3 +1,6 @@
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import rclass, rstr
+from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib.objectmodel import instantiate
 from pypy.jit.backend.ppc.locations import (imm, RegisterLocation,
                                             ImmLocation, StackLocation)
@@ -6,6 +9,13 @@
 from pypy.jit.backend.ppc.ppc_assembler import AssemblerPPC
 from pypy.jit.backend.ppc.arch import WORD
 from pypy.jit.backend.ppc.locations import get_spp_offset
+from pypy.jit.backend.detect_cpu import getcpuclass
+from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.codewriter import longlong
+from pypy.jit.metainterp.history import BasicFailDescr, \
+                                        JitCellToken, \
+                                        TargetToken
+from pypy.jit.tool.oparser import parse
 
 class MockBuilder(object):
     
@@ -141,3 +151,134 @@
 
 def stack(i):
     return StackLocation(i)
+
+CPU = getcpuclass()
+class BaseTestRegalloc(object):
+    cpu = CPU(None, None)
+    cpu.setup_once()
+
+    def raising_func(i):
+        if i:
+            raise LLException(zero_division_error,
+                              zero_division_value)
+    FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void))
+    raising_fptr = llhelper(FPTR, raising_func)
+
+    def f(a):
+        return 23
+
+    FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed))
+    f_fptr = llhelper(FPTR, f)
+    f_calldescr = cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT,
+                                                    EffectInfo.MOST_GENERAL)
+
+    zero_division_tp, zero_division_value = cpu.get_zero_division_error()
+    zd_addr = cpu.cast_int_to_adr(zero_division_tp)
+    zero_division_error = llmemory.cast_adr_to_ptr(zd_addr,
+                                            lltype.Ptr(rclass.OBJECT_VTABLE))
+    raising_calldescr = cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT,
+                                                    EffectInfo.MOST_GENERAL)
+
+    targettoken = TargetToken()
+    targettoken2 = TargetToken()
+    fdescr1 = BasicFailDescr(1)
+    fdescr2 = BasicFailDescr(2)
+    fdescr3 = BasicFailDescr(3)
+
+    def setup_method(self, meth):
+        self.targettoken._arm_loop_code = 0
+        self.targettoken2._arm_loop_code = 0
+
+    def f1(x):
+        return x + 1
+
+    def f2(x, y):
+        return x * y
+
+    def f10(*args):
+        assert len(args) == 10
+        return sum(args)
+
+    F1PTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed))
+    F2PTR = lltype.Ptr(lltype.FuncType([lltype.Signed] * 2, lltype.Signed))
+    F10PTR = lltype.Ptr(lltype.FuncType([lltype.Signed] * 10, lltype.Signed))
+    f1ptr = llhelper(F1PTR, f1)
+    f2ptr = llhelper(F2PTR, f2)
+    f10ptr = llhelper(F10PTR, f10)
+
+    f1_calldescr = cpu.calldescrof(F1PTR.TO, F1PTR.TO.ARGS, F1PTR.TO.RESULT,
+                                                    EffectInfo.MOST_GENERAL)
+    f2_calldescr = cpu.calldescrof(F2PTR.TO, F2PTR.TO.ARGS, F2PTR.TO.RESULT,
+                                                    EffectInfo.MOST_GENERAL)
+    f10_calldescr = cpu.calldescrof(F10PTR.TO, F10PTR.TO.ARGS,
+                                    F10PTR.TO.RESULT, EffectInfo.MOST_GENERAL)
+
+    namespace = locals().copy()
+    type_system = 'lltype'
+
+    def parse(self, s, boxkinds=None):
+        return parse(s, self.cpu, self.namespace,
+                     type_system=self.type_system,
+                     boxkinds=boxkinds)
+
+    def interpret(self, ops, args, run=True):
+        loop = self.parse(ops)
+        looptoken = JitCellToken()
+        self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+        arguments = []
+        for arg in args:
+            if isinstance(arg, int):
+                arguments.append(arg)
+            elif isinstance(arg, float):
+                arg = longlong.getfloatstorage(arg)
+                arguments.append(arg)
+            else:
+                assert isinstance(lltype.typeOf(arg), lltype.Ptr)
+                llgcref = lltype.cast_opaque_ptr(llmemory.GCREF, arg)
+                arguments.append(llgcref)
+        loop._jitcelltoken = looptoken
+        if run:
+            self.cpu.execute_token(looptoken, *arguments)
+        return loop
+
+    def prepare_loop(self, ops):
+        loop = self.parse(ops)
+        regalloc = Regalloc(assembler=self.cpu.assembler,
+        frame_manager=ARMFrameManager())
+        regalloc.prepare_loop(loop.inputargs, loop.operations)
+        return regalloc
+
+    def getint(self, index):
+        return self.cpu.get_latest_value_int(index)
+
+    def getfloat(self, index):
+        v = self.cpu.get_latest_value_float(index)
+        return longlong.getrealfloat(v)
+
+    def getints(self, end):
+        return [self.cpu.get_latest_value_int(index) for
+                index in range(0, end)]
+
+    def getfloats(self, end):
+        return [self.getfloat(index) for
+                index in range(0, end)]
+
+    def getptr(self, index, T):
+        gcref = self.cpu.get_latest_value_ref(index)
+        return lltype.cast_opaque_ptr(T, gcref)
+
+    def attach_bridge(self, ops, loop, guard_op_index, **kwds):
+        guard_op = loop.operations[guard_op_index]
+        assert guard_op.is_guard()
+        bridge = self.parse(ops, **kwds)
+        assert ([box.type for box in bridge.inputargs] ==
+                [box.type for box in guard_op.getfailargs()])
+        faildescr = guard_op.getdescr()
+        self.cpu.compile_bridge(faildescr, bridge.inputargs, bridge.operations,
+                                loop._jitcelltoken)
+        return bridge
+
+    def run(self, loop, *args):
+        return self.cpu.execute_token(loop._jitcelltoken, *args)
+
+


More information about the pypy-commit mailing list