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)
+
+
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit