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}