001/*
002 * Copyright (c) 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 jdk.internal.jvmci.hotspot;
024
025import static jdk.internal.jvmci.common.UnsafeAccess.*;
026import static jdk.internal.jvmci.hotspot.InitTimer.*;
027
028import java.util.*;
029
030import jdk.internal.jvmci.code.*;
031import jdk.internal.jvmci.common.*;
032import jdk.internal.jvmci.meta.*;
033import jdk.internal.jvmci.options.*;
034import jdk.internal.jvmci.runtime.*;
035import jdk.internal.jvmci.service.*;
036
037//JaCoCo Exclude
038
039public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider, HotSpotProxified {
040
041    private static final HotSpotJVMCIRuntime instance;
042
043    static {
044        try (InitTimer t0 = timer("HotSpotJVMCIRuntime.<clinit>")) {
045            try (InitTimer t = timer("HotSpotJVMCIRuntime.<init>")) {
046                instance = new HotSpotJVMCIRuntime();
047            }
048
049            try (InitTimer t = timer("HotSpotJVMCIRuntime.completeInitialization")) {
050                // Why deferred initialization? See comment in completeInitialization().
051                instance.completeInitialization();
052            }
053        }
054    }
055
056    /**
057     * Gets the singleton {@link HotSpotJVMCIRuntime} object.
058     */
059    public static HotSpotJVMCIRuntime runtime() {
060        assert instance != null;
061        return instance;
062    }
063
064    /**
065     * Do deferred initialization.
066     */
067    public void completeInitialization() {
068
069        // Proxies for the VM/Compiler interfaces cannot be initialized
070        // in the constructor as proxy creation causes static
071        // initializers to be executed for all the types involved in the
072        // proxied methods. Some of these static initializers (e.g. in
073        // HotSpotMethodData) rely on the static 'instance' field being set
074        // to retrieve configuration details.
075        CompilerToVM toVM = this.compilerToVm;
076
077        for (HotSpotVMEventListener vmEventListener : vmEventListeners) {
078            toVM = vmEventListener.completeInitialization(this, toVM);
079        }
080
081        this.compilerToVm = toVM;
082    }
083
084    public static class Options {
085
086        // @formatter:off
087        @Option(help = "The JVMCI runtime configuration to use", type = OptionType.Expert)
088        public static final OptionValue<String> JVMCIRuntime = new OptionValue<>("");
089
090        @Option(help = "File to which logging is sent.  A %p in the name will be replaced with a string identifying the process, usually the process id.", type = OptionType.Expert)
091        public static final PrintStreamOption LogFile = new PrintStreamOption();
092        // @formatter:on
093    }
094
095    public static HotSpotJVMCIBackendFactory findFactory(String architecture) {
096        HotSpotJVMCIBackendFactory basic = null;
097        HotSpotJVMCIBackendFactory selected = null;
098        HotSpotJVMCIBackendFactory nonBasic = null;
099        int nonBasicCount = 0;
100
101        for (HotSpotJVMCIBackendFactory factory : Services.load(HotSpotJVMCIBackendFactory.class)) {
102            if (factory.getArchitecture().equalsIgnoreCase(architecture)) {
103                if (factory.getJVMCIRuntimeName().equals(Options.JVMCIRuntime.getValue())) {
104                    assert selected == null || checkFactoryOverriding(selected, factory);
105                    selected = factory;
106                }
107                if (factory.getJVMCIRuntimeName().equals("basic")) {
108                    assert basic == null || checkFactoryOverriding(basic, factory);
109                    basic = factory;
110                } else {
111                    nonBasic = factory;
112                    nonBasicCount++;
113                }
114            }
115        }
116
117        if (selected != null) {
118            return selected;
119        } else {
120            if (!Options.JVMCIRuntime.getValue().equals("")) {
121                // Fail fast if a non-default value for JVMCIRuntime was specified
122                // and the corresponding factory is not available
123                throw new JVMCIError("Specified runtime \"%s\" not available for the %s architecture", Options.JVMCIRuntime.getValue(), architecture);
124            } else if (nonBasicCount == 1) {
125                // If there is exactly one non-basic runtime, select this one.
126                return nonBasic;
127            } else {
128                return basic;
129            }
130        }
131    }
132
133    /**
134     * Checks that a factory overriding is valid. A factory B can only override/replace a factory A
135     * if the B.getClass() is a subclass of A.getClass(). This models the assumption that B is
136     * extends the behavior of A and has therefore understood the behavior expected of A.
137     *
138     * @param baseFactory
139     * @param overridingFactory
140     */
141    private static boolean checkFactoryOverriding(HotSpotJVMCIBackendFactory baseFactory, HotSpotJVMCIBackendFactory overridingFactory) {
142        return baseFactory.getClass().isAssignableFrom(overridingFactory.getClass());
143    }
144
145    /**
146     * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend.
147     */
148    public static Kind getHostWordKind() {
149        return instance.getHostJVMCIBackend().getCodeCache().getTarget().wordKind;
150    }
151
152    /**
153     * Reads a klass pointer from a constant object.
154     */
155    public static long unsafeReadKlassPointer(Object object) {
156        return instance.getCompilerToVM().readUnsafeKlassPointer(object);
157    }
158
159    /**
160     * Reads a word value from a given object.
161     */
162    public static long unsafeReadWord(Object object, long offset) {
163        if (getHostWordKind() == Kind.Long) {
164            return unsafe.getLong(object, offset);
165        }
166        return unsafe.getInt(object, offset) & 0xFFFFFFFFL;
167    }
168
169    protected/* final */CompilerToVM compilerToVm;
170
171    protected final HotSpotVMConfig config;
172    private final JVMCIBackend hostBackend;
173
174    /**
175     * JVMCI mirrors are stored as a {@link ClassValue} associated with the {@link Class} of the
176     * type. This data structure stores both {@link HotSpotResolvedObjectType} and
177     * {@link HotSpotResolvedPrimitiveType} types.
178     */
179    private final ClassValue<ResolvedJavaType> jvmciMirrors = new ClassValue<ResolvedJavaType>() {
180        @Override
181        protected ResolvedJavaType computeValue(Class<?> javaClass) {
182            if (javaClass.isPrimitive()) {
183                Kind kind = Kind.fromJavaClass(javaClass);
184                return new HotSpotResolvedPrimitiveType(kind);
185            } else {
186                return new HotSpotResolvedObjectTypeImpl(javaClass);
187            }
188        }
189    };
190
191    private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>();
192
193    private final Iterable<HotSpotVMEventListener> vmEventListeners;
194
195    private HotSpotJVMCIRuntime() {
196        CompilerToVM toVM = new CompilerToVMImpl();
197        compilerToVm = toVM;
198        try (InitTimer t = timer("HotSpotVMConfig<init>")) {
199            config = new HotSpotVMConfig(compilerToVm);
200        }
201
202        String hostArchitecture = config.getHostArchitectureName();
203
204        HotSpotJVMCIBackendFactory factory;
205        try (InitTimer t = timer("find factory:", hostArchitecture)) {
206            factory = findFactory(hostArchitecture);
207        }
208        try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) {
209            hostBackend = registerBackend(factory.createJVMCIBackend(this, null));
210        }
211
212        Iterable<HotSpotVMEventListener> listeners = Services.load(HotSpotVMEventListener.class);
213        if (!listeners.iterator().hasNext()) {
214            listeners = Arrays.asList(new HotSpotVMEventListener() {
215            });
216        }
217        vmEventListeners = listeners;
218    }
219
220    private JVMCIBackend registerBackend(JVMCIBackend backend) {
221        Class<? extends Architecture> arch = backend.getCodeCache().getTarget().arch.getClass();
222        JVMCIBackend oldValue = backends.put(arch, backend);
223        assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName();
224        return backend;
225    }
226
227    public ResolvedJavaType fromClass(Class<?> javaClass) {
228        return jvmciMirrors.get(javaClass);
229    }
230
231    public HotSpotVMConfig getConfig() {
232        return config;
233    }
234
235    public CompilerToVM getCompilerToVM() {
236        return compilerToVm;
237    }
238
239    public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) {
240        Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class");
241        // If the name represents a primitive type we can short-circuit the lookup.
242        if (name.length() == 1) {
243            Kind kind = Kind.fromPrimitiveOrVoidTypeChar(name.charAt(0));
244            return fromClass(kind.toJavaClass());
245        }
246
247        // Resolve non-primitive types in the VM.
248        HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType;
249        final long metaspaceKlass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve);
250
251        if (metaspaceKlass == 0L) {
252            assert resolve == false;
253            return HotSpotUnresolvedJavaType.create(this, name);
254        }
255        return HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass);
256    }
257
258    public JVMCIBackend getHostJVMCIBackend() {
259        return hostBackend;
260    }
261
262    public <T extends Architecture> JVMCIBackend getJVMCIBackend(Class<T> arch) {
263        assert arch != Architecture.class;
264        return backends.get(arch);
265    }
266
267    public Map<Class<? extends Architecture>, JVMCIBackend> getBackends() {
268        return Collections.unmodifiableMap(backends);
269    }
270
271    /**
272     * Called from the VM.
273     */
274    @SuppressWarnings({"unused"})
275    private void compileMetaspaceMethod(long metaspaceMethod, int entryBCI, long jvmciEnv, int id) {
276        for (HotSpotVMEventListener vmEventListener : vmEventListeners) {
277            vmEventListener.compileMetaspaceMethod(metaspaceMethod, entryBCI, jvmciEnv, id);
278        }
279    }
280
281    /**
282     * Called from the VM.
283     */
284    @SuppressWarnings({"unused"})
285    private void compileTheWorld() throws Throwable {
286        for (HotSpotVMEventListener vmEventListener : vmEventListeners) {
287            vmEventListener.notifyCompileTheWorld();
288        }
289    }
290
291    /**
292     * Shuts down the runtime.
293     *
294     * Called from the VM.
295     */
296    @SuppressWarnings({"unused"})
297    private void shutdown() throws Exception {
298        for (HotSpotVMEventListener vmEventListener : vmEventListeners) {
299            vmEventListener.notifyShutdown();
300        }
301    }
302
303    /**
304     * Shuts down the runtime.
305     *
306     * Called from the VM.
307     *
308     * @param hotSpotCodeCacheProvider
309     */
310    void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompilationResult compResult) {
311        for (HotSpotVMEventListener vmEventListener : vmEventListeners) {
312            vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compResult);
313        }
314    }
315}