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 java.util.Iterator;
016    import org.jikesrvm.classloader.RVMClass;
017    import org.jikesrvm.classloader.RVMMethod;
018    import org.jikesrvm.util.HashMapRVM;
019    import org.jikesrvm.util.HashSetRVM;
020    
021    /**
022     * This class holds the dependencies that define invalidation
023     * requirements for the opt compiled methods.
024     *
025     * <p> Currently we only support 2 kinds of dependencies:
026     *   The set of compiled method id's that depend on a RVMMethod
027     *   not being overridden.
028     *   The set of compiled method id's that depend on a RVMClass
029     *   having no subclasses
030     *
031     * <p> Note we track by compiled method ids instead of pointers to
032     *     compiled methods because we don't have weak pointers.
033     *     We don't want the invalidaton database to keep code alive!
034     *     This would be an ideal use of weak references if we had them.
035     *
036     * <p> TODO: In the future, we should think about implementing a general
037     *       dependency mechanism.
038     *   See Chambers, Dean, Grove in ICSE-17 (1995) for one possible design
039     *   and pointers to related work.
040     */
041    public final class InvalidationDatabase {
042    
043      /**
044       * A mapping from RVMMethod to MethodSet: holds the set of methods which
045       * depend on a particular method being "final"
046       */
047      private final HashMapRVM<RVMMethod, MethodSet> nonOverriddenHash =
048        new HashMapRVM<RVMMethod, MethodSet>();
049    
050      /**
051       * A mapping from RVMClass to MethodSet: holds the set of methods which
052       * depend on a particular class being "final"
053       */
054      private final HashMapRVM<RVMClass, MethodSet> noSubclassHash =
055        new HashMapRVM<RVMClass, MethodSet>();
056    
057      /////////////////////
058      // (1) Dependency on a particular RVMMethod not being overridden.
059      /////////////////////
060      /**
061       * Return an iteration of CMID's (compiled method ids)
062       * that are dependent on the argument RVMMethod not being overridden.
063       * return null if no dependent methods.
064       *
065       * <p> NOTE: returns null instead of EmptyIterator.EMPTY as part of
066       * a delicate * dance to avoid recursive classloading. --dave.
067       */
068      public Iterator<Integer> invalidatedByOverriddenMethod(RVMMethod m) {
069        MethodSet s = nonOverriddenHash.get(m);
070        return (s == null) ? null : s.iterator();
071      }
072    
073      /**
074       * Record that if a particular RVMMethod method is ever overridden, then
075       * the CompiledMethod encoded by the cmid must be invalidated.
076       */
077      public void addNotOverriddenDependency(RVMMethod source, int dependent_cmid) {
078        MethodSet s = findOrCreateMethodSet(nonOverriddenHash, source);
079        s.add(dependent_cmid);
080      }
081    
082      /**
083       * Delete a NotOverriddenDependency.
084       * No effect if the dependency doesn't exist..
085       */
086      public void removeNotOverriddenDependency(RVMMethod source, int dependent_cmid) {
087        MethodSet s = nonOverriddenHash.get(source);
088        if (s != null) {
089          s.remove(dependent_cmid);
090        }
091      }
092    
093      /**
094       * Delete all NotOverridden dependencies on the argument RVMMethod
095       */
096      public void removeNotOverriddenDependency(RVMMethod source) {
097        nonOverriddenHash.remove(source);
098      }
099    
100      /////////////////////
101      // (2) Dependency on a particular RVMClass not having any subclasses.
102      /////////////////////
103      /**
104       * Return an iteration of CMID's of CompiledMethods that are dependent
105       * on the argument RVMClass not having any subclasses.
106       * return null if no dependent methods.
107       *
108       * <p> NOTE: returns null instead of EmptyIterator.EMPTY as part of
109       * a delicate dance to avoid recursive classloading. --dave.
110       */
111      public Iterator<Integer> invalidatedBySubclass(RVMClass m) {
112        MethodSet s = noSubclassHash.get(m);
113        return (s == null) ? null : s.iterator();
114      }
115    
116      /**
117       * Record that if a particular RVMClass ever has a subclass, then
118       * the CompiledMethod encoded by the cmid must be invalidated.
119       */
120      public void addNoSubclassDependency(RVMClass source, int dependent_cmid) {
121        MethodSet s = findOrCreateMethodSet(noSubclassHash, source);
122        s.add(dependent_cmid);
123      }
124    
125      /**
126       * Delete a NoSubclassDependency. No effect if the dependency doesn't exist..
127       */
128      public void removeNoSubclassDependency(RVMClass source, int dependent_cmid) {
129        MethodSet s = noSubclassHash.get(source);
130        if (s != null) {
131          s.remove(dependent_cmid);
132        }
133      }
134    
135      /**
136       * Delete all NoSubclass dependencies on the argument RVMClass
137       */
138      public void removeNoSubclassDependency(RVMClass source) {
139        noSubclassHash.remove(source);
140      }
141    
142      /**
143       * Look up the MethodSet corresponding to a given key in the database.
144       * If none found, create one.
145       */
146      private <T> MethodSet findOrCreateMethodSet(HashMapRVM<T, MethodSet> hash, T key) {
147        MethodSet result = hash.get(key);
148        if (result == null) {
149          result = new MethodSet(key);
150          hash.put(key, result);
151        }
152        return result;
153      }
154    
155      /**
156       * The following defines a set of methods that share a common "key"
157       */
158      static final class MethodSet {
159        final Object key;
160        /**
161         * a set of cmids (Integers)
162         */
163        final HashSetRVM<Integer> methods = new HashSetRVM<Integer>();
164    
165        MethodSet(Object key) {
166          this.key = key;
167        }
168    
169        void add(int cmid) {
170          methods.add(cmid);
171        }
172    
173        void remove(int cmid) {
174          methods.remove(cmid);
175        }
176    
177        public Iterator<Integer> iterator() {
178          return methods.iterator();
179        }
180      }
181    }