/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt;
import org.jikesrvm.classloader.VM_Atom;
import org.jikesrvm.classloader.VM_Class;
import org.jikesrvm.classloader.VM_Method;
import org.jikesrvm.util.VM_HashMap;
import org.jikesrvm.util.VM_HashSet;
/**
* This class holds, for each interface, the set of initialized classes
* that implement the interface.
*/
public class OPT_InterfaceHierarchy {
/**
* a mapping from VM_Class (an interface) to a set of classes that
* claim to implement this interface.
*/
private static VM_HashMap<VM_Class, VM_HashSet<VM_Class>> interfaceMapping =
new VM_HashMap<VM_Class, VM_HashSet<VM_Class>>();
/**
* Notify this dictionary that a new class has been initialized.
* This method updates the dictionary to record the interface
* implementors.
*/
public static synchronized void notifyClassInitialized(VM_Class c) {
if (!c.isInterface()) {
for (VM_Class intf : c.getAllImplementedInterfaces()) {
noteImplements(c, intf);
}
}
}
/**
* Note that class c implements interface I;
*/
private static void noteImplements(VM_Class c, VM_Class I) {
VM_HashSet<VM_Class> implementsSet = findOrCreateSet(I);
implementsSet.add(c);
}
/**
* Return the set of classes that implement a given interface. Create a
* set if none found.
*/
private static synchronized VM_HashSet<VM_Class> findOrCreateSet(VM_Class I) {
VM_HashSet<VM_Class> set = interfaceMapping.get(I);
if (set == null) {
set = new VM_HashSet<VM_Class>(3);
interfaceMapping.put(I, set);
}
return set;
}
/**
* Return the set of all classes known to implement interface I.
*/
private static VM_HashSet<VM_Class> allImplementors(VM_Class I) {
// get the set of classes registered as implementing I
VM_HashSet<VM_Class> result = findOrCreateSet(I);
// also add any classes that implement a sub-interface of I.
// need to do this kludge to avoid recursive concurrent modification
for (VM_Class subClass : I.getSubClasses()) {
result.addAll(allImplementors(subClass));
}
// also add any sub-classes of these classes.
// need to cache additions to avoid modifying the set while iterating
VM_HashSet<VM_Class> toAdd = new VM_HashSet<VM_Class>(5);
for (VM_Class c : result) {
toAdd.addAll(allSubClasses(c));
}
result.addAll(toAdd);
return result;
}
/**
* Return the set of all classes known to extend C
*/
private static VM_HashSet<VM_Class> allSubClasses(VM_Class C) {
VM_HashSet<VM_Class> result = new VM_HashSet<VM_Class>(5);
// also add any classes that implement a sub-interface of I.
for (VM_Class subClass : C.getSubClasses()) {
result.add(subClass);
result.addAll(allSubClasses(subClass));
}
return result;
}
/**
* If, in the current class hierarchy, there is exactly one method that
* defines the interface method foo, then return the unique
* implementation. If there is not a unique implementation, return
* null.
*/
public static synchronized VM_Method getUniqueImplementation(VM_Method foo) {
VM_Class I = foo.getDeclaringClass();
VM_HashSet<VM_Class> classes = allImplementors(I);
VM_Method firstMethod = null;
VM_Atom name = foo.getName();
VM_Atom desc = foo.getDescriptor();
for (VM_Class klass : classes) {
VM_Method m = klass.findDeclaredMethod(name, desc);
if (firstMethod == null) {
firstMethod = m;
}
if (m != firstMethod) {
return null;
}
}
return firstMethod;
}
}