001/* 002 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.lir.framemap; 024 025import java.util.*; 026 027import jdk.internal.jvmci.code.*; 028import jdk.internal.jvmci.meta.*; 029 030import com.oracle.graal.asm.*; 031 032/** 033 * This class is used to build the stack frame layout for a compiled method. A {@link StackSlot} is 034 * used to index slots of the frame relative to the stack pointer. The frame size is only fixed 035 * after register allocation when all spill slots have been allocated. Both the outgoing argument 036 * area and the spill are can grow until then. Therefore, outgoing arguments are indexed from the 037 * stack pointer, while spill slots are indexed from the beginning of the frame (and the total frame 038 * size has to be added to get the actual offset from the stack pointer). 039 */ 040public abstract class FrameMap { 041 042 private final TargetDescription target; 043 private final RegisterConfig registerConfig; 044 045 public interface ReferenceMapBuilderFactory { 046 047 ReferenceMapBuilder newReferenceMapBuilder(int totalFrameSize); 048 } 049 050 private final ReferenceMapBuilderFactory referenceMapFactory; 051 052 /** 053 * The final frame size, not including the size of the 054 * {@link Architecture#getReturnAddressSize() return address slot}. The value is only set after 055 * register allocation is complete, i.e., after all spill slots have been allocated. 056 */ 057 private int frameSize; 058 059 /** 060 * Initial size of the area occupied by spill slots and other stack-allocated memory blocks. 061 */ 062 protected int initialSpillSize; 063 064 /** 065 * Size of the area occupied by spill slots and other stack-allocated memory blocks. 066 */ 067 protected int spillSize; 068 069 /** 070 * Size of the area occupied by outgoing overflow arguments. This value is adjusted as calling 071 * conventions for outgoing calls are retrieved. On some platforms, there is a minimum outgoing 072 * size even if no overflow arguments are on the stack. 073 */ 074 protected int outgoingSize; 075 076 /** 077 * Determines if this frame has values on the stack for outgoing calls. 078 */ 079 private boolean hasOutgoingStackArguments; 080 081 /** 082 * The list of stack slots allocated in this frame that are present in every reference map. 083 */ 084 private final List<StackSlot> objectStackSlots; 085 086 /** 087 * Records whether an offset to an incoming stack argument was ever returned by 088 * {@link #offsetForStackSlot(StackSlot)}. 089 */ 090 private boolean accessesCallerFrame; 091 092 /** 093 * Creates a new frame map for the specified method. The given registerConfig is optional, in 094 * case null is passed the default RegisterConfig from the CodeCacheProvider will be used. 095 */ 096 public FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) { 097 this.target = codeCache.getTarget(); 098 this.registerConfig = registerConfig == null ? codeCache.getRegisterConfig() : registerConfig; 099 this.frameSize = -1; 100 this.outgoingSize = codeCache.getMinimumOutgoingSize(); 101 this.objectStackSlots = new ArrayList<>(); 102 this.referenceMapFactory = referenceMapFactory; 103 } 104 105 public RegisterConfig getRegisterConfig() { 106 return registerConfig; 107 } 108 109 public TargetDescription getTarget() { 110 return target; 111 } 112 113 public void addLiveValues(ReferenceMapBuilder refMap) { 114 for (Value value : objectStackSlots) { 115 refMap.addLiveValue(value); 116 } 117 } 118 119 protected int returnAddressSize() { 120 return getTarget().arch.getReturnAddressSize(); 121 } 122 123 protected int calleeSaveAreaSize() { 124 CalleeSaveLayout csl = getRegisterConfig().getCalleeSaveLayout(); 125 return csl != null ? csl.size : 0; 126 } 127 128 /** 129 * Determines if an offset to an incoming stack argument was ever returned by 130 * {@link #offsetForStackSlot(StackSlot)}. 131 */ 132 public boolean accessesCallerFrame() { 133 return accessesCallerFrame; 134 } 135 136 /** 137 * Gets the frame size of the compiled frame, not including the size of the 138 * {@link Architecture#getReturnAddressSize() return address slot}. 139 * 140 * @return The size of the frame (in bytes). 141 */ 142 public int frameSize() { 143 assert frameSize != -1 : "frame size not computed yet"; 144 return frameSize; 145 } 146 147 public int outgoingSize() { 148 return outgoingSize; 149 } 150 151 /** 152 * Determines if any space is used in the frame apart from the 153 * {@link Architecture#getReturnAddressSize() return address slot}. 154 */ 155 public boolean frameNeedsAllocating() { 156 int unalignedFrameSize = spillSize - returnAddressSize(); 157 return hasOutgoingStackArguments || unalignedFrameSize != 0; 158 } 159 160 /** 161 * Gets the total frame size of the compiled frame, including the size of the 162 * {@link Architecture#getReturnAddressSize() return address slot}. 163 * 164 * @return The total size of the frame (in bytes). 165 */ 166 public abstract int totalFrameSize(); 167 168 /** 169 * Gets the current size of this frame. This is the size that would be returned by 170 * {@link #frameSize()} if {@link #finish()} were called now. 171 */ 172 public abstract int currentFrameSize(); 173 174 /** 175 * Aligns the given frame size to the stack alignment size and return the aligned size. 176 * 177 * @param size the initial frame size to be aligned 178 * @return the aligned frame size 179 */ 180 protected abstract int alignFrameSize(int size); 181 182 /** 183 * Computes the final size of this frame. After this method has been called, methods that change 184 * the frame size cannot be called anymore, e.g., no more spill slots or outgoing arguments can 185 * be requested. 186 */ 187 public void finish() { 188 frameSize = currentFrameSize(); 189 if (frameSize > getRegisterConfig().getMaximumFrameSize()) { 190 throw new BailoutException("Frame size (%d) exceeded maximum allowed frame size (%d).", frameSize, getRegisterConfig().getMaximumFrameSize()); 191 } 192 } 193 194 /** 195 * Computes the offset of a stack slot relative to the frame register. 196 * 197 * @param slot a stack slot 198 * @return the offset of the stack slot 199 */ 200 public int offsetForStackSlot(StackSlot slot) { 201 if (slot.isInCallerFrame()) { 202 accessesCallerFrame = true; 203 } 204 return slot.getOffset(totalFrameSize()); 205 } 206 207 /** 208 * Gets the offset from the stack pointer to the stack area where callee-saved registers are 209 * stored. 210 * 211 * @return The offset to the callee save area (in bytes). 212 */ 213 public abstract int offsetToCalleeSaveArea(); 214 215 /** 216 * Informs the frame map that the compiled code calls a particular method, which may need stack 217 * space for outgoing arguments. 218 * 219 * @param cc The calling convention for the called method. 220 */ 221 public void callsMethod(CallingConvention cc) { 222 reserveOutgoing(cc.getStackSize()); 223 } 224 225 /** 226 * Reserves space for stack-based outgoing arguments. 227 * 228 * @param argsSize The amount of space (in bytes) to reserve for stack-based outgoing arguments. 229 */ 230 public void reserveOutgoing(int argsSize) { 231 assert frameSize == -1 : "frame size must not yet be fixed"; 232 outgoingSize = Math.max(outgoingSize, argsSize); 233 hasOutgoingStackArguments = hasOutgoingStackArguments || argsSize > 0; 234 } 235 236 /** 237 * Reserves a new spill slot in the frame of the method being compiled. The returned slot is 238 * aligned on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte 239 * boundary. 240 * 241 * @param kind The kind of the spill slot to be reserved. 242 * @param additionalOffset 243 * @return A spill slot denoting the reserved memory area. 244 */ 245 protected abstract StackSlot allocateNewSpillSlot(LIRKind kind, int additionalOffset); 246 247 /** 248 * Returns the spill slot size for the given {@link LIRKind}. The default value is the size in 249 * bytes for the target architecture. 250 * 251 * @param kind the {@link LIRKind} to be stored in the spill slot. 252 * @return the size in bytes 253 */ 254 public int spillSlotSize(LIRKind kind) { 255 return getTarget().getSizeInBytes(kind.getPlatformKind()); 256 } 257 258 /** 259 * Reserves a spill slot in the frame of the method being compiled. The returned slot is aligned 260 * on its natural alignment, i.e., an 8-byte spill slot is aligned at an 8-byte boundary, unless 261 * overridden by a subclass. 262 * 263 * @param kind The kind of the spill slot to be reserved. 264 * @return A spill slot denoting the reserved memory area. 265 */ 266 public StackSlot allocateSpillSlot(LIRKind kind) { 267 assert frameSize == -1 : "frame size must not yet be fixed"; 268 int size = spillSlotSize(kind); 269 spillSize = NumUtil.roundUp(spillSize + size, size); 270 return allocateNewSpillSlot(kind, 0); 271 } 272 273 /** 274 * Returns the size of the stack slot range for {@code slots} objects. 275 * 276 * @param slots The number of slots. 277 * @return The size in byte 278 */ 279 public int spillSlotRangeSize(int slots) { 280 return slots * getTarget().wordSize; 281 } 282 283 /** 284 * Reserves a number of contiguous slots in the frame of the method being compiled. If the 285 * requested number of slots is 0, this method returns {@code null}. 286 * 287 * @param slots the number of slots to reserve 288 * @param objects specifies the indexes of the object pointer slots. The caller is responsible 289 * for guaranteeing that each such object pointer slot is initialized before any 290 * instruction that uses a reference map. Without this guarantee, the garbage 291 * collector could see garbage object values. 292 * @return the first reserved stack slot (i.e., at the lowest address) 293 */ 294 public StackSlot allocateStackSlots(int slots, BitSet objects) { 295 assert frameSize == -1 : "frame size must not yet be fixed"; 296 if (slots == 0) { 297 return null; 298 } 299 spillSize += spillSlotRangeSize(slots); 300 301 if (!objects.isEmpty()) { 302 assert objects.length() <= slots; 303 StackSlot result = null; 304 for (int slotIndex = 0; slotIndex < slots; slotIndex++) { 305 StackSlot objectSlot = null; 306 if (objects.get(slotIndex)) { 307 objectSlot = allocateNewSpillSlot(LIRKind.reference(Kind.Object), slotIndex * getTarget().wordSize); 308 addObjectStackSlot(objectSlot); 309 } 310 if (slotIndex == 0) { 311 if (objectSlot != null) { 312 result = objectSlot; 313 } else { 314 result = allocateNewSpillSlot(LIRKind.value(getTarget().wordKind), 0); 315 } 316 } 317 } 318 assert result != null; 319 return result; 320 321 } else { 322 return allocateNewSpillSlot(LIRKind.value(getTarget().wordKind), 0); 323 } 324 } 325 326 protected void addObjectStackSlot(StackSlot objectSlot) { 327 objectStackSlots.add(objectSlot); 328 } 329 330 public ReferenceMapBuilder newReferenceMapBuilder() { 331 return referenceMapFactory.newReferenceMapBuilder(totalFrameSize()); 332 } 333}