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 }