Mercurial > hg > truffle
diff graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java @ 18443:1c92d437179b
FrameMapBuilder: move into package.
author | Josef Eisl <josef.eisl@jku.at> |
---|---|
date | Mon, 17 Nov 2014 16:41:44 +0100 |
parents | graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java@9bf59aa9d8c6 |
children | 6383574293f9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMap.java Mon Nov 17 16:41:44 2014 +0100 @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2009, 2014, 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.oracle.graal.lir.framemap; + +import static com.oracle.graal.api.code.ValueUtil.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; + +/** + * This class is used to build the stack frame layout for a compiled method. A {@link StackSlot} is + * used to index slots of the frame relative to the stack pointer. The frame size is only fixed + * after register allocation when all spill slots have been allocated. Both the outgoing argument + * area and the spill are can grow until then. Therefore, outgoing arguments are indexed from the + * stack pointer, while spill slots are indexed from the beginning of the frame (and the total frame + * size has to be added to get the actual offset from the stack pointer). + */ +public abstract class FrameMap { + + private final TargetDescription target; + private final RegisterConfig registerConfig; + + /** + * The final frame size, not including the size of the + * {@link Architecture#getReturnAddressSize() return address slot}. The value is only set after + * register allocation is complete, i.e., after all spill slots have been allocated. + */ + private int frameSize; + + /** + * Initial size of the area occupied by spill slots and other stack-allocated memory blocks. + */ + protected int initialSpillSize; + + /** + * Size of the area occupied by spill slots and other stack-allocated memory blocks. + */ + protected int spillSize; + + /** + * Size of the area occupied by outgoing overflow arguments. This value is adjusted as calling + * conventions for outgoing calls are retrieved. On some platforms, there is a minimum outgoing + * size even if no overflow arguments are on the stack. + */ + protected int outgoingSize; + + /** + * Determines if this frame has values on the stack for outgoing calls. + */ + private boolean hasOutgoingStackArguments; + + /** + * The list of stack slots allocated in this frame that are present in every reference map. + */ + private final List<StackSlot> objectStackSlots; + + /** + * Records whether an offset to an incoming stack argument was ever returned by + * {@link #offsetForStackSlot(StackSlot)}. + */ + private boolean accessesCallerFrame; + + /** + * Creates a new frame map for the specified method. The given registerConfig is optional, in + * case null is passed the default RegisterConfig from the CodeCacheProvider will be used. + */ + public FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig) { + this.target = codeCache.getTarget(); + this.registerConfig = registerConfig == null ? codeCache.getRegisterConfig() : registerConfig; + this.frameSize = -1; + this.outgoingSize = codeCache.getMinimumOutgoingSize(); + this.objectStackSlots = new ArrayList<>(); + } + + public RegisterConfig getRegisterConfig() { + return registerConfig; + } + + public TargetDescription getTarget() { + return target; + } + + protected int returnAddressSize() { + return getTarget().arch.getReturnAddressSize(); + } + + protected int calleeSaveAreaSize() { + CalleeSaveLayout csl = getRegisterConfig().getCalleeSaveLayout(); + return csl != null ? csl.size : 0; + } + + /** + * Determines if an offset to an incoming stack argument was ever returned by + * {@link #offsetForStackSlot(StackSlot)}. + */ + public boolean accessesCallerFrame() { + return accessesCallerFrame; + } + + /** + * Gets the frame size of the compiled frame, not including the size of the + * {@link Architecture#getReturnAddressSize() return address slot}. + * + * @return The size of the frame (in bytes). + */ + public int frameSize() { + assert frameSize != -1 : "frame size not computed yet"; + return frameSize; + } + + public int outgoingSize() { + return outgoingSize; + } + + /** + * Determines if any space is used in the frame apart from the + * {@link Architecture#getReturnAddressSize() return address slot}. + */ + public boolean frameNeedsAllocating() { + int unalignedFrameSize = spillSize - returnAddressSize(); + return hasOutgoingStackArguments || unalignedFrameSize != 0; + } + + /** + * Gets the total frame size of the compiled frame, including the size of the + * {@link Architecture#getReturnAddressSize() return address slot}. + * + * @return The total size of the frame (in bytes). + */ + public abstract int totalFrameSize(); + + /** + * Gets the current size of this frame. This is the size that would be returned by + * {@link #frameSize()} if {@link #finish()} were called now. + */ + public abstract int currentFrameSize(); + + /** + * Aligns the given frame size to the stack alignment size and return the aligned size. + * + * @param size the initial frame size to be aligned + * @return the aligned frame size + */ + protected abstract int alignFrameSize(int size); + + /** + * Computes the final size of this frame. After this method has been called, methods that change + * the frame size cannot be called anymore, e.g., no more spill slots or outgoing arguments can + * be requested. + */ + public void finish() { + frameSize = currentFrameSize(); + if (frameSize > getRegisterConfig().getMaximumFrameSize()) { + throw new BailoutException("Frame size (%d) exceeded maximum allowed frame size (%d).", frameSize, getRegisterConfig().getMaximumFrameSize()); + } + } + + /** + * Computes the offset of a stack slot relative to the frame register. + * + * @param slot a stack slot + * @return the offset of the stack slot + */ + public int offsetForStackSlot(StackSlot slot) { + // @formatter:off + assert (!slot.getRawAddFrameSize() && slot.getRawOffset() < outgoingSize) || + (slot.getRawAddFrameSize() && slot.getRawOffset() < 0 && -slot.getRawOffset() <= spillSize) || + (slot.getRawAddFrameSize() && slot.getRawOffset() >= 0) : + String.format("RawAddFrameSize: %b RawOffset: 0x%x spillSize: 0x%x outgoingSize: 0x%x", slot.getRawAddFrameSize(), slot.getRawOffset(), spillSize, outgoingSize); + // @formatter:on + if (slot.isInCallerFrame()) { + accessesCallerFrame = true; + } + return slot.getOffset(totalFrameSize()); + } + + /** + * Gets the offset from the stack pointer to the stack area where callee-saved registers are + * stored. + * + * @return The offset to the callee save area (in bytes). + */ + public abstract int offsetToCalleeSaveArea(); + + /** + * Informs the frame map that the compiled code calls a particular method, which may need stack + * space for outgoing arguments. + * + * @param cc The calling convention for the called method. + */ + public void callsMethod(CallingConvention cc) { + reserveOutgoing(cc.getStackSize()); + } + + /** + * Reserves space for stack-based outgoing arguments. + * + * @param argsSize The amount of space (in bytes) to reserve for stack-based outgoing arguments. + */ + public void reserveOutgoing(int argsSize) { + assert frameSize == -1 : "frame size must not yet be fixed"; + outgoingSize = Math.max(outgoingSize, argsSize); + hasOutgoingStackArguments = hasOutgoingStackArguments || argsSize > 0; + } + + /** + * Reserves a new spill slot in the frame of the method being compiled. The returned slot is + * aligned on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte + * boundary. + * + * @param kind The kind of the spill slot to be reserved. + * @param additionalOffset + * @return A spill slot denoting the reserved memory area. + */ + protected abstract StackSlot allocateNewSpillSlot(LIRKind kind, int additionalOffset); + + /** + * Returns the spill slot size for the given {@link LIRKind}. The default value is the size in + * bytes for the target architecture. + * + * @param kind the {@link LIRKind} to be stored in the spill slot. + * @return the size in bytes + */ + public int spillSlotSize(LIRKind kind) { + return getTarget().getSizeInBytes(kind.getPlatformKind()); + } + + /** + * Reserves a spill slot in the frame of the method being compiled. The returned slot is aligned + * on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte boundary, unless + * overridden by a subclass. + * + * @param kind The kind of the spill slot to be reserved. + * @return A spill slot denoting the reserved memory area. + */ + protected StackSlot allocateSpillSlot(LIRKind kind) { + assert frameSize == -1 : "frame size must not yet be fixed"; + int size = spillSlotSize(kind); + spillSize = NumUtil.roundUp(spillSize + size, size); + return allocateNewSpillSlot(kind, 0); + } + + /** + * Reserves a number of contiguous slots in the frame of the method being compiled. If the + * requested number of slots is 0, this method returns {@code null}. + * + * @param slots the number of slots to reserve + * @param objects specifies the indexes of the object pointer slots. The caller is responsible + * for guaranteeing that each such object pointer slot is initialized before any + * instruction that uses a reference map. Without this guarantee, the garbage + * collector could see garbage object values. + * @return the first reserved stack slot (i.e., at the lowest address) + */ + protected StackSlot allocateStackSlots(int slots, BitSet objects) { + assert frameSize == -1 : "frame size must not yet be fixed"; + if (slots == 0) { + return null; + } + spillSize += (slots * getTarget().wordSize); + + if (!objects.isEmpty()) { + assert objects.length() <= slots; + StackSlot result = null; + for (int slotIndex = 0; slotIndex < slots; slotIndex++) { + StackSlot objectSlot = null; + if (objects.get(slotIndex)) { + objectSlot = allocateNewSpillSlot(LIRKind.reference(Kind.Object), slotIndex * getTarget().wordSize); + addObjectStackSlot(objectSlot); + } + if (slotIndex == 0) { + if (objectSlot != null) { + result = objectSlot; + } else { + result = allocateNewSpillSlot(LIRKind.value(getTarget().wordKind), 0); + } + } + } + assert result != null; + return result; + + } else { + return allocateNewSpillSlot(LIRKind.value(getTarget().wordKind), 0); + } + } + + protected void addObjectStackSlot(StackSlot objectSlot) { + objectStackSlots.add(objectSlot); + } + + public ReferenceMap initReferenceMap(boolean hasRegisters) { + ReferenceMap refMap = getTarget().createReferenceMap(hasRegisters, frameSize() / getTarget().wordSize); + for (StackSlot slot : objectStackSlots) { + setReference(slot, refMap); + } + return refMap; + } + + /** + * Marks the specified location as a reference in the reference map of the debug information. + * The tracked location can be a {@link RegisterValue} or a {@link StackSlot}. Note that a + * {@link JavaConstant} is automatically tracked. + * + * @param location The location to be added to the reference map. + * @param refMap A reference map, as created by {@link #initReferenceMap(boolean)}. + */ + public void setReference(Value location, ReferenceMap refMap) { + LIRKind kind = location.getLIRKind(); + if (isRegister(location)) { + refMap.setRegister(asRegister(location).getReferenceMapIndex(), kind); + } else if (isStackSlot(location)) { + int offset = offsetForStackSlot(asStackSlot(location)); + refMap.setStackSlot(offset, kind); + } else { + assert isConstant(location); + } + } +}