[pypy-commit] pypy ppc-jit-backend: (bivab, hager): insert stack check before building the PyPy frame
hager
noreply at buildbot.pypy.org
Thu Mar 22 15:42:32 CET 2012
Author: hager <sven.hager at uni-duesseldorf.de>
Branch: ppc-jit-backend
Changeset: r53898:398b83a81dbf
Date: 2012-03-22 07:41 -0700
http://bitbucket.org/pypy/pypy/changeset/398b83a81dbf/
Log: (bivab, hager): insert stack check before building the PyPy frame
diff --git a/pypy/jit/backend/ppc/ppc_assembler.py b/pypy/jit/backend/ppc/ppc_assembler.py
--- a/pypy/jit/backend/ppc/ppc_assembler.py
+++ b/pypy/jit/backend/ppc/ppc_assembler.py
@@ -92,6 +92,7 @@
self._regalloc = None
self.max_stack_params = 0
self.propagate_exception_path = 0
+ self.stack_check_slowpath = 0
self.setup_failure_recovery()
self._debug = False
self.loop_run_counters = []
@@ -377,6 +378,133 @@
self.write_64_bit_func_descr(rawstart, rawstart+3*WORD)
self.malloc_slowpath = rawstart
+ def _build_stack_check_slowpath(self):
+ _, _, slowpathaddr = self.cpu.insert_stack_check()
+ if slowpathaddr == 0 or self.cpu.propagate_exception_v < 0:
+ return # no stack check (for tests, or non-translated)
+ #
+ # make a "function" that is called immediately at the start of
+ # an assembler function. In particular, the stack looks like:
+ #
+ # | |
+ # | OLD BACKCHAIN |
+ # | |
+ # =============================== -
+ # | | | > MINI FRAME (BACHCHAIN SIZE * WORD)
+ # | BACKCHAIN | |
+ # | | |
+ # =============================== -
+ # | |
+ # | SAVED PARAM REGS |
+ # | |
+ # -------------------------------
+ # | |
+ # | BACKCHAIN |
+ # | |
+ # =============================== <- SP
+ #
+ mc = PPCBuilder()
+ # save argument registers and return address
+
+ # make small frame to store data (parameter regs + LR + SCRATCH) in
+ # there
+ SAVE_AREA = len(r.PARAM_REGS)
+ frame_size = (BACKCHAIN_SIZE + SAVE_AREA) * WORD
+
+ # align the SP
+ MINIFRAME_SIZE = BACKCHAIN_SIZE * WORD
+ while (frame_size + MINIFRAME_SIZE) % (4 * WORD) != 0:
+ frame_size += WORD
+
+ # write function descriptor
+ if IS_PPC_64:
+ for _ in range(6):
+ mc.write32(0)
+
+ # build frame
+ with scratch_reg(mc):
+ if IS_PPC_32:
+ mc.stwu(r.SP.value, r.SP.value, -frame_size)
+ mc.mflr(r.SCRATCH.value)
+ mc.stw(r.SCRATCH.value, r.SP.value, frame_size + WORD)
+ else:
+ mc.stdu(r.SP.value, r.SP.value, -frame_size)
+ mc.mflr(r.SCRATCH.value)
+ mc.std(r.SCRATCH.value, r.SP.value, frame_size + 2 * WORD)
+
+ # save parameter registers
+ for i, reg in enumerate(r.PARAM_REGS):
+ mc.store(reg.value, r.SP.value, (i + BACKCHAIN_SIZE) * WORD)
+
+ # use SP as single parameter for the call
+ mc.mr(r.r3.value, r.SP.value)
+
+ # stack still aligned
+ mc.call(slowpathaddr)
+
+ with scratch_reg(mc):
+ mc.load_imm(r.SCRATCH, self.cpu.pos_exception())
+ mc.loadx(r.SCRATCH.value, 0, r.SCRATCH.value)
+ # if this comparison is true, then everything is ok,
+ # else we have an exception
+ mc.cmp_op(0, r.SCRATCH.value, 0, imm=True)
+
+ jnz_location = mc.currpos()
+ mc.nop()
+
+ # restore parameter registers
+ for i, reg in enumerate(r.PARAM_REGS):
+ mc.load(reg.value, r.SP.value, (i + BACKCHAIN_SIZE) * WORD)
+
+ # restore LR
+ with scratch_reg(mc):
+ lr_offset = frame_size + WORD
+ if IS_PPC_64:
+ lr_offset += WORD
+
+ mc.load(r.SCRATCH.value, r.SP.value,
+ lr_offset)
+ mc.mtlr(r.SCRATCH.value)
+
+ # reset SP
+ mc.addi(r.SP.value, r.SP.value, frame_size)
+ mc.blr()
+
+ pmc = OverwritingBuilder(mc, jnz_location, 1)
+ pmc.bc(4, 2, mc.currpos() - jnz_location)
+ pmc.overwrite()
+
+ # call on_leave_jitted_save_exc()
+ addr = self.cpu.get_on_leave_jitted_int(save_exception=True)
+ mc.call(addr)
+ #
+ mc.load_imm(r.RES, self.cpu.propagate_exception_v)
+ #
+ # footer -- note the addi, which skips the return address of this
+ # function, and will instead return to the caller's caller. Note
+ # also that we completely ignore the saved arguments, because we
+ # are interrupting the function.
+
+ # restore link register out of preprevious frame
+ offset_LR = frame_size + BACKCHAIN_SIZE * WORD + WORD
+ if IS_PPC_64:
+ offset_LR += WORD
+
+ with scratch_reg(mc):
+ mc.load(r.SCRATCH.value, r.SP.value, offset_LR)
+ mc.mtlr(r.SCRATCH.value)
+
+ # remove this frame and the miniframe
+ both_framesizes = frame_size + BACKCHAIN_SIZE * WORD
+ mc.addi(r.SP.value, r.SP.value, both_framesizes)
+ mc.blr()
+
+ mc.prepare_insts_blocks()
+ rawstart = mc.materialize(self.cpu.asmmemmgr, [])
+ if IS_PPC_64:
+ self.write_64_bit_func_descr(rawstart, rawstart+3*WORD)
+ self.stack_check_slowpath = rawstart
+
def _build_propagate_exception_path(self):
if self.cpu.propagate_exception_v < 0:
return
@@ -463,9 +591,76 @@
mc.store(reg.value, r.SPP.value, i * WORD)
def gen_bootstrap_code(self, loophead, spilling_area):
+ self._insert_stack_check()
self._make_frame(spilling_area)
self.mc.b_offset(loophead)
+ def _insert_stack_check(self):
+ if self.stack_check_slowpath == 0:
+ pass # not translated
+ else:
+ # this is the size for the miniframe
+ frame_size = BACKCHAIN_SIZE * WORD
+
+ endaddr, lengthaddr, _ = self.cpu.insert_stack_check()
+
+ # save r16
+ self.mc.mtctr(r.r16.value)
+
+ with scratch_reg(self.mc):
+ self.mc.load_imm(r.SCRATCH, endaddr) # load SCRATCH, [start]
+ self.mc.loadx(r.SCRATCH.value, 0, r.SCRATCH.value)
+ self.mc.subf(r.SCRATCH.value, r.SP.value, r.SCRATCH.value)
+ self.mc.load_imm(r.r16, lengthaddr)
+ self.mc.load(r.r16.value, r.r16.value, 0)
+ self.mc.cmp_op(0, r.SCRATCH.value, r.r16.value, signed=False)
+
+ # restore r16
+ self.mc.mfctr(r.r16.value)
+
+ patch_loc = self.mc.currpos()
+ self.mc.nop()
+
+ # make minimal frame which contains the LR
+ #
+ # | OLD FRAME |
+ # ==============================
+ # | |
+ # | BACKCHAIN | > BACKCHAIN_SIZE * WORD
+ # | |
+ # ============================== <- SP
+
+ if IS_PPC_32:
+ self.mc.stwu(r.SP.value, r.SP.value, -frame_size)
+ self.mc.mflr(r.SCRATCH.value)
+ self.mc.stw(r.SCRATCH.value, r.SP.value, frame_size + WORD)
+ else:
+ self.mc.stdu(r.SP.value, r.SP.value, -frame_size)
+ self.mc.mflr(r.SCRATCH.value)
+ self.mc.std(r.SCRATCH.value, r.SP.value, frame_size + 2 * WORD)
+
+ # make check
+ self.mc.call(self.stack_check_slowpath)
+
+ # restore LR
+ with scratch_reg(self.mc):
+ lr_offset = frame_size + WORD
+ if IS_PPC_64:
+ lr_offset += WORD
+
+ self.mc.load(r.SCRATCH.value, r.SP.value,
+ lr_offset)
+ self.mc.mtlr(r.SCRATCH.value)
+
+ # remove minimal frame
+ self.mc.addi(r.SP.value, r.SP.value, frame_size)
+
+ offset = self.mc.currpos() - patch_loc
+ #
+ pmc = OverwritingBuilder(self.mc, patch_loc, 1)
+ pmc.bc(4, 1, offset) # jump if SCRATCH <= r16, i. e. not(SCRATCH > r16)
+ pmc.overwrite()
+
def setup(self, looptoken, operations):
self.current_clt = looptoken.compiled_loop_token
operations = self.cpu.gc_ll_descr.rewrite_assembler(self.cpu,
@@ -486,6 +681,7 @@
self._build_propagate_exception_path()
if gc_ll_descr.get_malloc_slowpath_addr is not None:
self._build_malloc_slowpath()
+ self._build_stack_check_slowpath()
if gc_ll_descr.gcrootmap and gc_ll_descr.gcrootmap.is_shadow_stack:
self._build_release_gil(gc_ll_descr.gcrootmap)
self.memcpy_addr = self.cpu.cast_ptr_to_int(memcpy_fn)
@@ -596,6 +792,7 @@
if log:
operations = self._inject_debugging_code(looptoken, operations,
'e', looptoken.number)
+
self.startpos = self.mc.currpos()
regalloc = Regalloc(assembler=self, frame_manager=PPCFrameManager())
More information about the pypy-commit
mailing list