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