1 /*
2 * Copyright (c) 2013, 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 package jdk.vm.ci.hotspot;
24
25 import java.util.Map;
26 import java.util.Objects;
27
28 import jdk.vm.ci.code.BailoutException;
29 import jdk.vm.ci.code.BytecodeFrame;
30 import jdk.vm.ci.code.CodeCacheProvider;
31 import jdk.vm.ci.code.CompiledCode;
32 import jdk.vm.ci.code.InstalledCode;
33 import jdk.vm.ci.code.RegisterConfig;
34 import jdk.vm.ci.code.TargetDescription;
35 import jdk.vm.ci.code.site.Call;
36 import jdk.vm.ci.code.site.Mark;
37 import jdk.vm.ci.meta.ResolvedJavaMethod;
38 import jdk.vm.ci.meta.SpeculationLog;
39
40 /**
41 * HotSpot implementation of {@link CodeCacheProvider}.
42 */
43 public class HotSpotCodeCacheProvider implements CodeCacheProvider {
44
45 protected final HotSpotJVMCIRuntime runtime;
46 private final HotSpotVMConfig config;
47 protected final TargetDescription target;
48 protected final RegisterConfig regConfig;
49
50 public HotSpotCodeCacheProvider(HotSpotJVMCIRuntime runtime, TargetDescription target, RegisterConfig regConfig) {
51 this.runtime = runtime;
52 this.config = runtime.getConfig();
53 this.target = target;
54 this.regConfig = regConfig;
55 }
56
57 @Override
58 public String getMarkName(Mark mark) {
59 int markId = (int) mark.id;
60 HotSpotVMConfigStore store = runtime.getConfigStore();
61 for (Map.Entry<String, Long> e : store.getConstants().entrySet()) {
62 String name = e.getKey();
63 if (name.startsWith("MARKID_") && e.getValue() == markId) {
64 return name;
65 }
66 }
67 return CodeCacheProvider.super.getMarkName(mark);
68 }
69
70 /**
71 * Decodes a call target to a mnemonic if possible.
72 */
73 @Override
74 public String getTargetName(Call call) {
75 if (call.target instanceof HotSpotForeignCallTarget) {
76 long address = ((HotSpotForeignCallTarget) call.target).address;
77 HotSpotVMConfigStore store = runtime.getConfigStore();
78 for (Map.Entry<String, VMField> e : store.getFields().entrySet()) {
79 VMField field = e.getValue();
80 if (field.isStatic() && field.value != null && field.value instanceof Long && ((Long) field.value) == address) {
81 return e.getValue() + ":0x" + Long.toHexString(address);
82 }
83 }
84 }
85 return CodeCacheProvider.super.getTargetName(call);
86 }
87
88 @Override
89 public RegisterConfig getRegisterConfig() {
90 return regConfig;
91 }
92
93 @Override
94 public int getMinimumOutgoingSize() {
95 return config.runtimeCallStackSize;
96 }
97
98 private InstalledCode logOrDump(InstalledCode installedCode, CompiledCode compiledCode) {
99 runtime.notifyInstall(this, installedCode, compiledCode);
100 return installedCode;
101 }
102
103 @Override
104 public InstalledCode installCode(ResolvedJavaMethod method, CompiledCode compiledCode, InstalledCode installedCode, SpeculationLog log, boolean isDefault) {
105 InstalledCode resultInstalledCode;
106 if (installedCode != null) {
107 throw new IllegalArgumentException("InstalledCode argument must be null");
108 }
109 HotSpotCompiledCode hsCompiledCode = (HotSpotCompiledCode) compiledCode;
110 String name = hsCompiledCode.getName();
111 HotSpotCompiledNmethod hsCompiledNmethod = null;
112 HotSpotSpeculationLog speculationLog = null;
113 if (log != null) {
114 if (log.hasSpeculations()) {
115 speculationLog = (HotSpotSpeculationLog) log;
116 }
117 }
118 byte[] speculations;
119 long failedSpeculationsAddress;
120 if (speculationLog != null) {
121 speculations = speculationLog.getFlattenedSpeculations(true);
122 failedSpeculationsAddress = speculationLog.getFailedSpeculationsAddress();
123 } else {
124 speculations = new byte[0];
125 failedSpeculationsAddress = 0L;
126 }
127
128 if (method == null) {
129 // Must be a stub
130 resultInstalledCode = new HotSpotRuntimeStub(name);
131 } else {
132 hsCompiledNmethod = (HotSpotCompiledNmethod) hsCompiledCode;
133 HotSpotResolvedJavaMethodImpl hsMethod = (HotSpotResolvedJavaMethodImpl) method;
134 HotSpotNmethod nmethod = new HotSpotNmethod(hsMethod, name, isDefault, hsCompiledNmethod.id);
135 nmethod.setSpeculationLog(speculationLog);
136 resultInstalledCode = nmethod;
137 }
138
139 int result = runtime.getCompilerToVM().installCode(hsCompiledCode, resultInstalledCode, failedSpeculationsAddress, speculations);
140 if (result != config.codeInstallResultOk) {
141 String resultDesc = config.getCodeInstallResultDescription(result);
142 if (hsCompiledNmethod != null) {
143 String msg = hsCompiledNmethod.getInstallationFailureMessage();
144 if (msg != null) {
145 msg = String.format("Code installation failed: %s%n%s", resultDesc, msg);
146 } else {
147 msg = String.format("Code installation failed: %s", resultDesc);
148 }
149 throw new BailoutException(result >= config.codeInstallResultFirstPermanentBailout, msg);
150 } else {
151 throw new BailoutException("Error installing %s: %s", ((HotSpotCompiledCode) compiledCode).getName(), resultDesc);
152 }
153 }
154 return logOrDump(resultInstalledCode, compiledCode);
155 }
156
157 public void invalidateInstalledCode(InstalledCode installedCode, int invalidationReason) {
158 if (installedCode instanceof HotSpotNmethod) {
159 HotSpotNmethod nmethod = (HotSpotNmethod) installedCode;
160 nmethod.invalidate(true, invalidationReason);
161 } else {
162 throw new IllegalArgumentException("Cannot invalidate a " + Objects.requireNonNull(installedCode).getClass().getName());
163 }
164 }
165
166 @Override
167 public void invalidateInstalledCode(InstalledCode installedCode) {
168 invalidateInstalledCode(installedCode, jvmciInvalidationReason());
169 }
170
171 @Override
172 public TargetDescription getTarget() {
173 return target;
174 }
175
176 public String disassemble(InstalledCode code) {
177 if (code.isValid()) {
178 return runtime.getCompilerToVM().disassembleCodeBlob(code);
179 }
180 return null;
181 }
182
183 @Override
184 public SpeculationLog createSpeculationLog() {
185 return new HotSpotSpeculationLog();
186 }
187
188 @Override
189 public long getMaxCallTargetOffset(long address) {
190 return runtime.getCompilerToVM().getMaxCallTargetOffset(address);
191 }
192
193 @Override
194 public boolean shouldDebugNonSafepoints() {
195 return runtime.getCompilerToVM().shouldDebugNonSafepoints();
196 }
197
198 public int interpreterFrameSize(BytecodeFrame pos) {
199 return runtime.getCompilerToVM().interpreterFrameSize(pos);
200 }
201
202 /**
203 * Resets all compilation statistics.
204 */
205 public void resetCompilationStatistics() {
206 runtime.getCompilerToVM().resetCompilationStatistics();
207 }
208
209 private static int jvmciInvalidationReason() {
210 return HotSpotJVMCIRuntime.runtime().config.getConstant("nmethod::InvalidationReason::JVMCI_INVALIDATE", Integer.class);
211 }
212 }