1 /* 2 * Copyright (c) 2013, 2016, 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 package org.graalvm.compiler.hotspot.stubs; 24 25 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; 26 import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.PreferGraalStubs; 27 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readPendingDeoptimization; 28 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord; 29 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writePendingDeoptimization; 30 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeRegisterAsWord; 31 32 import org.graalvm.compiler.api.replacements.Fold; 33 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; 34 import org.graalvm.compiler.api.replacements.Snippet; 35 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; 36 import org.graalvm.compiler.core.common.LocationIdentity; 37 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 38 import org.graalvm.compiler.debug.GraalError; 39 import org.graalvm.compiler.graph.Node.ConstantNodeParameter; 40 import org.graalvm.compiler.graph.Node.NodeIntrinsic; 41 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 42 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; 43 import org.graalvm.compiler.hotspot.meta.HotSpotProviders; 44 import org.graalvm.compiler.hotspot.nodes.SaveAllRegistersNode; 45 import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; 46 import org.graalvm.compiler.hotspot.nodes.UncommonTrapCallNode; 47 import org.graalvm.compiler.nodes.NamedLocationIdentity; 48 import org.graalvm.compiler.word.Word; 49 50 import jdk.vm.ci.code.Register; 51 import jdk.vm.ci.code.TargetDescription; 52 53 /** 54 * Uncommon trap stub. 55 * 56 * This is the entry point for code which is returning to a de-optimized frame. 57 * 58 * The steps taken by this frame are as follows: 59 * 60 * <li>push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) and all 61 * potentially live registers (at a pollpoint many registers can be live). 62 * 63 * <li>call the C routine: Deoptimization::fetch_unroll_info (this function returns information 64 * about the number and size of interpreter frames which are equivalent to the frame which is being 65 * deoptimized) 66 * 67 * <li>deallocate the unpack frame, restoring only results values. Other volatile registers will now 68 * be captured in the vframeArray as needed. 69 * 70 * <li>deallocate the deoptimization frame 71 * 72 * <li>in a loop using the information returned in the previous step push new interpreter frames 73 * (take care to propagate the return values through each new frame pushed) 74 * 75 * <li>create a dummy "unpack_frame" and save the return values (O0, O1, F0) 76 * 77 * <li>call the C routine: Deoptimization::unpack_frames (this function lays out values on the 78 * interpreter frame which was just created) 79 * 80 * <li>deallocate the dummy unpack_frame 81 * 82 * <li>ensure that all the return values are correctly set and then do a return to the interpreter 83 * entry point 84 * 85 * <p> 86 * <b>ATTENTION: We cannot do any complicated operations e.g. logging via printf in this snippet 87 * because we change the current stack layout and so the code is very sensitive to register 88 * allocation.</b> 89 */ 90 public class UncommonTrapStub extends SnippetStub { 91 92 public static final LocationIdentity STACK_BANG_LOCATION = NamedLocationIdentity.mutable("stack bang"); 93 94 private final TargetDescription target; 95 96 public UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) { 97 super(UncommonTrapStub.class, "uncommonTrapHandler", providers, linkage); 98 this.target = target; 99 assert PreferGraalStubs.getValue(); 100 } 101 102 @Override 103 public boolean preservesRegisters() { 104 return false; 105 } 106 107 @Override 108 protected Object getConstantParameterValue(int index, String name) { 109 switch (index) { 110 case 0: 111 return providers.getRegisters().getThreadRegister(); 112 case 1: 113 return providers.getRegisters().getStackPointerRegister(); 114 default: 115 throw GraalError.shouldNotReachHere("unknown parameter " + name + " at index " + index); 116 } 117 } 118 119 /** 120 * Uncommon trap handler. 121 * 122 * We save the argument return registers. We call the first C routine, fetch_unroll_info(). This 123 * routine captures the return values and returns a structure which describes the current frame 124 * size and the sizes of all replacement frames. The current frame is compiled code and may 125 * contain many inlined functions, each with their own JVM state. We pop the current frame, then 126 * push all the new frames. Then we call the C routine unpack_frames() to populate these frames. 127 * Finally unpack_frames() returns us the new target address. Notice that callee-save registers 128 * are BLOWN here; they have already been captured in the vframeArray at the time the return PC 129 * was patched. 130 */ 131 @Snippet 132 private static void uncommonTrapHandler(@ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister) { 133 final Word thread = registerAsWord(threadRegister); 134 final long registerSaver = SaveAllRegistersNode.saveAllRegisters(); 135 136 final int actionAndReason = readPendingDeoptimization(thread); 137 writePendingDeoptimization(thread, -1); 138 139 final Word unrollBlock = UncommonTrapCallNode.uncommonTrap(registerSaver, actionAndReason, deoptimizationUnpackUncommonTrap(INJECTED_VMCONFIG)); 140 141 DeoptimizationStub.deoptimizationCommon(stackPointerRegister, thread, registerSaver, unrollBlock); 142 } 143 144 /** 145 * Reads the value of the passed register as a Word. 146 */ 147 private static Word readRegister(Register register) { 148 return registerAsWord(register, false, false); 149 } 150 151 /** 152 * Writes the value of the passed register. 153 * 154 * @param value value the register should be set to 155 */ 156 private static void writeRegister(Register register, Word value) { 157 writeRegisterAsWord(register, value); 158 } 159 160 @Fold 161 static int stackShadowPages(@InjectedParameter GraalHotSpotVMConfig config) { 162 return config.useStackBanging ? config.stackShadowPages : 0; 163 } 164 165 /** 166 * Returns the stack bias for the host architecture. 167 * 168 * @deprecated This method should go away as soon as JDK-8032410 hits the Graal repository. 169 * 170 * @return stack bias 171 */ 172 @Deprecated 173 @Fold 174 static int stackBias(@InjectedParameter GraalHotSpotVMConfig config) { 175 return config.stackBias; 176 } 177 178 @Fold 179 static int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset(@InjectedParameter GraalHotSpotVMConfig config) { 180 return config.deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset; 181 } 182 183 @Fold 184 static int deoptimizationUnrollBlockCallerAdjustmentOffset(@InjectedParameter GraalHotSpotVMConfig config) { 185 return config.deoptimizationUnrollBlockCallerAdjustmentOffset; 186 } 187 188 @Fold 189 static int deoptimizationUnrollBlockNumberOfFramesOffset(@InjectedParameter GraalHotSpotVMConfig config) { 190 return config.deoptimizationUnrollBlockNumberOfFramesOffset; 191 } 192 193 @Fold 194 static int deoptimizationUnrollBlockTotalFrameSizesOffset(@InjectedParameter GraalHotSpotVMConfig config) { 195 return config.deoptimizationUnrollBlockTotalFrameSizesOffset; 196 } 197 198 @Fold 199 static int deoptimizationUnrollBlockFrameSizesOffset(@InjectedParameter GraalHotSpotVMConfig config) { 200 return config.deoptimizationUnrollBlockFrameSizesOffset; 201 } 202 203 @Fold 204 static int deoptimizationUnrollBlockFramePcsOffset(@InjectedParameter GraalHotSpotVMConfig config) { 205 return config.deoptimizationUnrollBlockFramePcsOffset; 206 } 207 208 @Fold 209 static int deoptimizationUnrollBlockInitialInfoOffset(@InjectedParameter GraalHotSpotVMConfig config) { 210 return config.deoptimizationUnrollBlockInitialInfoOffset; 211 } 212 213 @Fold 214 static int deoptimizationUnpackDeopt(@InjectedParameter GraalHotSpotVMConfig config) { 215 return config.deoptimizationUnpackDeopt; 216 } 217 218 @Fold 219 static int deoptimizationUnpackUncommonTrap(@InjectedParameter GraalHotSpotVMConfig config) { 220 return config.deoptimizationUnpackUncommonTrap; 221 } 222 223 @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true) 224 public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode); 225 }