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 */ 013package org.jikesrvm.compilers.opt.inlining; 014 015import org.jikesrvm.classloader.Atom; 016import org.jikesrvm.classloader.RVMClass; 017import org.jikesrvm.classloader.RVMMethod; 018import org.jikesrvm.util.ImmutableEntryHashMapRVM; 019import org.jikesrvm.util.ImmutableEntryHashSetRVM; 020 021/** 022 * This class holds, for each interface, the set of initialized classes 023 * that implement the interface. 024 */ 025public 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 * @param c class that was initialized 040 */ 041 public static synchronized void notifyClassInitialized(RVMClass c) { 042 if (!c.isInterface()) { 043 for (RVMClass intf : c.getAllImplementedInterfaces()) { 044 noteImplements(c, intf); 045 } 046 } 047 } 048 049 /** 050 * Notes that a class implements an interface. 051 * 052 * @param c the class that implements the interface 053 * @param I the implemented interface 054 */ 055 private static void noteImplements(RVMClass c, RVMClass I) { 056 ImmutableEntryHashSetRVM<RVMClass> implementsSet = findOrCreateSet(I); 057 implementsSet.add(c); 058 } 059 060 /** 061 * @param I the implemented interface 062 * @return the set of classes that implement a given interface. Create a 063 * set if none found. 064 */ 065 private static synchronized ImmutableEntryHashSetRVM<RVMClass> findOrCreateSet(RVMClass I) { 066 ImmutableEntryHashSetRVM<RVMClass> set = interfaceMapping.get(I); 067 if (set == null) { 068 set = new ImmutableEntryHashSetRVM<RVMClass>(3); 069 interfaceMapping.put(I, set); 070 } 071 return set; 072 } 073 074 /** 075 * @return the set of all classes known to implement the interface 076 * @param I the implemented interface 077 */ 078 private static ImmutableEntryHashSetRVM<RVMClass> allImplementors(RVMClass I) { 079 // get the set of classes registered as implementing I 080 ImmutableEntryHashSetRVM<RVMClass> result = findOrCreateSet(I); 081 082 // also add any classes that implement a sub-interface of I. 083 // need to do this kludge to avoid recursive concurrent modification 084 for (RVMClass subClass : I.getSubClasses()) { 085 result.addAll(allImplementors(subClass)); 086 } 087 088 // also add any sub-classes of these classes. 089 // need to cache additions to avoid modifying the set while iterating 090 ImmutableEntryHashSetRVM<RVMClass> toAdd = new ImmutableEntryHashSetRVM<RVMClass>(5); 091 for (RVMClass c : result) { 092 toAdd.addAll(allSubClasses(c)); 093 } 094 result.addAll(toAdd); 095 096 return result; 097 } 098 099 /** 100 * @param C an interface 101 * @return the set of all classes known to extend C 102 */ 103 private static ImmutableEntryHashSetRVM<RVMClass> allSubClasses(RVMClass C) { 104 ImmutableEntryHashSetRVM<RVMClass> result = new ImmutableEntryHashSetRVM<RVMClass>(5); 105 106 // also add any classes that implement a sub-interface of I. 107 for (RVMClass subClass : C.getSubClasses()) { 108 result.add(subClass); 109 result.addAll(allSubClasses(subClass)); 110 } 111 112 return result; 113 } 114 115 /** 116 * If, in the current class hierarchy, there is exactly one method that 117 * defines the interface method foo, then return the unique 118 * implementation. If there is not a unique implementation, return 119 * null. 120 * 121 * @param foo an interface method 122 * @return the unique implementation if it exists, {@code null} otherwise 123 */ 124 public static synchronized RVMMethod getUniqueImplementation(RVMMethod foo) { 125 RVMClass I = foo.getDeclaringClass(); 126 127 ImmutableEntryHashSetRVM<RVMClass> classes = allImplementors(I); 128 RVMMethod firstMethod = null; 129 Atom name = foo.getName(); 130 Atom desc = foo.getDescriptor(); 131 132 for (RVMClass klass : classes) { 133 RVMMethod m = klass.findDeclaredMethod(name, desc); 134 if (firstMethod == null) { 135 firstMethod = m; 136 } 137 138 if (m != firstMethod) { 139 return null; 140 } 141 } 142 return firstMethod; 143 } 144}