1 /* 2 * Copyright (c) 2013, 2018, 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.aarch64; 26 27 import static java.lang.reflect.Modifier.isStatic; 28 import static jdk.vm.ci.aarch64.AArch64.lr; 29 import static jdk.vm.ci.aarch64.AArch64.r10; 30 import static jdk.vm.ci.aarch64.AArch64.sp; 31 import static jdk.vm.ci.aarch64.AArch64.zr; 32 import static jdk.vm.ci.code.ValueUtil.asRegister; 33 import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp; 34 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; 35 import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; 36 37 import jdk.internal.vm.compiler.collections.EconomicSet; 38 import org.graalvm.compiler.asm.Assembler; 39 import org.graalvm.compiler.asm.Label; 40 import org.graalvm.compiler.asm.aarch64.AArch64Address; 41 import org.graalvm.compiler.asm.aarch64.AArch64Assembler; 42 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; 43 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister; 44 import org.graalvm.compiler.code.CompilationResult; 45 import org.graalvm.compiler.core.aarch64.AArch64NodeMatchRules; 46 import org.graalvm.compiler.core.common.CompilationIdentifier; 47 import org.graalvm.compiler.core.common.LIRKind; 48 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; 49 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 50 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 51 import org.graalvm.compiler.hotspot.HotSpotDataBuilder; 52 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; 53 import org.graalvm.compiler.hotspot.HotSpotHostBackend; 54 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; 55 import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; 56 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; 57 import org.graalvm.compiler.hotspot.meta.HotSpotProviders; 58 import org.graalvm.compiler.hotspot.stubs.Stub; 59 import org.graalvm.compiler.lir.LIR; 60 import org.graalvm.compiler.lir.aarch64.AArch64Call; 61 import org.graalvm.compiler.lir.aarch64.AArch64FrameMap; 62 import org.graalvm.compiler.lir.aarch64.AArch64FrameMapBuilder; 63 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 64 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 65 import org.graalvm.compiler.lir.asm.DataBuilder; 66 import org.graalvm.compiler.lir.asm.FrameContext; 67 import org.graalvm.compiler.lir.framemap.FrameMap; 68 import org.graalvm.compiler.lir.framemap.FrameMapBuilder; 69 import org.graalvm.compiler.lir.gen.LIRGenerationResult; 70 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 71 import org.graalvm.compiler.nodes.StructuredGraph; 72 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 73 74 import jdk.vm.ci.aarch64.AArch64Kind; 75 import jdk.vm.ci.code.CallingConvention; 76 import jdk.vm.ci.code.Register; 77 import jdk.vm.ci.code.RegisterConfig; 78 import jdk.vm.ci.code.StackSlot; 79 import jdk.vm.ci.hotspot.HotSpotCallingConventionType; 80 import jdk.vm.ci.hotspot.HotSpotSentinelConstant; 81 import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig; 82 import jdk.vm.ci.meta.JavaKind; 83 import jdk.vm.ci.meta.JavaType; 84 import jdk.vm.ci.meta.ResolvedJavaMethod; 85 86 /** 87 * HotSpot AArch64 specific backend. 88 */ 89 public class AArch64HotSpotBackend extends HotSpotHostBackend { 90 91 public AArch64HotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { 92 super(config, runtime, providers); 93 } 94 95 @Override 96 public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) { 97 RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; 98 return new AArch64FrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull); 99 } 100 101 @Override 102 public FrameMap newFrameMap(RegisterConfig registerConfig) { 103 return new AArch64FrameMap(getCodeCache(), registerConfig, this); 104 } 105 106 @Override 107 public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) { 108 return new AArch64HotSpotLIRGenerator(getProviders(), config, lirGenRes); 109 } 110 111 @Override 112 public LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, Object stub) { 113 return new HotSpotLIRGenerationResult(compilationId, lir, frameMapBuilder, makeCallingConvention(graph, (Stub) stub), stub, config.requiresReservedStackCheck(graph.getMethods())); 114 } 115 116 @Override 117 public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { 118 return new AArch64HotSpotNodeLIRBuilder(graph, lirGen, new AArch64NodeMatchRules(lirGen)); 119 } 120 121 @Override 122 protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) { 123 AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm; 124 try (ScratchRegister sc = masm.getScratchRegister()) { 125 Register scratch = sc.getRegister(); 126 AArch64Address address = masm.makeAddress(sp, -bangOffset, scratch, 8, /* allowOverwrite */false); 127 masm.str(64, zr, address); 128 } 129 } 130 131 private class HotSpotFrameContext implements FrameContext { 132 final boolean isStub; 133 134 HotSpotFrameContext(boolean isStub) { 135 this.isStub = isStub; 136 } 137 138 @Override 139 public void enter(CompilationResultBuilder crb) { 140 FrameMap frameMap = crb.frameMap; 141 final int frameSize = frameMap.frameSize(); 142 final int totalFrameSize = frameMap.totalFrameSize(); 143 assert frameSize + 2 * crb.target.arch.getWordSize() == totalFrameSize : "total framesize should be framesize + 2 words"; 144 AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm; 145 if (!isStub) { 146 emitStackOverflowCheck(crb); 147 } 148 crb.blockComment("[method prologue]"); 149 150 try (ScratchRegister sc = masm.getScratchRegister()) { 151 int wordSize = crb.target.arch.getWordSize(); 152 Register rscratch1 = sc.getRegister(); 153 assert totalFrameSize > 0; 154 if (frameSize < 1 << 9) { 155 masm.sub(64, sp, sp, totalFrameSize); 156 masm.stp(64, fp, lr, AArch64Address.createScaledImmediateAddress(sp, frameSize / wordSize)); 157 } else { 158 masm.stp(64, fp, lr, AArch64Address.createPreIndexedImmediateAddress(sp, -2)); 159 if (frameSize < 1 << 12) { 160 masm.sub(64, sp, sp, totalFrameSize - 2 * wordSize); 161 } else { 162 masm.mov(rscratch1, totalFrameSize - 2 * wordSize); 163 masm.sub(64, sp, sp, rscratch1); 164 } 165 } 166 } 167 if (ZapStackOnMethodEntry.getValue(crb.getOptions())) { 168 try (ScratchRegister sc = masm.getScratchRegister()) { 169 Register scratch = sc.getRegister(); 170 int longSize = 8; 171 masm.mov(64, scratch, sp); 172 AArch64Address address = AArch64Address.createPostIndexedImmediateAddress(scratch, longSize); 173 try (ScratchRegister sc2 = masm.getScratchRegister()) { 174 Register value = sc2.getRegister(); 175 masm.mov(value, 0xBADDECAFFC0FFEEL); 176 for (int i = 0; i < frameSize; i += longSize) { 177 masm.str(64, value, address); 178 } 179 } 180 181 } 182 } 183 crb.blockComment("[code body]"); 184 } 185 186 @Override 187 public void leave(CompilationResultBuilder crb) { 188 AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm; 189 FrameMap frameMap = crb.frameMap; 190 final int totalFrameSize = frameMap.totalFrameSize(); 191 192 crb.blockComment("[method epilogue]"); 193 try (ScratchRegister sc = masm.getScratchRegister()) { 194 int wordSize = crb.target.arch.getWordSize(); 195 Register rscratch1 = sc.getRegister(); 196 final int frameSize = frameMap.frameSize(); 197 assert totalFrameSize > 0; 198 if (frameSize < 1 << 9) { 199 masm.ldp(64, fp, lr, AArch64Address.createScaledImmediateAddress(sp, frameSize / wordSize)); 200 masm.add(64, sp, sp, totalFrameSize); 201 } else { 202 if (frameSize < 1 << 12) { 203 masm.add(64, sp, sp, totalFrameSize - 2 * wordSize); 204 } else { 205 masm.mov(rscratch1, totalFrameSize - 2 * wordSize); 206 masm.add(64, sp, sp, rscratch1); 207 } 208 masm.ldp(64, fp, lr, AArch64Address.createPostIndexedImmediateAddress(sp, 2)); 209 } 210 } 211 212 } 213 214 @Override 215 public boolean hasFrame() { 216 return true; 217 } 218 219 } 220 221 @Override 222 protected Assembler createAssembler(FrameMap frameMap) { 223 return new AArch64MacroAssembler(getTarget()); 224 } 225 226 @Override 227 public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRen, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { 228 HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRen; 229 LIR lir = gen.getLIR(); 230 assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; 231 232 Stub stub = gen.getStub(); 233 Assembler masm = createAssembler(frameMap); 234 HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null); 235 236 DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget()); 237 CompilationResultBuilder crb = factory.createBuilder(getCodeCache(), getForeignCalls(), frameMap, masm, dataBuilder, frameContext, lir.getOptions(), lir.getDebug(), compilationResult, 238 Register.None); 239 crb.setTotalFrameSize(frameMap.totalFrameSize()); 240 crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize()); 241 StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot(); 242 if (deoptimizationRescueSlot != null && stub == null) { 243 crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot); 244 } 245 246 if (stub != null) { 247 EconomicSet<Register> destroyedCallerRegisters = gatherDestroyedCallerRegisters(lir); 248 updateStub(stub, destroyedCallerRegisters, gen.getCalleeSaveInfo(), frameMap); 249 } 250 return crb; 251 } 252 253 @Override 254 public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { 255 AArch64MacroAssembler masm = (AArch64MacroAssembler) crb.asm; 256 FrameMap frameMap = crb.frameMap; 257 RegisterConfig regConfig = frameMap.getRegisterConfig(); 258 Label verifiedStub = new Label(); 259 260 emitCodePrefix(crb, installedCodeOwner, masm, regConfig, verifiedStub); 261 emitCodeBody(crb, lir, masm); 262 emitCodeSuffix(crb, masm, frameMap); 263 } 264 265 private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod installedCodeOwner, AArch64MacroAssembler masm, RegisterConfig regConfig, Label verifiedStub) { 266 HotSpotProviders providers = getProviders(); 267 if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) { 268 crb.recordMark(config.MARKID_UNVERIFIED_ENTRY); 269 CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, this); 270 // See definition of IC_Klass in c1_LIRAssembler_aarch64.cpp 271 // equal to scratch(1) careful! 272 Register inlineCacheKlass = AArch64HotSpotRegisterConfig.inlineCacheRegister; 273 Register receiver = asRegister(cc.getArgument(0)); 274 int transferSize = config.useCompressedClassPointers ? 4 : 8; 275 AArch64Address klassAddress = masm.makeAddress(receiver, config.hubOffset, transferSize); 276 277 // Are r10 and r11 available scratch registers here? One would hope so. 278 Register klass = r10; 279 if (config.useCompressedClassPointers) { 280 masm.ldr(32, klass, klassAddress); 281 AArch64HotSpotMove.decodeKlassPointer(crb, masm, klass, klass, config.getKlassEncoding(), config); 282 } else { 283 masm.ldr(64, klass, klassAddress); 284 } 285 masm.cmp(64, inlineCacheKlass, klass); 286 /* 287 * Conditional jumps have a much lower range than unconditional ones, which can be a 288 * problem because the miss handler could be out of range. 289 */ 290 masm.branchConditionally(AArch64Assembler.ConditionFlag.EQ, verifiedStub); 291 AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(IC_MISS_HANDLER)); 292 } 293 masm.align(config.codeEntryAlignment); 294 crb.recordMark(config.MARKID_OSR_ENTRY); 295 masm.bind(verifiedStub); 296 crb.recordMark(config.MARKID_VERIFIED_ENTRY); 297 298 if (GeneratePIC.getValue(crb.getOptions())) { 299 // Check for method state 300 HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; 301 if (!frameContext.isStub) { 302 crb.recordInlineDataInCodeWithNote(new HotSpotSentinelConstant(LIRKind.value(AArch64Kind.QWORD), JavaKind.Long), HotSpotConstantLoadAction.MAKE_NOT_ENTRANT); 303 try (ScratchRegister sc = masm.getScratchRegister()) { 304 Register scratch = sc.getRegister(); 305 masm.addressOf(scratch); 306 masm.ldr(64, scratch, AArch64Address.createBaseRegisterOnlyAddress(scratch)); 307 Label noCall = new Label(); 308 masm.cbz(64, scratch, noCall); 309 AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(WRONG_METHOD_HANDLER)); 310 masm.bind(noCall); 311 } 312 } 313 } 314 } 315 316 private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) { 317 emitInvalidatePlaceholder(crb, masm); 318 crb.emit(lir); 319 } 320 321 /** 322 * Insert a nop at the start of the prolog so we can patch in a branch if we need to invalidate 323 * the method later. 324 * 325 * @see "http://mail.openjdk.java.net/pipermail/aarch64-port-dev/2013-September/000273.html" 326 */ 327 public static void emitInvalidatePlaceholder(CompilationResultBuilder crb, AArch64MacroAssembler masm) { 328 if (!GeneratePIC.getValue(crb.getOptions())) { 329 crb.blockComment("[nop for method invalidation]"); 330 masm.nop(); 331 } 332 } 333 334 private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) { 335 HotSpotProviders providers = getProviders(); 336 HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; 337 if (!frameContext.isStub) { 338 HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls(); 339 try (ScratchRegister sc = masm.getScratchRegister()) { 340 Register scratch = sc.getRegister(); 341 crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); 342 ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER); 343 Register helper = AArch64Call.isNearCall(linkage) ? null : scratch; 344 AArch64Call.directCall(crb, masm, linkage, helper, null); 345 } 346 crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); 347 ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER); 348 masm.adr(lr, 0); // Warning: the argument is an offset from the instruction! 349 AArch64Call.directJmp(crb, masm, linkage); 350 } else { 351 // No need to emit the stubs for entries back into the method since 352 // it has no calls that can cause such "return" entries 353 assert !frameMap.accessesCallerFrame(); 354 } 355 } 356 357 @Override 358 public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) { 359 RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; 360 return new AArch64HotSpotRegisterAllocationConfig(registerConfigNonNull, allocationRestrictedTo); 361 } 362 363 @Override 364 public EconomicSet<Register> translateToCallerRegisters(EconomicSet<Register> calleeRegisters) { 365 return calleeRegisters; 366 } 367 }