/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.ppc; import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_DOUBLE; import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS; import org.jikesrvm.VM; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; /** *-------------------------------------------------------------------------- * Stackframe layout conventions *--------------------------------------------------------------------------- * * A stack is an array of "slots", declared formally as 4 bytes on 32bit architectures * and 8 bytes on 64bit architectures, each slot * containing either a primitive (byte, int, float, etc), an object pointer, * a machine code pointer (a return address pointer), or a pointer to another * slot in the same stack (a frame pointer). The interpretation of a slot's * contents depends on the current value of IP, the machine instruction * address register. * Each machine code generator provides maps, for use by the garbage collector, * that tell how to interpret the stack slots at "safe points" in the * program's execution.<p> * * Here's a picture of what a stack might look like in memory.<p> * * Note: this (array) object is drawn upside down compared to other objects * because the hardware stack grows from high memory to low memory, but * array objects are laid out from low memory to high (header first). * <pre> * hi-memory * +===============+ * | LR save area | * +---------------+ * | MI=-1 | <-- "invisible method" id * +---------------+ * +-> | FP=0 | <-- "end of vm stack" sentinel * | +===============+ . . . . . . . . . . . . . . . . . . . . . . . . . . . * | | saved FPRs | \ . * | +---------------+ \_nonvolatile register save area . * | | saved GPRS | / . * | +---------------+ / . * | | (padding) | <--optional padding so frame size is multiple of 8 . * | +---------------+ . * | | local0 | \ . * | +---------------+ \_local variables (++) . * | | local1 | / . * | +---------------+ / . * | | operand0 | \ . * | +---------------+ \_operand stack (++) . * | | operand1 | / . * | +---------------+ / ..frame * | | ... | . * | +---------------+ . * | | spill1 | \ . * | +---------------+ \_parameter spill area . * | | spill0 | / . * | +===============+ / . * | | | <-- spot for this frame's callee's return address . * | +---------------+ . * | | MI | <-- this frame's method id . * \ +---------------+ . * FP -> | saved FP | <-- this frame's caller's frame . * +===============+ . . . . . . . . . . . . . . . . . . . . . . . . . . . * th.stackLimit-> | ... | \ * +---------------+ \_guard region for detecting & processing stack overflow * | ... | / * +---------------+ / * |(object header)| * low-memory +---------------+ * * note: (++) means "baseline compiler frame layout and register * usage conventions" * * </pre> * * On the 64 bit powerPC some design decisions were made as follows:<p> * * An Address, Float and Integer-Like types take 1 slot of 8 bytes. * The 4 byte quantities resides in the least significant half of the slot, * which is at side of the higher addresses. * A Long and a Double take 2 slots of 8 bytes, one of which is not used: * the actual value is also stored at the side of the highest addresses.<p> * * Here are some pictures of what a stackslot might look like in memory. * * <pre> * * 64 bit 32 bit * * High Memory * * | Stack grows down * | * | +---------------+---------------+ +---------------+ * | | Integer | '''garbage''' | | Integer | * | +---------------+---------------+ +---------------+ * | | Address | | Address | * | +---------------+---------------+ +---------------+ * | | Long | | | * | +---------------+---------------+ +-- Long ---+ * | | '''garbage''' | | | * | +---------------+---------------+ +---------------+ * | |Byte| ''| 'g| a| r b a g e ''' | |Byte| 'garbage'| * | +---------------+---------------+ +---------------+ * | | Double | | | * | +---------------+---------------+ +--- Double ---+ * | | '''garbage''' | | | * | +---------------+---------------+ +---------------+ * | | empty | | empty | * | +---------------+---------------+ +---------------+ * \ / * * Low Memory * * </pre> */ public final class StackframeLayoutConstants { public static final int LOG_BYTES_IN_STACKSLOT = LOG_BYTES_IN_ADDRESS; public static final int BYTES_IN_STACKSLOT = 1 << LOG_BYTES_IN_STACKSLOT; /** size of frame header, in bytes */ public static final int STACKFRAME_HEADER_SIZE = 3 * BYTES_IN_STACKSLOT; // SVR4 ABI has no space between FP and LR, swap the positions for LR and CMID depending on ABI. public static final Offset STACKFRAME_RETURN_ADDRESS_OFFSET = Offset.fromIntSignExtend(VM.BuildForPower64ELF_ABI ? 2 * BYTES_IN_STACKSLOT : BYTES_IN_STACKSLOT); public static final Offset STACKFRAME_METHOD_ID_OFFSET = Offset.fromIntSignExtend(VM.BuildForPower64ELF_ABI ? BYTES_IN_STACKSLOT : 2 * BYTES_IN_STACKSLOT); /** base of this frame **/ public static final Offset STACKFRAME_FRAME_POINTER_OFFSET = Offset.zero(); /** fp value indicating end of stack walkback */ public static final Address STACKFRAME_SENTINEL_FP = Address.fromIntSignExtend(-2); /** marker for "assembler" frames that have no associated RVMMethod **/ public static final int INVISIBLE_METHOD_ID = -1; /** * Stackframe alignment. Align to 8 byte boundary for good floating point * save/restore performance (on powerPC, anyway). */ public static final int STACKFRAME_ALIGNMENT = BYTES_IN_DOUBLE; // Sizes for stacks and sub-regions thereof. // Values are in bytes and must be a multiple of 8 (size of a stack slot on 64-architecture). /** how much to grow normal stack when overflow detected */ public static final int STACK_SIZE_GROW = 8 * 1024; /** max space needed for stack overflow trap processing */ public static final int STACK_SIZE_GUARD = 8 * 1024; /** max space needed for entry to sysCall# via Magic */ public static final int STACK_SIZE_NATIVE = 4 * 1024; /** max space needed for first entry to native code via JNI */ public static final int STACK_SIZE_JNINATIVE = 180 * 1024; /** max space needed for dlopen sys call */ public static final int STACK_SIZE_DLOPEN = 30 * 1024; /** size to grow once for native on first entry via JNI */ public static final int STACK_SIZE_JNINATIVE_GROW = 184 * 1024; /** max space needed while running with gc disabled */ public static final int STACK_SIZE_GCDISABLED = 4 * 1024; // /** upper limit on stack size (includes guard region) */ public static final int STACK_SIZE_MAX = 512 * 1024; // Complications: // - STACK_SIZE_GUARD must be greater than STACK_SIZE_NATIVE or STACK_SIZE_GCDISABLED // to ensure that frames allocated by stack growing code will fit within guard region. // - STACK_SIZE_GROW must be greater than STACK_SIZE_NATIVE or STACK_SIZE_GCDISABLED // to ensure that, if stack is grown prior to disabling gc or calling native code, // the new stack will accommodate that code without generating a stack overflow trap. // - Values chosen for STACK_SIZE_NATIVE and STACK_SIZE_GCDISABLED are pure guess work // selected by trial and error. // // Initial stack sizes. Note that stacks for collector threads cannot grow. /** Initial stack size for normal thread. Stacks for "normal" threads grow as needed by trapping on guard region. */ public static final int STACK_SIZE_NORMAL = STACK_SIZE_GUARD + STACK_SIZE_GCDISABLED + 16 * 1024 + (VM.BuildFor64Addr ? 256 * 1024 : 0); /** Initial stack size for boot thread. Stacks for "boot" thread grow as needed - boot thread calls JNI during initialization */ public static final int STACK_SIZE_BOOT = STACK_SIZE_GUARD + STACK_SIZE_GCDISABLED + STACK_SIZE_JNINATIVE + 128 * 1024; /** Initial stack size for collector thread. Stacks for "collector" threads are fixed in size and cannot grow. */ public static final int STACK_SIZE_COLLECTOR = STACK_SIZE_GUARD + STACK_SIZE_GCDISABLED + 32 * 1024; private StackframeLayoutConstants() { // prevent instantiation } }