001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.jikesrvm.compilers.opt.inlining;
014
015 import org.jikesrvm.classloader.Atom;
016 import org.jikesrvm.classloader.RVMClass;
017 import org.jikesrvm.classloader.RVMMethod;
018 import org.jikesrvm.util.ImmutableEntryHashMapRVM;
019 import org.jikesrvm.util.ImmutableEntryHashSetRVM;
020
021 /**
022 * This class holds, for each interface, the set of initialized classes
023 * that implement the interface.
024 */
025 public class InterfaceHierarchy {
026
027 /**
028 * a mapping from RVMClass (an interface) to a set of classes that
029 * claim to implement this interface.
030 */
031 private static final ImmutableEntryHashMapRVM<RVMClass, ImmutableEntryHashSetRVM<RVMClass>> interfaceMapping =
032 new ImmutableEntryHashMapRVM<RVMClass, ImmutableEntryHashSetRVM<RVMClass>>();
033
034 /**
035 * Notify this dictionary that a new class has been initialized.
036 * This method updates the dictionary to record the interface
037 * implementors.
038 */
039 public static synchronized void notifyClassInitialized(RVMClass c) {
040 if (!c.isInterface()) {
041 for (RVMClass intf : c.getAllImplementedInterfaces()) {
042 noteImplements(c, intf);
043 }
044 }
045 }
046
047 /**
048 * Note that class c implements interface I;
049 */
050 private static void noteImplements(RVMClass c, RVMClass I) {
051 ImmutableEntryHashSetRVM<RVMClass> implementsSet = findOrCreateSet(I);
052 implementsSet.add(c);
053 }
054
055 /**
056 * Return the set of classes that implement a given interface. Create a
057 * set if none found.
058 */
059 private static synchronized ImmutableEntryHashSetRVM<RVMClass> findOrCreateSet(RVMClass I) {
060 ImmutableEntryHashSetRVM<RVMClass> set = interfaceMapping.get(I);
061 if (set == null) {
062 set = new ImmutableEntryHashSetRVM<RVMClass>(3);
063 interfaceMapping.put(I, set);
064 }
065 return set;
066 }
067
068 /**
069 * Return the set of all classes known to implement interface I.
070 */
071 private static ImmutableEntryHashSetRVM<RVMClass> allImplementors(RVMClass I) {
072 // get the set of classes registered as implementing I
073 ImmutableEntryHashSetRVM<RVMClass> result = findOrCreateSet(I);
074
075 // also add any classes that implement a sub-interface of I.
076 // need to do this kludge to avoid recursive concurrent modification
077 for (RVMClass subClass : I.getSubClasses()) {
078 result.addAll(allImplementors(subClass));
079 }
080
081 // also add any sub-classes of these classes.
082 // need to cache additions to avoid modifying the set while iterating
083 ImmutableEntryHashSetRVM<RVMClass> toAdd = new ImmutableEntryHashSetRVM<RVMClass>(5);
084 for (RVMClass c : result) {
085 toAdd.addAll(allSubClasses(c));
086 }
087 result.addAll(toAdd);
088
089 return result;
090 }
091
092 /**
093 * Return the set of all classes known to extend C
094 */
095 private static ImmutableEntryHashSetRVM<RVMClass> allSubClasses(RVMClass C) {
096 ImmutableEntryHashSetRVM<RVMClass> result = new ImmutableEntryHashSetRVM<RVMClass>(5);
097
098 // also add any classes that implement a sub-interface of I.
099 for (RVMClass subClass : C.getSubClasses()) {
100 result.add(subClass);
101 result.addAll(allSubClasses(subClass));
102 }
103
104 return result;
105 }
106
107 /**
108 * If, in the current class hierarchy, there is exactly one method that
109 * defines the interface method foo, then return the unique
110 * implementation. If there is not a unique implementation, return
111 * null.
112 */
113 public static synchronized RVMMethod getUniqueImplementation(RVMMethod foo) {
114 RVMClass I = foo.getDeclaringClass();
115
116 ImmutableEntryHashSetRVM<RVMClass> classes = allImplementors(I);
117 RVMMethod firstMethod = null;
118 Atom name = foo.getName();
119 Atom desc = foo.getDescriptor();
120
121 for (RVMClass klass : classes) {
122 RVMMethod m = klass.findDeclaredMethod(name, desc);
123 if (firstMethod == null) {
124 firstMethod = m;
125 }
126
127 if (m != firstMethod) {
128 return null;
129 }
130 }
131 return firstMethod;
132 }
133 }