1 /* 2 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.lir.amd64; 26 27 import static jdk.vm.ci.code.ValueUtil.asStackSlot; 28 29 import org.graalvm.compiler.core.common.NumUtil; 30 import org.graalvm.compiler.core.common.LIRKind; 31 import org.graalvm.compiler.lir.framemap.FrameMap; 32 33 import jdk.vm.ci.amd64.AMD64Kind; 34 import jdk.vm.ci.code.CodeCacheProvider; 35 import jdk.vm.ci.code.RegisterConfig; 36 import jdk.vm.ci.code.StackSlot; 37 38 /** 39 * AMD64 specific frame map. 40 * 41 * This is the format of an AMD64 stack frame: 42 * 43 * <pre> 44 * Base Contents 45 * 46 * : : ----- 47 * caller | incoming overflow argument n | ^ 48 * frame : ... : | positive 49 * | incoming overflow argument 0 | | offsets 50 * ---------+--------------------------------+--------------------- 51 * | return address | | ^ 52 * current +--------------------------------+ | | ----- 53 * frame | | | | ^ 54 * : callee save area : | | | 55 * | | | | | 56 * +--------------------------------+ | | | 57 * | spill slot 0 | | negative | | 58 * : ... : v offsets | | 59 * | spill slot n | ----- total frame 60 * +--------------------------------+ frame size 61 * | alignment padding | size | 62 * +--------------------------------+ ----- | | 63 * | outgoing overflow argument n | ^ | | 64 * : ... : | positive | | 65 * | outgoing overflow argument 0 | | offsets v v 66 * %sp--> +--------------------------------+--------------------------- 67 * 68 * </pre> 69 * 70 * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size of such 71 * a block may be greater than the size of a normal spill slot or the word size. 72 * <p> 73 * A runtime can reserve space at the beginning of the overflow argument area. The calling 74 * convention can specify that the first overflow stack argument is not at offset 0, but at a 75 * specified offset. Use {@link CodeCacheProvider#getMinimumOutgoingSize()} to make sure that 76 * call-free methods also have this space reserved. Then the VM can use the memory at offset 0 77 * relative to the stack pointer. 78 */ 79 public class AMD64FrameMap extends FrameMap { 80 81 private StackSlot rbpSpillSlot; 82 83 public AMD64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) { 84 this(codeCache, registerConfig, referenceMapFactory, false); 85 } 86 87 public AMD64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory, boolean useBasePointer) { 88 super(codeCache, registerConfig, referenceMapFactory); 89 // (negative) offset relative to sp + total frame size 90 initialSpillSize = returnAddressSize() + (useBasePointer ? getTarget().arch.getWordSize() : 0); 91 spillSize = initialSpillSize; 92 } 93 94 @Override 95 public int totalFrameSize() { 96 int result = frameSize() + initialSpillSize; 97 assert result % getTarget().stackAlignment == 0 : "Total frame size not aligned: " + result; 98 return result; 99 } 100 101 @Override 102 public int currentFrameSize() { 103 return alignFrameSize(outgoingSize + spillSize - initialSpillSize); 104 } 105 106 @Override 107 protected int alignFrameSize(int size) { 108 return NumUtil.roundUp(size + initialSpillSize, getTarget().stackAlignment) - initialSpillSize; 109 } 110 111 @Override 112 public int offsetForStackSlot(StackSlot slot) { 113 // @formatter:off 114 assert (!slot.getRawAddFrameSize() && slot.getRawOffset() < outgoingSize) || 115 (slot.getRawAddFrameSize() && slot.getRawOffset() < 0 && -slot.getRawOffset() <= spillSize) || 116 (slot.getRawAddFrameSize() && slot.getRawOffset() >= 0) : 117 String.format("RawAddFrameSize: %b RawOffset: 0x%x spillSize: 0x%x outgoingSize: 0x%x", slot.getRawAddFrameSize(), slot.getRawOffset(), spillSize, outgoingSize); 118 // @formatter:on 119 return super.offsetForStackSlot(slot); 120 } 121 122 /** 123 * For non-leaf methods, RBP is preserved in the special stack slot required by the HotSpot 124 * runtime for walking/inspecting frames of such methods. 125 */ 126 StackSlot allocateRBPSpillSlot() { 127 assert spillSize == initialSpillSize : "RBP spill slot must be the first allocated stack slots"; 128 rbpSpillSlot = allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); 129 assert asStackSlot(rbpSpillSlot).getRawOffset() == -16 : asStackSlot(rbpSpillSlot).getRawOffset(); 130 return rbpSpillSlot; 131 } 132 133 void freeRBPSpillSlot() { 134 int size = spillSlotSize(LIRKind.value(AMD64Kind.QWORD)); 135 assert spillSize == NumUtil.roundUp(initialSpillSize + size, size) : "RBP spill slot can not be freed after allocation other stack slots"; 136 spillSize = initialSpillSize; 137 } 138 139 public StackSlot allocateDeoptimizationRescueSlot() { 140 assert spillSize == initialSpillSize || spillSize == initialSpillSize + 141 spillSlotSize(LIRKind.value(AMD64Kind.QWORD)) : "Deoptimization rescue slot must be the first or second (if there is an RBP spill slot) stack slot"; 142 return allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); 143 } 144 }