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 }