/* * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.max.vm; import static com.sun.max.vm.MaxineVM.*; import java.io.*; import java.util.*; import com.sun.max.annotate.*; import com.sun.max.config.*; import com.sun.max.platform.*; import com.sun.max.program.*; import com.sun.max.vm.heap.*; import com.sun.max.vm.hosted.*; import com.sun.max.vm.layout.*; import com.sun.max.vm.monitor.*; import com.sun.max.vm.reference.*; import com.sun.max.vm.run.*; import com.sun.max.vm.runtime.*; /** * The configuration of a VM is defined by: * <ul> * <li> a {@link BuildLevel} * <li> a set of {@link BootImagePackage boot-image packages} that will be in the boot image * <li> a specific subset of the boot-image packages that implement the {@link VMScheme} VM schemes. * </ul> * This information is all known at the time the instance is constructed. */ public final class VMConfiguration { public final BuildLevel buildLevel; @HOSTED_ONLY public final BootImagePackage referencePackage; @HOSTED_ONLY public final BootImagePackage layoutPackage; @HOSTED_ONLY public final BootImagePackage heapPackage; @HOSTED_ONLY public final BootImagePackage monitorPackage; @HOSTED_ONLY public final BootImagePackage runPackage; @HOSTED_ONLY public List<BootImagePackage> bootImagePackages; @HOSTED_ONLY private final Set<BootImagePackage> schemePackages = new HashSet<BootImagePackage>(); private ArrayList<VMScheme> vmSchemes = new ArrayList<VMScheme>(); private boolean areSchemesLoadedAndInstantiated = false; @INSPECTED @CONSTANT_WHEN_NOT_ZERO private ReferenceScheme referenceScheme; @INSPECTED @CONSTANT_WHEN_NOT_ZERO private LayoutScheme layoutScheme; @INSPECTED @CONSTANT_WHEN_NOT_ZERO private HeapScheme heapScheme; @INSPECTED @CONSTANT_WHEN_NOT_ZERO private MonitorScheme monitorScheme; @INSPECTED @CONSTANT_WHEN_NOT_ZERO private RunScheme runScheme; public VMConfiguration(BuildLevel buildLevel, Platform platform, BootImagePackage referencePackage, BootImagePackage layoutPackage, BootImagePackage heapPackage, BootImagePackage monitorPackage, BootImagePackage runPackage) { this.buildLevel = buildLevel; this.referencePackage = referencePackage; this.layoutPackage = layoutPackage; this.heapPackage = heapPackage; this.monitorPackage = monitorPackage; this.runPackage = runPackage; addSchemePackage(referencePackage); addSchemePackage(layoutPackage); addSchemePackage(heapPackage); addSchemePackage(monitorPackage); addSchemePackage(runPackage); } /** * Gather all the packages that might be part of the VM boot image by scanning the class * path from the well-defined root ({@code com.sun.max.config}) and looking for {@code Package} classes, * instantiating them, and in the process possibly following new roots. * We then ask each package if it should be included in the image in this configuration by * invoking the {@code isPartOfMaxineVM} method. That method may, particularly if it is * in a scheme instance, need to ask questions about the configuration we are constructing. * Valid questions concern the values (names) of the scheme packages and the classes * registered as the scheme implementations. Since the schemes have not be instantiated * at this stage, scheme instances cannot be used. i.e., one must use {@link Class#isAssignableFrom} * rather than {@code instanceof}. The method {@link #schemeImplClassIsSubClass} can be used to * check whether a given class is the same as or a subclass of the registered class for a given scheme. */ public VMConfiguration gatherBootImagePackages() { activeConfig = this; bootImagePackages = new ArrayList<BootImagePackage>(); for (BootImagePackage pkg : BootImagePackage.getTransitiveSubPackages( HostedVMClassLoader.HOSTED_VM_CLASS_LOADER.classpath(), new com.sun.max.config.Package())) { if (pkg.isPartOfMaxineVM(this)) { bootImagePackages.add(pkg); } } MaxineVM.registerBootImagePackages(bootImagePackages); return this; } private static VMConfiguration activeConfig; /** * Provides access to the {@link VMConfiguration} that initiated {@link #gatherBootImagePackages()}. */ public static VMConfiguration activeConfig() { return activeConfig; } private void addSchemePackage(BootImagePackage pkg) { if (pkg != null) { schemePackages.add(pkg); } } @INLINE public ReferenceScheme referenceScheme() { return referenceScheme; } @INLINE public LayoutScheme layoutScheme() { return layoutScheme; } @INLINE public HeapScheme heapScheme() { return heapScheme; } @INLINE public MonitorScheme monitorScheme() { return monitorScheme; } @INLINE public RunScheme runScheme() { return runScheme; } @HOSTED_ONLY public List<BootImagePackage> packages() { return Arrays.asList(new BootImagePackage[] { referencePackage, layoutPackage, heapPackage, monitorPackage, runPackage}); } public List<VMScheme> vmSchemes() { return vmSchemes; } /** * Checks whether the actual scheme class that implements a given scheme (class) in this configuration * is the same class or a subclass of another given class. * It is analogous to comparing the scheme package but allows an assignability check * within {@link BootImagePackage#isPartOfMaxineVM(VMConfiguration)} before * the schemes are instantiated. * @param <S> * @param schemeClass the scheme class being searched for * @param schemeSubClass the scheme class being checked * @return true iff the actual implementation class is same as or a subclass of schemeSubClass */ @HOSTED_ONLY public <S extends VMScheme> boolean schemeImplClassIsSubClass(Class<S> schemeClass, Class<? extends S> schemeSubClass) { for (BootImagePackage pkg : schemePackages) { final Class<? extends S> result = pkg.schemeTypeToImplementation(schemeClass); if (result != null && schemeSubClass.isAssignableFrom(result)) { return true; } } return false; } @HOSTED_ONLY private <VMScheme_Type extends VMScheme> VMScheme_Type loadAndInstantiateScheme(List<VMScheme> loadedSchemes, BootImagePackage p, Class<VMScheme_Type> vmSchemeType) { if (p == null) { throw ProgramError.unexpected("Package not found for scheme: " + vmSchemeType.getSimpleName()); } if (loadedSchemes != null) { Class< ? extends VMScheme_Type> impl = p.loadSchemeImplementation(vmSchemeType); for (VMScheme vmScheme : loadedSchemes) { if (vmScheme.getClass() == impl) { vmSchemes.add(vmScheme); return vmSchemeType.cast(vmScheme); } } } // If one implementation class in package p implements multiple schemes, then only a single // instance of that class is created and shared by the VM configuration for all the schemes // it implements. for (VMScheme vmScheme : vmSchemes) { if (vmSchemeType.isInstance(vmScheme) && p.loadSchemeImplementation(vmSchemeType).equals(vmScheme.getClass())) { return vmSchemeType.cast(vmScheme); } } final VMScheme_Type vmScheme = p.loadAndInstantiateScheme(vmSchemeType); vmSchemes.add(vmScheme); return vmScheme; } /** * Loads and instantiates all the schemes of this configuration. * * @param loadedSchemes the set of schemes already loaded and instantiated in this process. If non-{@code null}, * this list is used to prevent any given scheme implementation from being instantiated more than once. */ @HOSTED_ONLY public void loadAndInstantiateSchemes(List<VMScheme> loadedSchemes) { if (areSchemesLoadedAndInstantiated) { return; } referenceScheme = loadAndInstantiateScheme(loadedSchemes, referencePackage, ReferenceScheme.class); layoutScheme = loadAndInstantiateScheme(loadedSchemes, layoutPackage, LayoutScheme.class); monitorScheme = loadAndInstantiateScheme(loadedSchemes, monitorPackage, MonitorScheme.class); heapScheme = loadAndInstantiateScheme(loadedSchemes, heapPackage, HeapScheme.class); runScheme = loadAndInstantiateScheme(loadedSchemes, runPackage, RunScheme.class); areSchemesLoadedAndInstantiated = true; } public void initializeSchemes(MaxineVM.Phase phase) { vm().compilationBroker.initialize(phase); for (int i = 0; i < vmSchemes.size(); i++) { try { // Log.print("Initializing: "); // Log.print(vmSchemes.get(i).name()); // Log.print(" @"); // Log.println(phase.name()); vmSchemes.get(i).initialize(phase); } catch (Throwable t) { FatalError.unexpected("Error initializing scheme " + vmSchemes.get(i).name() + " in phase " + phase.name(), t); } } } /** * Convenience method for accessing the configuration associated with the * current {@linkplain MaxineVM#vm() VM} context. */ @FOLD public static VMConfiguration vmConfig() { return vm().config; } @Override public String toString() { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); print(new PrintStream(baos), ""); return baos.toString(); } public void print(PrintStream out, String indent) { out.println(indent + "Build level: " + buildLevel); for (VMScheme vmScheme : vmSchemes()) { final String specification = vmScheme.specification().getSimpleName(); out.println(indent + specification.replace("Scheme", " scheme") + ": " + vmScheme.about()); } out.println(indent + "Optimizing compiler: " + vm().compilationBroker.optimizingCompiler); out.println(indent + "Baseline compiler: " + vm().compilationBroker.baselineCompiler); } /** * Use {@link MaxineVM#isDebug()} instead of calling this directly. */ @FOLD public boolean debugging() { return buildLevel == BuildLevel.DEBUG; } }