001/* 002 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.hotspot.stubs; 024 025import static com.oracle.graal.compiler.GraalCompiler.*; 026import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; 027 028import java.util.*; 029 030import jdk.internal.jvmci.code.*; 031import jdk.internal.jvmci.common.*; 032import com.oracle.graal.debug.*; 033import com.oracle.graal.debug.Debug.*; 034import com.oracle.graal.debug.internal.*; 035import jdk.internal.jvmci.hotspot.*; 036import jdk.internal.jvmci.meta.*; 037 038import com.oracle.graal.compiler.target.*; 039import com.oracle.graal.hotspot.*; 040import com.oracle.graal.hotspot.meta.*; 041import com.oracle.graal.hotspot.nodes.*; 042import com.oracle.graal.lir.asm.*; 043import com.oracle.graal.lir.phases.*; 044import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; 045import com.oracle.graal.lir.profiling.*; 046import com.oracle.graal.nodes.*; 047import com.oracle.graal.phases.*; 048import com.oracle.graal.phases.schedule.*; 049import com.oracle.graal.phases.tiers.*; 050 051//JaCoCo Exclude 052 053/** 054 * Base class for implementing some low level code providing the out-of-line slow path for a snippet 055 * and/or a callee saved call to a HotSpot C/C++ runtime function or even a another compiled Java 056 * method. 057 */ 058public abstract class Stub { 059 060 private static final List<Stub> stubs = new ArrayList<>(); 061 062 /** 063 * The linkage information for a call to this stub from compiled code. 064 */ 065 protected final HotSpotForeignCallLinkage linkage; 066 067 /** 068 * The code installed for the stub. 069 */ 070 protected InstalledCode code; 071 072 /** 073 * Compilation result from which {@link #code} was created. 074 */ 075 protected CompilationResult compResult; 076 077 /** 078 * The registers destroyed by this stub. 079 */ 080 private Set<Register> destroyedRegisters; 081 082 public void initDestroyedRegisters(Set<Register> registers) { 083 assert registers != null; 084 assert destroyedRegisters == null || registers.equals(destroyedRegisters) : "cannot redefine"; 085 destroyedRegisters = registers; 086 } 087 088 /** 089 * Gets the registers defined by this stub. These are the temporaries of this stub and must thus 090 * be caller saved by a callers of this stub. 091 */ 092 public Set<Register> getDestroyedRegisters() { 093 assert destroyedRegisters != null : "not yet initialized"; 094 return destroyedRegisters; 095 } 096 097 /** 098 * Determines if this stub preserves all registers apart from those it 099 * {@linkplain #getDestroyedRegisters() destroys}. 100 */ 101 public boolean preservesRegisters() { 102 return true; 103 } 104 105 protected final HotSpotProviders providers; 106 107 /** 108 * Creates a new stub. 109 * 110 * @param linkage linkage details for a call to the stub 111 */ 112 public Stub(HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { 113 this.linkage = linkage; 114 this.providers = providers; 115 stubs.add(this); 116 } 117 118 /** 119 * Gets an immutable view of all stubs that have been created. 120 */ 121 public static Collection<Stub> getStubs() { 122 return Collections.unmodifiableList(stubs); 123 } 124 125 /** 126 * Gets the linkage for a call to this stub from compiled code. 127 */ 128 public HotSpotForeignCallLinkage getLinkage() { 129 return linkage; 130 } 131 132 public RegisterConfig getRegisterConfig() { 133 return null; 134 } 135 136 /** 137 * Gets the graph that from which the code for this stub will be compiled. 138 */ 139 protected abstract StructuredGraph getGraph(); 140 141 @Override 142 public String toString() { 143 return "Stub<" + linkage.getDescriptor() + ">"; 144 } 145 146 /** 147 * Gets the method the stub's code will be associated with once installed. This may be null. 148 */ 149 protected abstract ResolvedJavaMethod getInstalledCodeOwner(); 150 151 /** 152 * Gets a context object for the debug scope created when producing the code for this stub. 153 */ 154 protected abstract Object debugScopeContext(); 155 156 /** 157 * Gets the code for this stub, compiling it first if necessary. 158 */ 159 public synchronized InstalledCode getCode(final Backend backend) { 160 if (code == null) { 161 try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) { 162 final StructuredGraph graph = getGraph(); 163 164 // Stubs cannot be recompiled so they cannot be compiled with 165 // assumptions and there is no point in recording evol_method dependencies 166 assert graph.getAssumptions() == null; 167 assert !graph.isInlinedMethodRecordingEnabled() : graph; 168 169 if (!(graph.start() instanceof StubStartNode)) { 170 StubStartNode newStart = graph.add(new StubStartNode(Stub.this)); 171 newStart.setStateAfter(graph.start().stateAfter()); 172 graph.replaceFixed(graph.start(), newStart); 173 } 174 175 CodeCacheProvider codeCache = providers.getCodeCache(); 176 // The stub itself needs the incoming calling convention. 177 CallingConvention incomingCc = linkage.getIncomingCallingConvention(); 178 TargetDescription target = codeCache.getTarget(); 179 180 compResult = new CompilationResult(toString()); 181 try (Scope s0 = Debug.scope("StubCompilation", graph, providers.getCodeCache())) { 182 Suites defaultSuites = providers.getSuites().getDefaultSuites(); 183 Suites suites = new Suites(new PhaseSuite<>(), defaultSuites.getMidTier(), defaultSuites.getLowTier()); 184 SchedulePhase schedule = emitFrontEnd(providers, target, graph, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graph), suites); 185 LIRSuites lirSuites = createLIRSuites(); 186 emitBackEnd(graph, Stub.this, incomingCc, getInstalledCodeOwner(), backend, target, compResult, CompilationResultBuilderFactory.Default, schedule, getRegisterConfig(), lirSuites); 187 } catch (Throwable e) { 188 throw Debug.handle(e); 189 } 190 191 assert destroyedRegisters != null; 192 try (Scope s = Debug.scope("CodeInstall")) { 193 Stub stub = Stub.this; 194 HotSpotRuntimeStub installedCode = new HotSpotRuntimeStub(stub); 195 HotSpotCompiledCode hsCompResult = new HotSpotCompiledRuntimeStub(compResult); 196 197 HotSpotGraalRuntime runtime = runtime(); 198 int result = runtime.getCompilerToVM().installCode(hsCompResult, installedCode, null); 199 HotSpotVMConfig config = runtime.getConfig(); 200 if (result != config.codeInstallResultOk) { 201 throw new JVMCIError("Error installing stub %s: %s", Stub.this, config.getCodeInstallResultDescription(result)); 202 } 203 ((HotSpotCodeCacheProvider) codeCache).logOrDump(installedCode, compResult); 204 code = installedCode; 205 } catch (Throwable e) { 206 throw Debug.handle(e); 207 } 208 } catch (Throwable e) { 209 throw Debug.handle(e); 210 } 211 assert code != null : "error installing stub " + this; 212 } 213 214 return code; 215 } 216 217 private LIRSuites createLIRSuites() { 218 LIRSuites lirSuites = new LIRSuites(providers.getSuites().getDefaultLIRSuites()); 219 ListIterator<LIRPhase<PostAllocationOptimizationContext>> moveProfiling = lirSuites.getPostAllocationOptimizationStage().findPhase(MoveProfiling.class); 220 if (moveProfiling != null) { 221 moveProfiling.remove(); 222 } 223 return lirSuites; 224 } 225 226 /** 227 * Gets the compilation result for this stub, compiling it first if necessary, and installing it 228 * in code. 229 */ 230 public synchronized CompilationResult getCompilationResult(final Backend backend) { 231 if (code == null) { 232 getCode(backend); 233 } 234 return compResult; 235 } 236}