/* * 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.actor.holder; import java.util.*; import com.sun.max.annotate.*; import com.sun.max.program.*; import com.sun.max.vm.*; import com.sun.max.vm.runtime.*; import com.sun.max.vm.type.*; /** * Management of unique integer identifiers for {@link ClassActor}s. * * Every class in the system is assigned a globally unique identifier. This * identifier is used in the implementation of interface dispatch, type * tests and also serves as the opaque {@code jclass} handle to a * class in JNI code. */ public final class ClassIDManager { /** * Value to be used as invalid class id. */ public static int NULL_CLASS_ID = -1; private ClassIDManager() { } static final int MINIMAL_CLASSES_POPULATIONS = 4000; private static final LinearIDMap<ClassActor> idToClassActor = new LinearIDMap<ClassActor>(MINIMAL_CLASSES_POPULATIONS); /** * A bit set keeping track of the assigned class identifiers. A bit set to 1 doesn't necessarily mean a * non-null entry in {@link ClassIDManager#idToClassActor} as class identifiers are reserved eagerly for array classes, * whereas the corresponding array class actors are created lazily. * Thus it is possible to encounter a null entry for a used class identifier. */ private static BitSet usedIDs = new BitSet(); /** * Retrieves the class corresponding to a given identifier. * * @param id a class identifier * @return the class denoted by {@code id} */ public static ClassActor toClassActor(int id) { if (MaxineVM.isHosted() && mapping != null) { synchronized (mapping) { final ClassActor classActor = mapping.idToClassActor(id); if (classActor != null) { return classActor; } } } return idToClassActor.get(id); } /** * Allocates a new, system-wide unique identifier that will subsequently be * {@linkplain #register(ClassActor) bound} to a class actor. */ static synchronized int allocate() { final int id = usedIDs.nextClearBit(0); idToClassActor.set(id, null); usedIDs.set(id); if (TraceClassIDs) { Log.println("Allocated class identifier " + id); } return id; } /** * Binds a class actor to its allocated identifier. */ static synchronized void register(ClassActor classActor) { int id = classActor.id; FatalError.check(usedIDs.get(id), "Class ID must be allocated: id=" + id + ", class=" + classActor); idToClassActor.set(id, classActor); if (TraceClassIDs) { Log.println("Bound class identifier " + id + " to " + classActor); } } /** * Removes all identifiers associated with a given class. This must only be * called before a class is registered with its class loader. * * @see ClassRegistry#define0(ClassActor) */ public static synchronized void remove(ClassActor classActor) { assert ClassRegistry.get(classActor.classLoader, classActor.typeDescriptor, false) != classActor; int id = classActor.id; FatalError.check(usedIDs.get(id), "Class ID must be allocated"); FatalError.check(classActor.arrayClassIDs == null, "Can remove class ID only when no array classes were registered yet"); clear(id); } private static void clear(int id) { ClassActor c = idToClassActor.set(id, null); usedIDs.clear(id); if (TraceClassIDs) { Log.print("Released class identifier " + id); if (c != null) { Log.print(" {" + c + "}"); } Log.println(); } } private static boolean TraceClassIDs; static { VMOptions.addFieldOption("-XX:", "TraceClassIDs", "Trace management of class identifiers."); } public static synchronized int largestClassId() { return idToClassActor.maxID(); } @HOSTED_ONLY private static final BitSet createdArrayClassIDs = new BitSet(); @HOSTED_ONLY public static boolean traceArrayClassIDs = false; @HOSTED_ONLY public static void recordArrayClassID(ClassActor elementClass, int dimension, int id) { if (traceArrayClassIDs) { createdArrayClassIDs.set(id); StringBuffer sb = new StringBuffer("Class ID "); for (int d = 0; d <= dimension; d++) { sb.append('['); } sb.append(elementClass.name()); sb.append(" => "); sb.append(id); Trace.line(1, sb); } } @HOSTED_ONLY public static void validateUsedClassIds() { if (!traceArrayClassIDs) { return; } int id = 0; id = createdArrayClassIDs.nextSetBit(0); while (id >= 0) { ClassActor classActor = idToClassActor.get(id); if (classActor == null) { System.out.print("Class ID " + id + " created for array isn't assigned"); if (usedIDs.get(id)) { System.out.print(" but recorded used"); } System.out.println(); } else if (!(classActor instanceof ArrayClassActor)) { System.out.println("Class ID " + id + " created for array isn't assigned to class array but to " + classActor.name()); } id = createdArrayClassIDs.nextSetBit(id + 1); } id = 0; while (id >= 0) { ClassActor classActor = idToClassActor.get(id); if (classActor != null && classActor.arrayClassIDs != null) { final int [] arrayClassIDs = classActor.arrayClassIDs; for (int i = 0; i < arrayClassIDs.length; i++) { ClassActor arrayClassActor = idToClassActor.get(arrayClassIDs[i]); if (arrayClassActor == null) { System.out.print("Class ID " + arrayClassIDs[i] + " created for array isn't assigned"); if (usedIDs.get(arrayClassIDs[i])) { System.out.print(" but recorded used"); } System.out.println(); } else if (!(arrayClassActor instanceof ArrayClassActor) || arrayClassActor.elementClassActor() != classActor) { System.out.print("Class ID " + arrayClassIDs[i] + " is not an array class id for element class " + id); } } } id = usedIDs.nextSetBit(id + 1); } } public static boolean isUsedID(int id) { return usedIDs.get(id); } /** * Inspector support. */ @HOSTED_ONLY public interface Mapping { ClassActor idToClassActor(int id); } @HOSTED_ONLY private static Mapping mapping; @HOSTED_ONLY public static void setMapping(Mapping map) { mapping = map; } }