Stub.java revision 12968:4d8a004e5c6d
1/* 2 * Copyright (c) 2012, 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 */ 23package org.graalvm.compiler.hotspot.stubs; 24 25import static org.graalvm.compiler.core.GraalCompiler.emitBackEnd; 26import static org.graalvm.compiler.core.GraalCompiler.emitFrontEnd; 27import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; 28import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; 29import static org.graalvm.util.CollectionsUtil.allMatch; 30 31import java.util.ListIterator; 32 33import org.graalvm.compiler.code.CompilationResult; 34import org.graalvm.compiler.core.common.CompilationIdentifier; 35import org.graalvm.compiler.core.target.Backend; 36import org.graalvm.compiler.debug.Debug; 37import org.graalvm.compiler.debug.Debug.Scope; 38import org.graalvm.compiler.debug.internal.DebugScope; 39import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; 40import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; 41import org.graalvm.compiler.hotspot.meta.HotSpotProviders; 42import org.graalvm.compiler.hotspot.nodes.StubStartNode; 43import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 44import org.graalvm.compiler.lir.phases.LIRPhase; 45import org.graalvm.compiler.lir.phases.LIRSuites; 46import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; 47import org.graalvm.compiler.lir.profiling.MoveProfilingPhase; 48import org.graalvm.compiler.nodes.StructuredGraph; 49import org.graalvm.compiler.options.OptionValues; 50import org.graalvm.compiler.phases.OptimisticOptimizations; 51import org.graalvm.compiler.phases.PhaseSuite; 52import org.graalvm.compiler.phases.tiers.Suites; 53import org.graalvm.util.EconomicSet; 54 55import jdk.vm.ci.code.CodeCacheProvider; 56import jdk.vm.ci.code.InstalledCode; 57import jdk.vm.ci.code.Register; 58import jdk.vm.ci.code.RegisterConfig; 59import jdk.vm.ci.code.site.Call; 60import jdk.vm.ci.code.site.ConstantReference; 61import jdk.vm.ci.code.site.DataPatch; 62import jdk.vm.ci.code.site.Infopoint; 63import jdk.vm.ci.hotspot.HotSpotCompiledCode; 64import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; 65import jdk.vm.ci.meta.DefaultProfilingInfo; 66import jdk.vm.ci.meta.ResolvedJavaMethod; 67import jdk.vm.ci.meta.TriState; 68 69//JaCoCo Exclude 70 71/** 72 * Base class for implementing some low level code providing the out-of-line slow path for a snippet 73 * and/or a callee saved call to a HotSpot C/C++ runtime function or even a another compiled Java 74 * method. 75 */ 76public abstract class Stub { 77 78 /** 79 * The linkage information for a call to this stub from compiled code. 80 */ 81 protected final HotSpotForeignCallLinkage linkage; 82 83 /** 84 * The code installed for the stub. 85 */ 86 protected InstalledCode code; 87 88 /** 89 * The registers destroyed by this stub (from the caller's perspective). 90 */ 91 private EconomicSet<Register> destroyedCallerRegisters; 92 93 private static boolean checkRegisterSetEquivalency(EconomicSet<Register> a, EconomicSet<Register> b) { 94 if (a == b) { 95 return true; 96 } 97 if (a.size() != b.size()) { 98 return false; 99 } 100 return allMatch(a, e -> b.contains(e)); 101 } 102 103 public void initDestroyedCallerRegisters(EconomicSet<Register> registers) { 104 assert registers != null; 105 assert destroyedCallerRegisters == null || checkRegisterSetEquivalency(registers, destroyedCallerRegisters) : "cannot redefine"; 106 destroyedCallerRegisters = registers; 107 } 108 109 /** 110 * Gets the registers destroyed by this stub from a caller's perspective. These are the 111 * temporaries of this stub and must thus be caller saved by a callers of this stub. 112 */ 113 public EconomicSet<Register> getDestroyedCallerRegisters() { 114 assert destroyedCallerRegisters != null : "not yet initialized"; 115 return destroyedCallerRegisters; 116 } 117 118 /** 119 * Determines if this stub preserves all registers apart from those it 120 * {@linkplain #getDestroyedCallerRegisters() destroys}. 121 */ 122 public boolean preservesRegisters() { 123 return true; 124 } 125 126 protected final OptionValues options; 127 protected final HotSpotProviders providers; 128 129 /** 130 * Creates a new stub. 131 * 132 * @param linkage linkage details for a call to the stub 133 */ 134 public Stub(OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { 135 this.linkage = linkage; 136 this.options = options; 137 this.providers = providers; 138 } 139 140 /** 141 * Gets the linkage for a call to this stub from compiled code. 142 */ 143 public HotSpotForeignCallLinkage getLinkage() { 144 return linkage; 145 } 146 147 public RegisterConfig getRegisterConfig() { 148 return null; 149 } 150 151 /** 152 * Gets the graph that from which the code for this stub will be compiled. 153 * 154 * @param compilationId unique compilation id for the stub 155 */ 156 protected abstract StructuredGraph getGraph(CompilationIdentifier compilationId); 157 158 @Override 159 public String toString() { 160 return "Stub<" + linkage.getDescriptor() + ">"; 161 } 162 163 /** 164 * Gets the method the stub's code will be associated with once installed. This may be null. 165 */ 166 protected abstract ResolvedJavaMethod getInstalledCodeOwner(); 167 168 /** 169 * Gets a context object for the debug scope created when producing the code for this stub. 170 */ 171 protected abstract Object debugScopeContext(); 172 173 /** 174 * Gets the code for this stub, compiling it first if necessary. 175 */ 176 @SuppressWarnings("try") 177 public synchronized InstalledCode getCode(final Backend backend) { 178 if (code == null) { 179 try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) { 180 CodeCacheProvider codeCache = providers.getCodeCache(); 181 182 CompilationResult compResult = buildCompilationResult(backend); 183 try (Scope s = Debug.scope("CodeInstall", compResult)) { 184 assert destroyedCallerRegisters != null; 185 // Add a GeneratePIC check here later, we don't want to install 186 // code if we don't have a corresponding VM global symbol. 187 HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult); 188 code = codeCache.installCode(null, compiledCode, null, null, false); 189 } catch (Throwable e) { 190 throw Debug.handle(e); 191 } 192 } catch (Throwable e) { 193 throw Debug.handle(e); 194 } 195 assert code != null : "error installing stub " + this; 196 } 197 198 return code; 199 } 200 201 @SuppressWarnings("try") 202 private CompilationResult buildCompilationResult(final Backend backend) { 203 CompilationResult compResult = new CompilationResult(toString(), GeneratePIC.getValue(options)); 204 final StructuredGraph graph = getGraph(getStubCompilationId()); 205 206 // Stubs cannot be recompiled so they cannot be compiled with assumptions 207 assert graph.getAssumptions() == null; 208 209 if (!(graph.start() instanceof StubStartNode)) { 210 StubStartNode newStart = graph.add(new StubStartNode(Stub.this)); 211 newStart.setStateAfter(graph.start().stateAfter()); 212 graph.replaceFixed(graph.start(), newStart); 213 } 214 215 try (Scope s0 = Debug.scope("StubCompilation", graph, providers.getCodeCache())) { 216 Suites suites = createSuites(); 217 emitFrontEnd(providers, backend, graph, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, DefaultProfilingInfo.get(TriState.UNKNOWN), suites); 218 LIRSuites lirSuites = createLIRSuites(); 219 emitBackEnd(graph, Stub.this, getInstalledCodeOwner(), backend, compResult, CompilationResultBuilderFactory.Default, getRegisterConfig(), lirSuites); 220 assert checkStubInvariants(compResult); 221 } catch (Throwable e) { 222 throw Debug.handle(e); 223 } 224 return compResult; 225 } 226 227 /** 228 * Gets a {@link CompilationResult} that can be used for code generation. Required for AOT. 229 */ 230 @SuppressWarnings("try") 231 public CompilationResult getCompilationResult(final Backend backend) { 232 try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) { 233 return buildCompilationResult(backend); 234 } catch (Throwable e) { 235 throw Debug.handle(e); 236 } 237 } 238 239 public CompilationIdentifier getStubCompilationId() { 240 return new StubCompilationIdentifier(this); 241 } 242 243 /** 244 * Checks the conditions a compilation must satisfy to be installed as a RuntimeStub. 245 */ 246 private boolean checkStubInvariants(CompilationResult compResult) { 247 assert compResult.getExceptionHandlers().isEmpty() : this; 248 249 // Stubs cannot be recompiled so they cannot be compiled with 250 // assumptions and there is no point in recording evol_method dependencies 251 assert compResult.getAssumptions() == null : "stubs should not use assumptions: " + this; 252 253 for (DataPatch data : compResult.getDataPatches()) { 254 if (data.reference instanceof ConstantReference) { 255 ConstantReference ref = (ConstantReference) data.reference; 256 if (ref.getConstant() instanceof HotSpotMetaspaceConstant) { 257 HotSpotMetaspaceConstant c = (HotSpotMetaspaceConstant) ref.getConstant(); 258 if (c.asResolvedJavaType() != null && c.asResolvedJavaType().getName().equals("[I")) { 259 // special handling for NewArrayStub 260 // embedding the type '[I' is safe, since it is never unloaded 261 continue; 262 } 263 } 264 } 265 266 assert !(data.reference instanceof ConstantReference) : this + " cannot have embedded object or metadata constant: " + data.reference; 267 } 268 for (Infopoint infopoint : compResult.getInfopoints()) { 269 assert infopoint instanceof Call : this + " cannot have non-call infopoint: " + infopoint; 270 Call call = (Call) infopoint; 271 assert call.target instanceof HotSpotForeignCallLinkage : this + " cannot have non runtime call: " + call.target; 272 HotSpotForeignCallLinkage callLinkage = (HotSpotForeignCallLinkage) call.target; 273 assert !callLinkage.isCompiledStub() || callLinkage.getDescriptor().equals(UNCOMMON_TRAP_HANDLER) : this + " cannot call compiled stub " + callLinkage; 274 } 275 return true; 276 } 277 278 protected Suites createSuites() { 279 Suites defaultSuites = providers.getSuites().getDefaultSuites(options); 280 return new Suites(new PhaseSuite<>(), defaultSuites.getMidTier(), defaultSuites.getLowTier()); 281 } 282 283 protected LIRSuites createLIRSuites() { 284 LIRSuites lirSuites = new LIRSuites(providers.getSuites().getDefaultLIRSuites(options)); 285 ListIterator<LIRPhase<PostAllocationOptimizationContext>> moveProfiling = lirSuites.getPostAllocationOptimizationStage().findPhase(MoveProfilingPhase.class); 286 if (moveProfiling != null) { 287 moveProfiling.remove(); 288 } 289 return lirSuites; 290 } 291} 292