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 
HotSpotCodeCacheProvider(HotSpotJVMCIRuntime runtime, TargetDescription target, RegisterConfig regConfig)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
getMarkName(Mark mark)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
getTargetName(Call call)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
getRegisterConfig()89     public RegisterConfig getRegisterConfig() {
90         return regConfig;
91     }
92 
93     @Override
getMinimumOutgoingSize()94     public int getMinimumOutgoingSize() {
95         return config.runtimeCallStackSize;
96     }
97 
logOrDump(InstalledCode installedCode, CompiledCode compiledCode)98     private InstalledCode logOrDump(InstalledCode installedCode, CompiledCode compiledCode) {
99         runtime.notifyInstall(this, installedCode, compiledCode);
100         return installedCode;
101     }
102 
103     @Override
installCode(ResolvedJavaMethod method, CompiledCode compiledCode, InstalledCode installedCode, SpeculationLog log, boolean isDefault)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         if (method == null) {
113             // Must be a stub
114             resultInstalledCode = new HotSpotRuntimeStub(name);
115         } else {
116             hsCompiledNmethod = (HotSpotCompiledNmethod) hsCompiledCode;
117             HotSpotResolvedJavaMethodImpl hsMethod = (HotSpotResolvedJavaMethodImpl) method;
118             resultInstalledCode = new HotSpotNmethod(hsMethod, name, isDefault, hsCompiledNmethod.id);
119         }
120 
121         HotSpotSpeculationLog speculationLog = null;
122         if (log != null) {
123             if (log.hasSpeculations()) {
124                 speculationLog = (HotSpotSpeculationLog) log;
125             }
126         }
127 
128         byte[] speculations;
129         long failedSpeculationsAddress;
130         if (speculationLog != null) {
131             speculations = speculationLog.getFlattenedSpeculations(true);
132             failedSpeculationsAddress = speculationLog.getFailedSpeculationsAddress();
133         } else {
134             speculations = new byte[0];
135             failedSpeculationsAddress = 0L;
136         }
137         int result = runtime.getCompilerToVM().installCode(target, (HotSpotCompiledCode) compiledCode, resultInstalledCode, failedSpeculationsAddress, speculations);
138         if (result != config.codeInstallResultOk) {
139             String resultDesc = config.getCodeInstallResultDescription(result);
140             if (hsCompiledNmethod != null) {
141                 String msg = hsCompiledNmethod.getInstallationFailureMessage();
142                 if (msg != null) {
143                     msg = String.format("Code installation failed: %s%n%s", resultDesc, msg);
144                 } else {
145                     msg = String.format("Code installation failed: %s", resultDesc);
146                 }
147                 throw new BailoutException(result != config.codeInstallResultDependenciesFailed, msg);
148             } else {
149                 throw new BailoutException("Error installing %s: %s", ((HotSpotCompiledCode) compiledCode).getName(), resultDesc);
150             }
151         }
152         return logOrDump(resultInstalledCode, compiledCode);
153     }
154 
155     @Override
invalidateInstalledCode(InstalledCode installedCode)156     public void invalidateInstalledCode(InstalledCode installedCode) {
157         if (installedCode instanceof HotSpotNmethod) {
158             runtime.getCompilerToVM().invalidateHotSpotNmethod((HotSpotNmethod) installedCode);
159         } else {
160             throw new IllegalArgumentException("Cannot invalidate a " + Objects.requireNonNull(installedCode).getClass().getName());
161         }
162     }
163 
164     @Override
getTarget()165     public TargetDescription getTarget() {
166         return target;
167     }
168 
disassemble(InstalledCode code)169     public String disassemble(InstalledCode code) {
170         if (code.isValid()) {
171             return runtime.getCompilerToVM().disassembleCodeBlob(code);
172         }
173         return null;
174     }
175 
176     @Override
createSpeculationLog()177     public SpeculationLog createSpeculationLog() {
178         return new HotSpotSpeculationLog();
179     }
180 
181     @Override
getMaxCallTargetOffset(long address)182     public long getMaxCallTargetOffset(long address) {
183         return runtime.getCompilerToVM().getMaxCallTargetOffset(address);
184     }
185 
186     @Override
shouldDebugNonSafepoints()187     public boolean shouldDebugNonSafepoints() {
188         return runtime.getCompilerToVM().shouldDebugNonSafepoints();
189     }
190 
interpreterFrameSize(BytecodeFrame pos)191     public int interpreterFrameSize(BytecodeFrame pos) {
192         return runtime.getCompilerToVM().interpreterFrameSize(pos);
193     }
194 
195     /**
196      * Resets all compilation statistics.
197      */
resetCompilationStatistics()198     public void resetCompilationStatistics() {
199         runtime.getCompilerToVM().resetCompilationStatistics();
200     }
201 }
202