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    }