/* * 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 java.util.*; import com.oracle.max.cri.intrinsics.*; import com.sun.cri.ci.*; import com.sun.max.unsafe.*; import com.sun.max.vm.collect.*; import com.sun.max.vm.runtime.*; /** * Describes the layout of an activation frame for code translated by the VM. */ public abstract class VMFrameLayout { /** * Size of a stack location. Large enough to hold a native pointer or an object reference. */ public static final int STACK_SLOT_SIZE = Word.size(); /** * Determines how much space is reserved on the stack for this frame. This doesn't include the space for storing the * return instruction address on architectures that push it on calls. */ public abstract int frameSize(); /** * Gets the register used as the frame pointer. */ public abstract CiRegister framePointerReg(); /** * Gets the size of the reference map for all the stack words whose value may be changed by this frame's method. * This includes the parameter slots even though the space for them is allocated by the caller. These slots are * potentially reused by the method and thus may subsequently change their GC type. * * @return the size of a {@linkplain ByteArrayBitMap bit map} which * {@linkplain ByteArrayBitMap#computeBitMapSize(int) can encode} a bit for each unique stack word whose * value may be changed by this frame's method */ public abstract int frameReferenceMapSize(); /** * Gets the frame pointer offset of the effective address to which the entries in the reference map are relative. */ public abstract int frameReferenceMapOffset(); /** * Gets the frame pointer offset of the effective address of a given local variable. * * @param localVariableIndex an index into the local variables array * @return the frame pointer offset of the value of the variable at {@code localVariableIndex} in the local * variables array */ public int localVariableOffset(int localVariableIndex) { throw FatalError.unimplemented(); } /** * Gets the frame pointer offset of the effective address of a given operand stack slot. * * @param operandStackIndex an index relative to the bottom of the operand stack * @return the frame pointer offset of the value of the operand stack slot at {@code operandStackIndex} from the * bottom of the operand stack */ public int operandStackOffset(int operandStackIndex) { throw FatalError.unimplemented(); } /** * Gets the highest frame pointer offset of a stack slot considered to be within this frame. */ public int maximumSlotOffset() { return frameSize() + (isReturnAddressPushedByCall() ? Word.size() : 0); } /** * Gets the lowest frame pointer offset of a stack slot considered to be within this frame. */ public int lowestSlotOffset() { return 0; } /** * Determines if the caller of this frame pushed a return address to the stack. */ public abstract boolean isReturnAddressPushedByCall(); /** * Gets an object that can format the details of this layout as strings. */ public Slots slots() { return new Slots(); } @Override public String toString() { return slots().toString(); } /** * Describes a stack slot. */ public static class Slot { public final int offset; public final String name; /** * The frame reference map index that corresponds with this slot. If this slot in not covered by a frame * reference map, then this field has the value {@code -1}. */ public final int referenceMapIndex; public Slot(int offset, String name, int referenceMapIndex) { this.name = name; this.offset = offset; this.referenceMapIndex = referenceMapIndex; } @Override public String toString() { return String.format("FP%+d[bit=%d,name=%s]", offset, referenceMapIndex, name); } } /** * A collection of {@link Slot} objects that describe each stack slot within a frame in more detail. Note that * {@linkplain #iterator() iterating} over the slots goes from the slot with the highest offset to the slot with the * lowest offset. */ public class Slots implements Iterable<Slot> { protected final Slot[] slots; protected Slots() { final int maximumSlotOffset = maximumSlotOffset(); final int lowestSlotOffset = lowestSlotOffset(); assert maximumSlotOffset >= lowestSlotOffset; final int slotCount = UnsignedMath.divide(maximumSlotOffset - lowestSlotOffset, STACK_SLOT_SIZE); slots = new Slot[slotCount]; int index = 0; for (int offset = maximumSlotOffset - STACK_SLOT_SIZE; offset >= lowestSlotOffset; offset -= STACK_SLOT_SIZE) { slots[index++] = new Slot(offset, nameOfSlot(offset), referenceMapIndexForSlot(offset)); } } /** * Gets a descriptive name for the slot at a given offset. * * @param offset a frame pointer relative offset * @return a descriptive name for the slot at {@code offset}. */ protected String nameOfSlot(int offset) { if (isReturnAddressPushedByCall()) { final int offsetOfReturnAddress = frameSize(); if (offset == offsetOfReturnAddress) { return "return address"; } } final int slotIndex = UnsignedMath.divide(offset, STACK_SLOT_SIZE); return "slot " + slotIndex; } /** * Gets the frame reference map index that corresponds with the slot at a given offset. If the slot in not * covered by a frame reference map, then -1 is returned. * * @param offset a frame pointer relative offset * @return the frame reference map index for the slot at {@code offset} or -1 if that slot in not covered by a * frame reference map */ protected int referenceMapIndexForSlot(int offset) { if (offset < frameSize() && offset >= 0) { return UnsignedMath.divide(offset, STACK_SLOT_SIZE); } return -1; } public int size() { return slots.length; } /** * Gets the slot at a given index. The slot at index 0 (if any) is the one with the highest offset and * the slot at index {@code length() - 1} is the one with the lowest offset. * * @param index * @return the slot at {@code index} * @throws IndexOutOfBoundsException if {@code index < 0 || index >= length()} */ public final Slot slot(int index) throws IndexOutOfBoundsException { return slots[index]; } /** * Gets the slot at a given frame pointer offset. * * @param offset * @return null if there is no slot at the given offset */ public final Slot slotAtOffset(int offset) { final int index = UnsignedMath.divide(maximumSlotOffset() - offset, STACK_SLOT_SIZE); if (index < 0 || index >= slots.length) { return null; } return slots[index]; } /** * Gets an iterator over the slots. * * @return an iterator of the slots that iterates over the slots in descending order of their {@linkplain Slot#offset offsets} */ public Iterator<Slot> iterator() { return Arrays.asList(slots).iterator(); } /** * Formats the layout of the frame as a string. * * @param referenceMap if not null, extra detail is added to the returned string to indicate which slots contain * references according to this reference map */ public String toString(ByteArrayBitMap referenceMap) { final StringBuilder sb = new StringBuilder(); sb.append(String.format("-- Offset --+ Bit %s+-- Name --%n", referenceMap == null ? "" : "+ IsRef ")); for (Slot slot : this) { final String referenceMapIndex = slot.referenceMapIndex == -1 ? "" : String.valueOf(slot.referenceMapIndex); final String slotIsReference; if (referenceMap == null) { slotIsReference = ""; } else { if (referenceMapIndex.isEmpty()) { slotIsReference = "| "; } else { slotIsReference = referenceMap.isSet(slot.referenceMapIndex) ? "| yes " : "| no "; } } sb.append(String.format(" FP%+-6d | %-3s %s| %s%n", slot.offset, referenceMapIndex, slotIsReference, slot.name)); } return sb.toString(); } /** * Formats the layout of the frame as a string. */ @Override public String toString() { return toString(null); } } }