1 /* 2 * Copyright (c) 2012, 2019, 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.hotspot.amd64; 26 27 import static jdk.vm.ci.amd64.AMD64.rbp; 28 import static jdk.vm.ci.code.ValueUtil.isStackSlot; 29 import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER; 30 31 import org.graalvm.compiler.api.replacements.Snippet; 32 import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder; 33 import org.graalvm.compiler.core.amd64.AMD64NodeMatchRules; 34 import org.graalvm.compiler.core.common.LIRKind; 35 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 36 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 37 import org.graalvm.compiler.core.gen.DebugInfoBuilder; 38 import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; 39 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; 40 import org.graalvm.compiler.hotspot.HotSpotLockStack; 41 import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder; 42 import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode; 43 import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode; 44 import org.graalvm.compiler.lir.LIRFrameState; 45 import org.graalvm.compiler.lir.Variable; 46 import org.graalvm.compiler.lir.amd64.AMD64BreakpointOp; 47 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 48 import org.graalvm.compiler.nodes.BreakpointNode; 49 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; 50 import org.graalvm.compiler.nodes.DirectCallTargetNode; 51 import org.graalvm.compiler.nodes.FullInfopointNode; 52 import org.graalvm.compiler.nodes.IndirectCallTargetNode; 53 import org.graalvm.compiler.nodes.NodeView; 54 import org.graalvm.compiler.nodes.ParameterNode; 55 import org.graalvm.compiler.nodes.SafepointNode; 56 import org.graalvm.compiler.nodes.StructuredGraph; 57 import org.graalvm.compiler.nodes.ValueNode; 58 import org.graalvm.compiler.nodes.spi.NodeValueMap; 59 import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; 60 import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode; 61 62 import jdk.vm.ci.amd64.AMD64; 63 import jdk.vm.ci.amd64.AMD64Kind; 64 import jdk.vm.ci.code.BytecodeFrame; 65 import jdk.vm.ci.code.CallingConvention; 66 import jdk.vm.ci.code.Register; 67 import jdk.vm.ci.code.RegisterValue; 68 import jdk.vm.ci.code.StackSlot; 69 import jdk.vm.ci.code.ValueUtil; 70 import jdk.vm.ci.hotspot.HotSpotCallingConventionType; 71 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; 72 import jdk.vm.ci.meta.AllocatableValue; 73 import jdk.vm.ci.meta.JavaKind; 74 import jdk.vm.ci.meta.JavaType; 75 import jdk.vm.ci.meta.ResolvedJavaMethod; 76 import jdk.vm.ci.meta.Value; 77 import org.graalvm.compiler.replacements.nodes.ArrayRegionEqualsNode; 78 79 /** 80 * LIR generator specialized for AMD64 HotSpot. 81 */ 82 public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements HotSpotNodeLIRBuilder { 83 84 public AMD64HotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) { 85 super(graph, gen, nodeMatchRules); 86 assert gen instanceof AMD64HotSpotLIRGenerator; 87 assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder; 88 ((AMD64HotSpotLIRGenerator) gen).setDebugInfoBuilder(((HotSpotDebugInfoBuilder) getDebugInfoBuilder())); 89 } 90 91 private AMD64HotSpotLIRGenerator getGen() { 92 return (AMD64HotSpotLIRGenerator) gen; 93 } 94 95 @Override 96 protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) { 97 HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(AMD64Kind.QWORD)); 98 return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack, (HotSpotLIRGenerator) gen); 99 } 100 101 @Override 102 protected void emitPrologue(StructuredGraph graph) { 103 104 CallingConvention incomingArguments = gen.getResult().getCallingConvention(); 105 106 Value[] params = new Value[incomingArguments.getArgumentCount() + 1]; 107 for (int i = 0; i < params.length - 1; i++) { 108 params[i] = incomingArguments.getArgument(i); 109 if (isStackSlot(params[i])) { 110 StackSlot slot = ValueUtil.asStackSlot(params[i]); 111 if (slot.isInCallerFrame() && !gen.getResult().getLIR().hasArgInCallerFrame()) { 112 gen.getResult().getLIR().setHasArgInCallerFrame(); 113 } 114 } 115 } 116 params[params.length - 1] = rbp.asValue(LIRKind.value(AMD64Kind.QWORD)); 117 118 gen.emitIncomingValues(params); 119 120 getGen().emitSaveRbp(); 121 122 getGen().append(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack()); 123 124 for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) { 125 Value paramValue = params[param.index()]; 126 assert paramValue.getValueKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp(NodeView.DEFAULT))) : paramValue.getValueKind() + " != " + param.stamp(NodeView.DEFAULT); 127 setResult(param, gen.emitMove(paramValue)); 128 } 129 } 130 131 @Override 132 public void visitSafepointNode(SafepointNode i) { 133 LIRFrameState info = state(i); 134 Register thread = getGen().getProviders().getRegisters().getThreadRegister(); 135 append(new AMD64HotSpotSafepointOp(info, getGen().config, this, thread)); 136 } 137 138 @Override 139 protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { 140 InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); 141 if (invokeKind.isIndirect()) { 142 append(new AMD64HotspotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); 143 } else { 144 assert invokeKind.isDirect(); 145 HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); 146 assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method."; 147 append(new AMD64HotSpotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); 148 } 149 } 150 151 @Override 152 protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { 153 if (callTarget instanceof HotSpotIndirectCallTargetNode) { 154 Value metaspaceMethodSrc = operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()); 155 Value targetAddressSrc = operand(callTarget.computedAddress()); 156 AllocatableValue metaspaceMethodDst = AMD64.rbx.asValue(metaspaceMethodSrc.getValueKind()); 157 AllocatableValue targetAddressDst = AMD64.rax.asValue(targetAddressSrc.getValueKind()); 158 gen.emitMove(metaspaceMethodDst, metaspaceMethodSrc); 159 gen.emitMove(targetAddressDst, targetAddressSrc); 160 append(new AMD64IndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethodDst, targetAddressDst, callState, getGen().config)); 161 } else { 162 super.emitIndirectCall(callTarget, result, parameters, temps, callState); 163 } 164 } 165 166 @Override 167 public void emitPatchReturnAddress(ValueNode address) { 168 append(new AMD64HotSpotPatchReturnAddressOp(gen.load(operand(address)))); 169 } 170 171 @Override 172 public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { 173 Variable handler = gen.load(operand(handlerInCallerPc)); 174 ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); 175 CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); 176 assert outgoingCc.getArgumentCount() == 2; 177 RegisterValue exceptionFixed = (RegisterValue) outgoingCc.getArgument(0); 178 RegisterValue exceptionPcFixed = (RegisterValue) outgoingCc.getArgument(1); 179 gen.emitMove(exceptionFixed, operand(exception)); 180 gen.emitMove(exceptionPcFixed, operand(exceptionPc)); 181 Register thread = getGen().getProviders().getRegisters().getThreadRegister(); 182 AMD64HotSpotJumpToExceptionHandlerInCallerOp op = new AMD64HotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, getGen().config.threadIsMethodHandleReturnOffset, 183 thread); 184 append(op); 185 } 186 187 @Override 188 public void visitFullInfopointNode(FullInfopointNode i) { 189 if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) { 190 i.getDebug().log("Ignoring InfopointNode for AFTER_BCI"); 191 } else { 192 super.visitFullInfopointNode(i); 193 } 194 } 195 196 @Override 197 public void visitBreakpointNode(BreakpointNode node) { 198 JavaType[] sig = new JavaType[node.arguments().size()]; 199 for (int i = 0; i < sig.length; i++) { 200 sig[i] = node.arguments().get(i).stamp(NodeView.DEFAULT).javaType(gen.getMetaAccess()); 201 } 202 203 Value[] parameters = visitInvokeArguments(gen.getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), node.arguments()); 204 append(new AMD64BreakpointOp(parameters)); 205 } 206 207 private ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) { 208 return getGen().getForeignCalls().lookupForeignCall(descriptor); 209 } 210 211 @Override 212 public ForeignCallLinkage lookupGraalStub(ValueNode valueNode) { 213 ResolvedJavaMethod method = valueNode.graph().method(); 214 if (method == null || method.getAnnotation(Snippet.class) != null) { 215 // Emit assembly for snippet stubs 216 return null; 217 } 218 219 if (valueNode instanceof ArrayEqualsNode) { 220 ArrayEqualsNode arrayEqualsNode = (ArrayEqualsNode) valueNode; 221 JavaKind kind = arrayEqualsNode.getKind(); 222 ValueNode length = arrayEqualsNode.getLength(); 223 224 if (length.isConstant()) { 225 int constantLength = length.asJavaConstant().asInt(); 226 if (constantLength >= 0 && constantLength * kind.getByteCount() < 2 * getGen().getMaxVectorSize()) { 227 // Yield constant-length arrays comparison assembly 228 return null; 229 } 230 } 231 232 switch (kind) { 233 case Boolean: 234 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_BOOLEAN_ARRAY_EQUALS); 235 case Byte: 236 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_BYTE_ARRAY_EQUALS); 237 case Char: 238 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS); 239 case Short: 240 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_SHORT_ARRAY_EQUALS); 241 case Int: 242 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_INT_ARRAY_EQUALS); 243 case Long: 244 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_LONG_ARRAY_EQUALS); 245 case Float: 246 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_FLOAT_ARRAY_EQUALS); 247 case Double: 248 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_DOUBLE_ARRAY_EQUALS); 249 default: 250 return null; 251 } 252 } else if (valueNode instanceof ArrayCompareToNode) { 253 ArrayCompareToNode arrayCompareToNode = (ArrayCompareToNode) valueNode; 254 JavaKind kind1 = arrayCompareToNode.getKind1(); 255 JavaKind kind2 = arrayCompareToNode.getKind2(); 256 257 if (kind1 == JavaKind.Byte) { 258 if (kind2 == JavaKind.Byte) { 259 return lookupForeignCall(AMD64ArrayCompareToStub.STUB_BYTE_ARRAY_COMPARE_TO_BYTE_ARRAY); 260 } else if (kind2 == JavaKind.Char) { 261 return lookupForeignCall(AMD64ArrayCompareToStub.STUB_BYTE_ARRAY_COMPARE_TO_CHAR_ARRAY); 262 } 263 } else if (kind1 == JavaKind.Char) { 264 if (kind2 == JavaKind.Byte) { 265 return lookupForeignCall(AMD64ArrayCompareToStub.STUB_CHAR_ARRAY_COMPARE_TO_BYTE_ARRAY); 266 } else if (kind2 == JavaKind.Char) { 267 return lookupForeignCall(AMD64ArrayCompareToStub.STUB_CHAR_ARRAY_COMPARE_TO_CHAR_ARRAY); 268 } 269 } 270 } else if (valueNode instanceof ArrayRegionEqualsNode) { 271 ArrayRegionEqualsNode arrayRegionEqualsNode = (ArrayRegionEqualsNode) valueNode; 272 JavaKind kind1 = arrayRegionEqualsNode.getKind1(); 273 JavaKind kind2 = arrayRegionEqualsNode.getKind2(); 274 ValueNode length = arrayRegionEqualsNode.getLength(); 275 276 if (length.isConstant()) { 277 int constantLength = length.asJavaConstant().asInt(); 278 if (constantLength >= 0 && constantLength * (Math.max(kind1.getByteCount(), kind2.getByteCount())) < 2 * getGen().getMaxVectorSize()) { 279 // Yield constant-length arrays comparison assembly 280 return null; 281 } 282 } 283 284 if (kind1 == kind2) { 285 switch (kind1) { 286 case Byte: 287 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_BYTE_ARRAY_EQUALS_DIRECT); 288 case Char: 289 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS_DIRECT); 290 default: 291 return null; 292 } 293 } else if (kind1 == JavaKind.Char && kind2 == JavaKind.Byte) { 294 return lookupForeignCall(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS_BYTE_ARRAY); 295 } 296 } 297 298 return null; 299 } 300 }