/* * Copyright (c) 2007, 2012, 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; import static com.sun.max.platform.Platform.*; import com.oracle.max.cri.intrinsics.*; import com.sun.cri.ci.*; import com.sun.max.annotate.*; import com.sun.max.lang.*; import com.sun.max.unsafe.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.classfile.*; import com.sun.max.vm.compiler.*; import com.sun.max.vm.type.*; /** * Describes the layout of an activation frame for a method whose frame explicitly models the * JVMS notions of a <a href="http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html#15722">local * variable array</a> and an * <a href="http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html#28851">operand stack</a>. That is, * at any point in a bytecode method where a local variable or operand stack slot has a valid value, the value can be * accessed from the activation frame. */ public abstract class JVMSFrameLayout extends VMFrameLayout { protected final int numberOfLocalSlots; protected final int numberOfOperandStackSlots; protected final int numberOfParameterSlots; /** * Size of a JVMS slot. It may differ from {@link VMFrameLayout#STACK_SLOT_SIZE} due to alignment * constraints imposed on a stack frame by the target platform (e.g., AMD64 requires 16-byte aligned stack frame). * In this case, it's simpler to use a slot size larger than the optimal stack slot sized used by * an optimizing compiler. * * If {@code JVMS_SLOT_SIZE} is greater than {@link VMFrameLayout#STACK_SLOT_SIZE}, then stack values occupy * the lower address(es). For example, on a 64 bit machine with {@code JVMS_SLOT_SIZE == 16}, an integer in the * stack slot at address {@code sp} occupies the 4 bytes starting at {@code sp}. */ public static final int JVMS_SLOT_SIZE = getSlotSize(); public static final int JVMS_STACK_BIAS = getStackBias(); private static final Endianness ENDIANNESS = platform().endianness(); public static final int CATEGORY1_OFFSET_WITHIN_WORD = offsetWithinWord(Kind.INT); public static final int CATEGORY2_OFFSET_WITHIN_WORD = offsetWithinWord(Kind.LONG); /** * The number of word size stack slots per JVMS stack slot. See {@link #JVMS_SLOT_SIZE} for an explanation of why * JVMS stack slots may differ in size from normal stack slots. */ public static final int STACK_SLOTS_PER_JVMS_SLOT = JVMS_SLOT_SIZE / STACK_SLOT_SIZE; static { assert JVMS_SLOT_SIZE % STACK_SLOT_SIZE == 0 : "JVMS_SLOT_SIZE must be an even multiple of STACK_SLOT_SIZE"; } /** * Return the offset of a value of a given kind within a word. This helps hiding endianness issues for * loading/storing to stack slots. * @param kind * @return an offset in byte */ @HOSTED_ONLY public static int offsetWithinWord(Kind kind) { return ENDIANNESS.offsetWithinWord(Kind.WORD.width, kind.width); } @HOSTED_ONLY private static int getSlotSize() { final int alignment = target().stackAlignment; return Ints.roundUnsignedUpByPowerOfTwo(alignment, Word.size()); } @HOSTED_ONLY private static int getStackBias() { return target().stackBias; } public JVMSFrameLayout(int numberOfLocalSlots, int numberOfOperandStackSlots, int numberOfParameterSlots) { this.numberOfLocalSlots = numberOfLocalSlots; this.numberOfOperandStackSlots = numberOfOperandStackSlots; this.numberOfParameterSlots = numberOfParameterSlots; assert numberOfLocalSlots >= numberOfParameterSlots : "incoming arguments cannot be greater than number of locals"; } protected JVMSFrameLayout(ClassMethodActor classMethodActor) { final CodeAttribute codeAttribute = classMethodActor.codeAttribute(); numberOfOperandStackSlots = codeAttribute.maxStack; numberOfLocalSlots = codeAttribute.maxLocals; numberOfParameterSlots = classMethodActor.numberOfParameterSlots(); assert numberOfLocalSlots >= numberOfParameterSlots : "incoming arguments cannot be greater than number of locals"; } public static int stackSlotSize(Kind kind) { return kind.isCategory1 ? JVMS_SLOT_SIZE : 2 * JVMS_SLOT_SIZE; } public static int offsetInStackSlot(Kind kind) { if (kind.stackSlots == 2) { return CATEGORY2_OFFSET_WITHIN_WORD; } return CATEGORY1_OFFSET_WITHIN_WORD; } /** * Gets the number of stack slots occupied by the incoming parameters to this frame. */ public int numberOfParameterSlots() { return numberOfParameterSlots; } /** * Gets the number of stack slots occupied by the templates in this stack frame. */ public abstract int numberOfTemplateSlots(); /** * Gets the size, in bytes, of the area reserved for template slots. * @return the size of the template slots in bytes. */ public int sizeOfTemplateSlots() { return numberOfTemplateSlots() * STACK_SLOT_SIZE; } /** * Gets the number of local variable slots in this frame. This is equivalent to the value returned by * {@link CodeAttribute#maxLocals}. */ public int numberOfLocalSlots() { return numberOfLocalSlots; } /** * Gets the number of operand stack slots in this frame. This is equivalent to the value returned by * {@link CodeAttribute#maxStack}. */ public int numberOfOperandStackSlots() { return numberOfOperandStackSlots; } /** * Gets the size of the locals, in bytes. This is equal to the number of locals slots multiplied * by the size of a JVMS slot. * @return the size of the locals in bytes */ public final int sizeOfLocals() { return numberOfLocalSlots() * JVMS_SLOT_SIZE; } /** * Gets the size of the parameters, in bytes, which is equal to the number of parameter slots times * the size of a JVMS slot. * @return the size of the parameters in bytes */ public final int sizeOfParameters() { return numberOfParameterSlots() * JVMS_SLOT_SIZE; } /** * Gets the size of the local variables which are not parameters, in bytes. * @return the size of the non-parameter locals in bytes */ public final int sizeOfNonParameterLocals() { return numberOfNonParameterSlots() * JVMS_SLOT_SIZE; } /** * Gets the size of the operand stack, in bytes. * @return the size of the operand stack in bytes */ public final int sizeOfOperandStack() { return numberOfOperandStackSlots() * JVMS_SLOT_SIZE; } /** * Gets the index of the bit in the {@linkplain #frameReferenceMapSize() frame reference map} corresponding to the * stack slot for a given local variable. * * @param localVariableIndex * an index into the local variables array */ public abstract int localVariableReferenceMapIndex(int localVariableIndex); /** * Gets the index of the bit in the {@linkplain #frameReferenceMapSize() frame reference map} corresponding to the * stack slot for a given operand stack slot. * * @param operandStackIndex * an index relative to the bottom of the operand stack */ public abstract int operandStackReferenceMapIndex(int operandStackIndex); @Override public JVMSSlots slots() { return new JVMSSlots(); } public boolean isParameter(int localVariableIndex) { return localVariableIndex < numberOfParameterSlots; } public int numberOfNonParameterSlots() { return numberOfLocalSlots - numberOfParameterSlots; } public CiFrame asFrame(ClassMethodActor method, int bci, CiBitMap frameRefMap) { CodeAttribute codeAttribute = method.codeAttribute(); int numLocks = 0; // TODO: get the real value int numLocals = codeAttribute.maxLocals; int numStack = codeAttribute.maxStack; CiValue[] values = new CiValue[numLocals + numStack]; CiValue fp = framePointerReg().asValue(); for (int i = 0; i < numLocals; i++) { CiKind kind = WordUtil.archKind(); if (frameRefMap != null && frameRefMap.get(localVariableReferenceMapIndex(i))) { kind = CiKind.Object; } CiAddress value = new CiAddress(kind, fp, localVariableOffset(i)); values[i] = value; } for (int i = 0; i < numStack; i++) { CiKind kind = WordUtil.archKind(); if (frameRefMap != null && frameRefMap.get(operandStackReferenceMapIndex(i))) { kind = CiKind.Object; } CiAddress value = new CiAddress(kind, fp, operandStackOffset(i)); values[i + numLocals] = value; } return new CiFrame(null, method, bci, false, values, numLocals, numStack, numLocks); } /** * Size in bytes of parameters on a stack frame. * * @param parametersKinds kinds of parameters. * @return size in bytes */ public static int parametersFrameSize(Kind[] parametersKinds) { int frameSize = 0; for (Kind parametersKind : parametersKinds) { frameSize += stackSlotSize(parametersKind); } return frameSize; } public static boolean isFillerSlot(int jvmsSlotOffset, int offset) { if (JVMS_SLOT_SIZE == STACK_SLOT_SIZE) { return false; } for (int fillerOffset = jvmsSlotOffset + STACK_SLOT_SIZE; fillerOffset < jvmsSlotOffset + JVMS_SLOT_SIZE; fillerOffset += STACK_SLOT_SIZE) { if (offset == fillerOffset) { return true; } } return false; } public class JVMSSlots extends Slots { protected String nameOfLocal(int localVariableIndex) { if (isParameter(localVariableIndex)) { return "local " + localVariableIndex + " [parameter " + localVariableIndex + "]"; } return "local " + localVariableIndex + " [non-parameter " + (localVariableIndex - numberOfParameterSlots) + "]"; } @Override protected String nameOfSlot(int offset) { for (int i = 0; i != numberOfLocalSlots; ++i) { final int localVariableOffset = localVariableOffset(i); if (offset == localVariableOffset) { return nameOfLocal(i); } if (isFillerSlot(localVariableOffset, offset)) { return "local " + i + " [filler]"; } } for (int i = 0; i != numberOfOperandStackSlots; ++i) { final int operandStackOffset = operandStackOffset(i); if (operandStackOffset == offset) { return "operand stack " + i; } if (isFillerSlot(operandStackOffset, offset)) { return "operand stack " + i + " [filler]"; } } return super.nameOfSlot(offset); } @Override protected int referenceMapIndexForSlot(int offset) { if (offset >= lowestSlotOffset() && offset < maximumSlotOffset()) { return UnsignedMath.divide(offset - lowestSlotOffset(), STACK_SLOT_SIZE); } return -1; } } }