001/*
002 * Copyright (c) 2011, 2015, 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;
024
025import static com.oracle.graal.compiler.common.GraalOptions.*;
026import static com.oracle.graal.debug.GraalDebugConfig.*;
027import static com.oracle.graal.hotspot.HotSpotGraalRuntime.Options.*;
028import static jdk.internal.jvmci.common.UnsafeAccess.*;
029import static jdk.internal.jvmci.hotspot.InitTimer.*;
030
031import java.lang.reflect.*;
032import java.util.*;
033
034import jdk.internal.jvmci.code.*;
035import jdk.internal.jvmci.code.stack.*;
036import jdk.internal.jvmci.common.*;
037import jdk.internal.jvmci.hotspot.*;
038import jdk.internal.jvmci.meta.*;
039import jdk.internal.jvmci.options.*;
040import jdk.internal.jvmci.runtime.*;
041import jdk.internal.jvmci.service.*;
042
043import com.oracle.graal.api.collections.*;
044import com.oracle.graal.api.replacements.*;
045import com.oracle.graal.api.runtime.*;
046import com.oracle.graal.compiler.target.*;
047import com.oracle.graal.debug.*;
048import com.oracle.graal.graph.*;
049import com.oracle.graal.hotspot.debug.*;
050import com.oracle.graal.hotspot.logging.*;
051import com.oracle.graal.hotspot.meta.*;
052import com.oracle.graal.replacements.*;
053import com.oracle.graal.runtime.*;
054
055//JaCoCo Exclude
056
057/**
058 * Singleton class holding the instance of the {@link GraalRuntime}.
059 */
060public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider, HotSpotProxified {
061
062    private static final HotSpotGraalRuntime instance;
063
064    static {
065        try (InitTimer t0 = timer("HotSpotGraalRuntime.<clinit>")) {
066            try (InitTimer t = timer("HotSpotGraalRuntime.<init>")) {
067                instance = new HotSpotGraalRuntime();
068            }
069
070            try (InitTimer t = timer("HotSpotGraalRuntime.completeInitialization")) {
071                // Why deferred initialization? See comment in completeInitialization().
072                instance.completeInitialization();
073            }
074        }
075    }
076
077    /**
078     * Gets the singleton {@link HotSpotGraalRuntime} object.
079     */
080    public static HotSpotGraalRuntime runtime() {
081        assert instance != null;
082        return instance;
083    }
084
085    @Override
086    public HotSpotJVMCIRuntimeProvider getJVMCIRuntime() {
087        return jvmciRuntime;
088    }
089
090    private boolean checkArrayIndexScaleInvariants() {
091        assert getJVMCIRuntime().getArrayIndexScale(Kind.Byte) == 1;
092        assert getJVMCIRuntime().getArrayIndexScale(Kind.Boolean) == 1;
093        assert getJVMCIRuntime().getArrayIndexScale(Kind.Char) == 2;
094        assert getJVMCIRuntime().getArrayIndexScale(Kind.Short) == 2;
095        assert getJVMCIRuntime().getArrayIndexScale(Kind.Int) == 4;
096        assert getJVMCIRuntime().getArrayIndexScale(Kind.Long) == 8;
097        assert getJVMCIRuntime().getArrayIndexScale(Kind.Float) == 4;
098        assert getJVMCIRuntime().getArrayIndexScale(Kind.Double) == 8;
099        return true;
100    }
101
102    public static class Options {
103
104        // @formatter:off
105        @Option(help = "The runtime configuration to use", type = OptionType.Expert)
106        static final OptionValue<String> GraalRuntime = new OptionValue<>("");
107        // @formatter:on
108    }
109
110    private static HotSpotBackendFactory findFactory(String architecture) {
111        HotSpotBackendFactory basic = null;
112        HotSpotBackendFactory selected = null;
113        HotSpotBackendFactory nonBasic = null;
114        int nonBasicCount = 0;
115
116        assert GraalRuntime.getValue().equals(HotSpotJVMCIRuntime.Options.JVMCIRuntime.getValue());
117
118        for (HotSpotBackendFactory factory : Services.load(HotSpotBackendFactory.class)) {
119            if (factory.getArchitecture().equalsIgnoreCase(architecture)) {
120                if (factory.getGraalRuntimeName().equals(GraalRuntime.getValue())) {
121                    assert selected == null || checkFactoryOverriding(selected, factory);
122                    selected = factory;
123                }
124                if (factory.getGraalRuntimeName().equals("basic")) {
125                    assert basic == null || checkFactoryOverriding(basic, factory);
126                    basic = factory;
127                } else {
128                    nonBasic = factory;
129                    nonBasicCount++;
130                }
131            }
132        }
133
134        if (selected != null) {
135            return selected;
136        } else {
137            if (!GraalRuntime.getValue().equals("")) {
138                // Fail fast if a non-default value for GraalRuntime was specified
139                // and the corresponding factory is not available
140                throw new JVMCIError("Specified runtime \"%s\" not available for the %s architecture", GraalRuntime.getValue(), architecture);
141            } else if (nonBasicCount == 1) {
142                // If there is exactly one non-basic runtime, select this one.
143                return nonBasic;
144            } else {
145                return basic;
146            }
147        }
148    }
149
150    /**
151     * Checks that a factory overriding is valid. A factory B can only override/replace a factory A
152     * if the B.getClass() is a subclass of A.getClass(). This models the assumption that B is
153     * extends the behavior of A and has therefore understood the behavior expected of A.
154     *
155     * @param baseFactory
156     * @param overridingFactory
157     */
158    private static boolean checkFactoryOverriding(HotSpotBackendFactory baseFactory, HotSpotBackendFactory overridingFactory) {
159        return baseFactory.getClass().isAssignableFrom(overridingFactory.getClass());
160    }
161
162    /**
163     * Gets the kind of a word value on the {@linkplain #getHostBackend() host} backend.
164     */
165    public static Kind getHostWordKind() {
166        return instance.getHostBackend().getTarget().wordKind;
167    }
168
169    /**
170     * Reads a klass pointer from a constant object.
171     */
172    public static long unsafeReadKlassPointer(Object object) {
173        return instance.getCompilerToVM().readUnsafeKlassPointer(object);
174    }
175
176    /**
177     * Reads a word value from a given object.
178     */
179    public static long unsafeReadWord(Object object, long offset) {
180        if (getHostWordKind() == Kind.Long) {
181            return unsafe.getLong(object, offset);
182        }
183        return unsafe.getInt(object, offset) & 0xFFFFFFFFL;
184    }
185
186    private final HotSpotBackend hostBackend;
187    private DebugValuesPrinter debugValuesPrinter;
188
189    /**
190     * Graal mirrors are stored as a {@link ClassValue} associated with the {@link Class} of the
191     * type. This data structure stores both {@link HotSpotResolvedObjectType} and
192     * {@link HotSpotResolvedPrimitiveType} types.
193     */
194    private final ClassValue<ResolvedJavaType> graalMirrors = new ClassValue<ResolvedJavaType>() {
195        @Override
196        protected ResolvedJavaType computeValue(Class<?> javaClass) {
197            if (javaClass.isPrimitive()) {
198                Kind kind = Kind.fromJavaClass(javaClass);
199                return new HotSpotResolvedPrimitiveType(kind);
200            } else {
201                return new HotSpotResolvedObjectTypeImpl(javaClass);
202            }
203        }
204    };
205
206    private final Map<Class<? extends Architecture>, HotSpotBackend> backends = new HashMap<>();
207
208    private final HotSpotJVMCIRuntime jvmciRuntime;
209
210    private HotSpotGraalRuntime() {
211
212        jvmciRuntime = (HotSpotJVMCIRuntime) JVMCI.getRuntime();
213
214        HotSpotVMConfig config = getConfig();
215        CompileTheWorld.Options.overrideWithNativeOptions(config);
216
217        // Only set HotSpotPrintInlining if it still has its default value (false).
218        if (HotSpotPrintInlining.getValue() == false) {
219            HotSpotPrintInlining.setValue(config.printInlining);
220        }
221
222        if (Boolean.valueOf(System.getProperty("graal.printconfig"))) {
223            printConfig(config);
224        }
225
226        String hostArchitecture = config.getHostArchitectureName();
227
228        HotSpotBackendFactory factory;
229        try (InitTimer t = timer("find factory:", hostArchitecture)) {
230            factory = findFactory(hostArchitecture);
231        }
232        try (InitTimer t = timer("create backend:", hostArchitecture)) {
233            hostBackend = registerBackend(factory.createBackend(this, jvmciRuntime.getHostJVMCIBackend(), null));
234        }
235
236        String[] gpuArchitectures = getGPUArchitectureNames(getCompilerToVM());
237        for (String arch : gpuArchitectures) {
238            try (InitTimer t = timer("find factory:", arch)) {
239                factory = findFactory(arch);
240            }
241            if (factory == null) {
242                throw new JVMCIError("No backend available for specified GPU architecture \"%s\"", arch);
243            }
244            try (InitTimer t = timer("create backend:", arch)) {
245                registerBackend(factory.createBackend(this, null, hostBackend));
246            }
247        }
248    }
249
250    /**
251     * Do deferred initialization.
252     */
253    private void completeInitialization() {
254
255        if (Log.getValue() == null && !areScopedMetricsOrTimersEnabled() && Dump.getValue() == null && Verify.getValue() == null) {
256            if (MethodFilter.getValue() != null) {
257                TTY.println("WARNING: Ignoring MethodFilter option since Log, Meter, Time, TrackMemUse, Dump and Verify options are all null");
258            }
259        }
260
261        if (Debug.isEnabled()) {
262            DebugEnvironment.initialize(TTY.out);
263
264            String summary = DebugValueSummary.getValue();
265            if (summary != null) {
266                switch (summary) {
267                    case "Name":
268                    case "Partial":
269                    case "Complete":
270                    case "Thread":
271                        break;
272                    default:
273                        throw new JVMCIError("Unsupported value for DebugSummaryValue: %s", summary);
274                }
275            }
276        }
277
278        if (Debug.areUnconditionalMetricsEnabled() || Debug.areUnconditionalTimersEnabled() || (Debug.isEnabled() && areScopedMetricsOrTimersEnabled())) {
279            // This must be created here to avoid loading the DebugValuesPrinter class
280            // during shutdown() which in turn can cause a deadlock
281            debugValuesPrinter = new DebugValuesPrinter();
282        }
283
284        // Complete initialization of backends
285        try (InitTimer st = timer(hostBackend.getTarget().arch.getName(), ".completeInitialization")) {
286            hostBackend.completeInitialization();
287        }
288        for (HotSpotBackend backend : backends.values()) {
289            if (backend != hostBackend) {
290                try (InitTimer st = timer(backend.getTarget().arch.getName(), ".completeInitialization")) {
291                    backend.completeInitialization();
292                }
293            }
294        }
295
296        BenchmarkCounters.initialize(getCompilerToVM());
297
298        assert checkArrayIndexScaleInvariants();
299
300        runtimeStartTime = System.nanoTime();
301    }
302
303    private HotSpotBackend registerBackend(HotSpotBackend backend) {
304        Class<? extends Architecture> arch = backend.getTarget().arch.getClass();
305        HotSpotBackend oldValue = backends.put(arch, backend);
306        assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName();
307        return backend;
308    }
309
310    public ResolvedJavaType fromClass(Class<?> javaClass) {
311        return graalMirrors.get(javaClass);
312    }
313
314    /**
315     * Gets the names of the supported GPU architectures for the purpose of finding the
316     * corresponding {@linkplain HotSpotBackendFactory backend} objects.
317     */
318    private static String[] getGPUArchitectureNames(CompilerToVM c2vm) {
319        String gpuList = c2vm.getGPUs();
320        if (!gpuList.isEmpty()) {
321            String[] gpus = gpuList.split(",");
322            return gpus;
323        }
324        return new String[0];
325    }
326
327    private static void printConfig(HotSpotVMConfig config) {
328        Field[] fields = config.getClass().getDeclaredFields();
329        Map<String, Field> sortedFields = new TreeMap<>();
330        for (Field f : fields) {
331            f.setAccessible(true);
332            sortedFields.put(f.getName(), f);
333        }
334        for (Field f : sortedFields.values()) {
335            try {
336                Logger.info(String.format("%9s %-40s = %s", f.getType().getSimpleName(), f.getName(), Logger.pretty(f.get(config))));
337            } catch (Exception e) {
338            }
339        }
340    }
341
342    public HotSpotProviders getHostProviders() {
343        return getHostBackend().getProviders();
344    }
345
346    @Override
347    public String getName() {
348        return getClass().getSimpleName();
349    }
350
351    private final NodeCollectionsProvider nodeCollectionsProvider = new DefaultNodeCollectionsProvider();
352
353    @SuppressWarnings("unchecked")
354    @Override
355    public <T> T getCapability(Class<T> clazz) {
356        if (clazz == RuntimeProvider.class) {
357            return (T) this;
358        } else if (clazz == CollectionsProvider.class || clazz == NodeCollectionsProvider.class) {
359            return (T) nodeCollectionsProvider;
360        } else if (clazz == StackIntrospection.class) {
361            return (T) this;
362        } else if (clazz == SnippetReflectionProvider.class) {
363            return (T) getHostProviders().getSnippetReflection();
364        }
365        return null;
366    }
367
368    public HotSpotBackend getHostBackend() {
369        return hostBackend;
370    }
371
372    public <T extends Architecture> Backend getBackend(Class<T> arch) {
373        assert arch != Architecture.class;
374        return backends.get(arch);
375    }
376
377    public Map<Class<? extends Architecture>, HotSpotBackend> getBackends() {
378        return Collections.unmodifiableMap(backends);
379    }
380
381    @Override
382    public <T> T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor<T> visitor) {
383        final long[] initialMetaMethods = toMeta(initialMethods);
384        final long[] matchingMetaMethods = toMeta(matchingMethods);
385
386        CompilerToVM compilerToVM = getCompilerToVM();
387        HotSpotStackFrameReference current = compilerToVM.getNextStackFrame(null, initialMetaMethods, initialSkip);
388        while (current != null) {
389            T result = visitor.visitFrame(current);
390            if (result != null) {
391                return result;
392            }
393            current = compilerToVM.getNextStackFrame(current, matchingMetaMethods, 0);
394        }
395        return null;
396    }
397
398    private static long[] toMeta(ResolvedJavaMethod[] methods) {
399        if (methods == null) {
400            return null;
401        } else {
402            long[] result = new long[methods.length];
403            for (int i = 0; i < result.length; i++) {
404                result[i] = ((HotSpotResolvedJavaMethodImpl) methods[i]).getMetaspaceMethod();
405            }
406            return result;
407        }
408    }
409
410    private long runtimeStartTime;
411
412    /**
413     * Take action related to entering a new execution phase.
414     *
415     * @param phase the execution phase being entered
416     */
417    static void phaseTransition(String phase) {
418        CompilationStatistics.clear(phase);
419    }
420
421    void shutdown() {
422        if (debugValuesPrinter != null) {
423            debugValuesPrinter.printDebugValues();
424        }
425        phaseTransition("final");
426
427        SnippetCounter.printGroups(TTY.out().out());
428        BenchmarkCounters.shutdown(getCompilerToVM(), runtimeStartTime);
429    }
430}