/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.vm.stack.amd64;
import static com.sun.max.platform.Platform.*;
import com.oracle.max.asm.target.amd64.*;
import com.oracle.max.cri.intrinsics.*;
import com.sun.cri.ci.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.collect.*;
import com.sun.max.vm.compiler.target.*;
import com.sun.max.vm.stack.*;
/**
* Describes a stack frame for a AMD64 method whose frame conforms with the JVMS.
* This convention uses both a stack and a frame pointer (respectively, %rsp and %rbp).
* The frame pointer serves as a base for accessing local variables (as defined in class files of Java methods).
* The stack pointer is used as an operand stack (as defined in the JVMS).
* The layout of the stack is as follows:
* <p>
* <pre>
* Base Index Contents
* ----------------+--------------------------------+---------------- maximumSlotOffset() if P > 0
* [+R+(P*J)+1] | Java parameter 0 | Incoming
* | ... | Java
* [+R+1] | Java parameter (P-1) | parameters
* ----------------+--------------------------------+----------------
* [+R] | return address | Call save ___
* [+R-1] | caller's FP value | area ^
* +--------------------------------+---------------- |
* | ... | alignment |
* +--------------------------------+---------------- | maximumSlotOffset() if P == 0
* [+(T-1)] | template spill slot (T-1) | Template |
* | ... | spill |
* [+0] | template spill slot 0 | area frameSize()
* FP (%RBP) ==> +--------------------------------+---------------- |
* [-J] | Java non-parameter local 0 | Java |
* | ... | non-parameters |
* [-(L*J)] | Java non-parameter local (L-1) | locals v
* +--------------------------------+---------------- ---
* [-((L+1)*J)] | Java stack slot 0 | Java
* | ... | operand
* [-((L+S)*J)] | Java stack slot (S-1) | stack
* SP (%RSP) ==> +--------------------------------+---------------- lowestSlotOffset()
*
* where:
* P == Number of Java parameter slots
* L == Number of Java non-parameter local slots
* S == Number of Java operand stack slots # (i.e. maxStack)
* T == Number of template spill slots
* R == Return address offset [ frameSize - sizeOfNonParameterLocals() ]
* J == Stack slots per JVMS slot [ JVMS_SLOT_SIZE / Word.size() ]
*
* </pre>
*
* The parameters portion of the stack frame is set up by the caller.
* The frame size counts only those slots that are allocated on the stack by the callee, upon method entry, namely,
* the size for the saved frame pointer, the locals that aren't argument, the Java stack, and the template spill slots.
*/
public class AMD64JVMSFrameLayout extends JVMSFrameLayout {
/**
* Size of the call save area, in number of stack slots. All method invocations push a return address
* (1 stack slot) and the prologue saves the caller's frame pointer (1 stack slot).
*/
public static final int CALL_SAVE_AREA_SLOTS = 2;
private final int numberOfTemplateSlots;
public AMD64JVMSFrameLayout(TargetMethod targetMethod) {
super(targetMethod.classMethodActor());
final int frameSlots = UnsignedMath.divide(targetMethod.frameSize(), STACK_SLOT_SIZE);
final int nonTemplateSlots = 1 + UnsignedMath.divide(sizeOfNonParameterLocals(), STACK_SLOT_SIZE);
numberOfTemplateSlots = frameSlots - nonTemplateSlots;
assert targetMethod.frameSize() == frameSize();
}
public AMD64JVMSFrameLayout(ClassMethodActor classMethodActor, int numberOfTemplateSlots) {
super(classMethodActor);
this.numberOfTemplateSlots = numberOfTemplateSlots;
}
public AMD64JVMSFrameLayout(int numberOfLocalSlots, int numberOfOperandStackSlots, int numberOfParameterSlots, int numberOfTemplateSlots) {
super(numberOfLocalSlots, numberOfOperandStackSlots, numberOfParameterSlots);
this.numberOfTemplateSlots = numberOfTemplateSlots;
}
@Override
public CiRegister framePointerReg() {
return AMD64.rbp;
}
@Override
public int frameSize() {
final int numberOfSlots = 1 + numberOfTemplateSlots; // one extra word for the caller RBP
final int unalignedSize = numberOfSlots * STACK_SLOT_SIZE + sizeOfNonParameterLocals();
return target().alignFrameSize(unalignedSize);
}
@Override
public int localVariableOffset(int localVariableIndex) {
if (isParameter(localVariableIndex)) {
// The slot index is at a positive offset from RBP.
// | non-parameter locals | template slots | caller FP | return address | parameters |
// | <-------------------- frameSize() --------------> |
// ^ RBP ^ parameterStart
final int parameterStart = returnAddressOffset() + Word.size();
return parameterStart + JVMS_SLOT_SIZE * (numberOfParameterSlots - 1 - localVariableIndex);
}
// The slot index is at a negative offset from RBP.
// | non-parameter locals | template slots | call save area | return address | parameters |
// ^ slot index ^ RBP
final int slotIndex = numberOfParameterSlots - 1 - localVariableIndex;
return slotIndex * JVMS_SLOT_SIZE;
}
@Override
public int operandStackOffset(int operandStackIndex) {
return 0 - ((numberOfNonParameterSlots() + operandStackIndex + 1) * JVMS_SLOT_SIZE);
}
public int returnAddressOffset() {
return frameSize() - sizeOfNonParameterLocals();
}
public int callersRBPOffset() {
return returnAddressOffset() - STACK_SLOT_SIZE;
}
@Override
public int maximumSlotOffset() {
if (numberOfParameterSlots == 0) {
// if there are no parameters, return the offset to the end of the last template slot
return sizeOfNonParameterLocals() + numberOfTemplateSlots * STACK_SLOT_SIZE;
}
// return the end of the first parameter
return localVariableOffset(0) + JVMS_SLOT_SIZE;
}
@Override
public int lowestSlotOffset() {
// return the offset of the topmost operand on the Java stack
// if the operand stack size is 0, this will return the offset to the last local variable
return operandStackOffset(numberOfOperandStackSlots - 1);
}
@Override
public int numberOfTemplateSlots() {
return numberOfTemplateSlots;
}
@Override
public boolean isReturnAddressPushedByCall() {
return true;
}
@Override
public int frameReferenceMapOffset() {
return lowestSlotOffset();
}
@Override
public int frameReferenceMapSize() {
return ByteArrayBitMap.computeBitMapSize(UnsignedMath.divide(maximumSlotOffset() - lowestSlotOffset(), STACK_SLOT_SIZE));
}
@Override
public int localVariableReferenceMapIndex(int localVariableIndex) {
return framePointerOffsetToRefMapIndex(localVariableOffset(localVariableIndex));
}
@Override
public int operandStackReferenceMapIndex(int operandStackIndex) {
return framePointerOffsetToRefMapIndex(operandStackOffset(operandStackIndex));
}
private int framePointerOffsetToRefMapIndex(int offset) {
// | operand slots | non-parameter locals | template slots | call save area | return address | parameters |
// ^ operand offset (wrt. RBP) ^ RBP ^ local offset (wrt. RBP)
// <-------- frame pointer bias ---------->
final int framePointerBias = sizeOfOperandStack() + sizeOfNonParameterLocals();
return UnsignedMath.divide(offset + framePointerBias, STACK_SLOT_SIZE);
}
@Override
public JVMSSlots slots() {
return new JVMSSlots() {
@Override
protected String nameOfSlot(int offset) {
final int templateSlotIndex = UnsignedMath.divide(offset, STACK_SLOT_SIZE);
if (templateSlotIndex >= 0 && templateSlotIndex < numberOfTemplateSlots) {
return "template slot " + templateSlotIndex;
}
if (offset == returnAddressOffset()) {
return "return address";
}
if (offset == callersRBPOffset()) {
return "caller's FP";
}
return super.nameOfSlot(offset);
}
};
}
}