1/*
2 * Copyright (c) 2011, 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;
24
25import static jdk.vm.ci.common.InitTimer.timer;
26import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
27import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
28import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
29import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining;
30import static org.graalvm.compiler.debug.DebugContext.DEFAULT_LOG_STREAM;
31
32import java.util.ArrayList;
33import java.util.EnumMap;
34import java.util.List;
35import java.util.Map;
36
37import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
38import org.graalvm.compiler.api.runtime.GraalRuntime;
39import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction;
40import org.graalvm.compiler.core.common.CompilationIdentifier;
41import org.graalvm.compiler.core.common.GraalOptions;
42import org.graalvm.compiler.core.target.Backend;
43import org.graalvm.compiler.debug.DebugContext;
44import org.graalvm.compiler.debug.DebugContext.Description;
45import org.graalvm.compiler.debug.DebugHandlersFactory;
46import org.graalvm.compiler.debug.DiagnosticsOutputDirectory;
47import org.graalvm.compiler.debug.GlobalMetrics;
48import org.graalvm.compiler.debug.GraalError;
49import org.graalvm.compiler.debug.TTY;
50import org.graalvm.compiler.hotspot.CompilationStatistics.Options;
51import org.graalvm.compiler.hotspot.CompilerConfigurationFactory.BackendMap;
52import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
53import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
54import org.graalvm.compiler.nodes.spi.StampProvider;
55import org.graalvm.compiler.options.OptionValues;
56import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
57import org.graalvm.compiler.replacements.SnippetCounter;
58import org.graalvm.compiler.replacements.SnippetCounter.Group;
59import org.graalvm.compiler.runtime.RuntimeProvider;
60import org.graalvm.util.EconomicMap;
61import org.graalvm.util.Equivalence;
62
63import jdk.vm.ci.code.Architecture;
64import jdk.vm.ci.code.stack.StackIntrospection;
65import jdk.vm.ci.common.InitTimer;
66import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
67import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
68import jdk.vm.ci.meta.JavaKind;
69import jdk.vm.ci.meta.ResolvedJavaMethod;
70import jdk.vm.ci.runtime.JVMCIBackend;
71
72//JaCoCo Exclude
73
74/**
75 * Singleton class holding the instance of the {@link GraalRuntime}.
76 */
77public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider {
78
79    private static boolean checkArrayIndexScaleInvariants() {
80        assert getArrayIndexScale(JavaKind.Byte) == 1;
81        assert getArrayIndexScale(JavaKind.Boolean) == 1;
82        assert getArrayIndexScale(JavaKind.Char) == 2;
83        assert getArrayIndexScale(JavaKind.Short) == 2;
84        assert getArrayIndexScale(JavaKind.Int) == 4;
85        assert getArrayIndexScale(JavaKind.Long) == 8;
86        assert getArrayIndexScale(JavaKind.Float) == 4;
87        assert getArrayIndexScale(JavaKind.Double) == 8;
88        return true;
89    }
90
91    private final HotSpotBackend hostBackend;
92    private final GlobalMetrics metricValues = new GlobalMetrics();
93    private final List<SnippetCounter.Group> snippetCounterGroups;
94
95    private final EconomicMap<Class<? extends Architecture>, HotSpotBackend> backends = EconomicMap.create(Equivalence.IDENTITY);
96
97    private final GraalHotSpotVMConfig config;
98
99    private final OptionValues options;
100    private final DiagnosticsOutputDirectory outputDirectory;
101    private final Map<ExceptionAction, Integer> compilationProblemsPerAction;
102    private final HotSpotGraalMBean mBean;
103
104    /**
105     * @param compilerConfigurationFactory factory for the compiler configuration
106     *            {@link CompilerConfigurationFactory#selectFactory(String, OptionValues)}
107     */
108    @SuppressWarnings("try")
109    HotSpotGraalRuntime(HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory, OptionValues initialOptions) {
110        HotSpotVMConfigStore store = jvmciRuntime.getConfigStore();
111        config = GeneratePIC.getValue(initialOptions) ? new AOTGraalHotSpotVMConfig(store) : new GraalHotSpotVMConfig(store);
112
113        // Only set HotSpotPrintInlining if it still has its default value (false).
114        if (GraalOptions.HotSpotPrintInlining.getValue(initialOptions) == false && config.printInlining) {
115            options = new OptionValues(initialOptions, HotSpotPrintInlining, true);
116        } else {
117            options = initialOptions;
118        }
119
120        outputDirectory = new DiagnosticsOutputDirectory(options);
121        compilationProblemsPerAction = new EnumMap<>(ExceptionAction.class);
122        snippetCounterGroups = GraalOptions.SnippetCounters.getValue(options) ? new ArrayList<>() : null;
123        CompilerConfiguration compilerConfiguration = compilerConfigurationFactory.createCompilerConfiguration();
124
125        HotSpotGraalCompiler compiler = new HotSpotGraalCompiler(jvmciRuntime, this, initialOptions);
126        this.mBean = createHotSpotGraalMBean(compiler);
127
128        BackendMap backendMap = compilerConfigurationFactory.createBackendMap();
129
130        JVMCIBackend hostJvmciBackend = jvmciRuntime.getHostJVMCIBackend();
131        Architecture hostArchitecture = hostJvmciBackend.getTarget().arch;
132        try (InitTimer t = timer("create backend:", hostArchitecture)) {
133            HotSpotBackendFactory factory = backendMap.getBackendFactory(hostArchitecture);
134            if (factory == null) {
135                throw new GraalError("No backend available for host architecture \"%s\"", hostArchitecture);
136            }
137            hostBackend = registerBackend(factory.createBackend(this, compilerConfiguration, jvmciRuntime, null));
138        }
139
140        for (JVMCIBackend jvmciBackend : jvmciRuntime.getJVMCIBackends().values()) {
141            if (jvmciBackend == hostJvmciBackend) {
142                continue;
143            }
144
145            Architecture gpuArchitecture = jvmciBackend.getTarget().arch;
146            HotSpotBackendFactory factory = backendMap.getBackendFactory(gpuArchitecture);
147            if (factory == null) {
148                throw new GraalError("No backend available for specified GPU architecture \"%s\"", gpuArchitecture);
149            }
150            try (InitTimer t = timer("create backend:", gpuArchitecture)) {
151                registerBackend(factory.createBackend(this, compilerConfiguration, null, hostBackend));
152            }
153        }
154
155        // Complete initialization of backends
156        try (InitTimer st = timer(hostBackend.getTarget().arch.getName(), ".completeInitialization")) {
157            hostBackend.completeInitialization(jvmciRuntime, options);
158        }
159        for (HotSpotBackend backend : backends.getValues()) {
160            if (backend != hostBackend) {
161                try (InitTimer st = timer(backend.getTarget().arch.getName(), ".completeInitialization")) {
162                    backend.completeInitialization(jvmciRuntime, options);
163                }
164            }
165        }
166
167        BenchmarkCounters.initialize(jvmciRuntime, options);
168
169        assert checkArrayIndexScaleInvariants();
170
171        runtimeStartTime = System.nanoTime();
172        bootstrapJVMCI = config.getFlag("BootstrapJVMCI", Boolean.class);
173    }
174
175    private static HotSpotGraalMBean createHotSpotGraalMBean(HotSpotGraalCompiler compiler) {
176        try {
177            return HotSpotGraalMBean.create(compiler);
178        } catch (LinkageError ex) {
179            return null;
180        }
181    }
182
183    private HotSpotBackend registerBackend(HotSpotBackend backend) {
184        Class<? extends Architecture> arch = backend.getTarget().arch.getClass();
185        HotSpotBackend oldValue = backends.put(arch, backend);
186        assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName();
187        return backend;
188    }
189
190    @Override
191    public HotSpotProviders getHostProviders() {
192        return getHostBackend().getProviders();
193    }
194
195    @Override
196    public GraalHotSpotVMConfig getVMConfig() {
197        return config;
198    }
199
200    @Override
201    public DebugContext openDebugContext(OptionValues compilationOptions, CompilationIdentifier compilationId, Object compilable, Iterable<DebugHandlersFactory> factories) {
202        Description description = new Description(compilable, compilationId.toString(CompilationIdentifier.Verbosity.ID));
203        return DebugContext.create(compilationOptions, description, metricValues, DEFAULT_LOG_STREAM, factories);
204    }
205
206    @Override
207    public OptionValues getOptions() {
208        return mBean == null ? options : mBean.optionsFor(options, null);
209    }
210
211    @Override
212    public OptionValues getOptions(ResolvedJavaMethod forMethod) {
213        return mBean == null ? options : mBean.optionsFor(options, forMethod);
214    }
215
216    @Override
217    public Group createSnippetCounterGroup(String name) {
218        if (snippetCounterGroups != null) {
219            Group group = new Group(name);
220            snippetCounterGroups.add(group);
221            return group;
222        }
223        return null;
224    }
225
226    @Override
227    public String getName() {
228        return getClass().getSimpleName();
229    }
230
231    @SuppressWarnings("unchecked")
232    @Override
233    public <T> T getCapability(Class<T> clazz) {
234        if (clazz == RuntimeProvider.class) {
235            return (T) this;
236        } else if (clazz == OptionValues.class) {
237            return (T) options;
238        } else if (clazz == StackIntrospection.class) {
239            return (T) this;
240        } else if (clazz == SnippetReflectionProvider.class) {
241            return (T) getHostProviders().getSnippetReflection();
242        } else if (clazz == StampProvider.class) {
243            return (T) getHostProviders().getStampProvider();
244        }
245        return null;
246    }
247
248    @Override
249    public HotSpotBackend getHostBackend() {
250        return hostBackend;
251    }
252
253    @Override
254    public <T extends Architecture> Backend getBackend(Class<T> arch) {
255        assert arch != Architecture.class;
256        return backends.get(arch);
257    }
258
259    private long runtimeStartTime;
260    private boolean shutdown;
261
262    /**
263     * Take action related to entering a new execution phase.
264     *
265     * @param phase the execution phase being entered
266     */
267    void phaseTransition(String phase) {
268        if (Options.UseCompilationStatistics.getValue(options)) {
269            CompilationStatistics.clear(phase);
270        }
271    }
272
273    void shutdown() {
274        shutdown = true;
275        metricValues.print(options);
276
277        phaseTransition("final");
278
279        if (snippetCounterGroups != null) {
280            for (Group group : snippetCounterGroups) {
281                TTY.out().out().println(group);
282            }
283        }
284        BenchmarkCounters.shutdown(runtime(), options, runtimeStartTime);
285
286        outputDirectory.close();
287    }
288
289    void clearMetrics() {
290        metricValues.clear();
291    }
292
293    private final boolean bootstrapJVMCI;
294    private boolean bootstrapFinished;
295
296    public void notifyBootstrapFinished() {
297        bootstrapFinished = true;
298    }
299
300    @Override
301    public boolean isBootstrapping() {
302        return bootstrapJVMCI && !bootstrapFinished;
303    }
304
305    @Override
306    public boolean isShutdown() {
307        return shutdown;
308    }
309
310    @Override
311    public DiagnosticsOutputDirectory getOutputDirectory() {
312        return outputDirectory;
313    }
314
315    @Override
316    public Map<ExceptionAction, Integer> getCompilationProblemsPerAction() {
317        return compilationProblemsPerAction;
318    }
319}
320