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      /**
062       * Returns an iteration of CMID's (compiled method ids) that are dependent
063       * on the argument RVMMethod not being overridden. If there are no dependent
064       * methods, {@code null} will be returned.<p>
065       *
066       * NOTE: {@code null} is used instead of {@code EmptyIterator.getInstance}
067       * as part of delicate dance to avoid recursive classloading.
068       *
069       * @param m a method that can be overridden
070       * @return an iterator of CMIDs or {@code null}
071       */
072      public Iterator<Integer> invalidatedByOverriddenMethod(RVMMethod m) {
073        MethodSet s = nonOverriddenHash.get(m);
074        return (s == null) ? null : s.iterator();
075      }
076    
077      /**
078       * Record that if a particular RVMMethod method is ever overridden, then
079       * the CompiledMethod encoded by the cmid must be invalidated.
080       */
081      public void addNotOverriddenDependency(RVMMethod source, int dependent_cmid) {
082        MethodSet s = findOrCreateMethodSet(nonOverriddenHash, source);
083        s.add(dependent_cmid);
084      }
085    
086      /**
087       * Delete a NotOverriddenDependency.
088       * No effect if the dependency doesn't exist..
089       */
090      public void removeNotOverriddenDependency(RVMMethod source, int dependent_cmid) {
091        MethodSet s = nonOverriddenHash.get(source);
092        if (s != null) {
093          s.remove(dependent_cmid);
094        }
095      }
096    
097      /**
098       * Delete all NotOverridden dependencies on the argument RVMMethod
099       */
100      public void removeNotOverriddenDependency(RVMMethod source) {
101        nonOverriddenHash.remove(source);
102      }
103    
104      /////////////////////
105      // (2) Dependency on a particular RVMClass not having any subclasses.
106      /////////////////////
107    
108      /**
109       * Returns an iteration of CMID's (compiled method ids) that are dependent
110       * on the argument RVMMethod not having any subclasses. If there are no
111       * dependent methods, {@code null} will be returned.<p>
112       *
113       * NOTE: {@code null} is used instead of {@code EmptyIterator.getInstance}
114       * as part of delicate dance to avoid recursive classloading.
115       *
116       * @param m a method that can be overridden
117       * @return an iterator of CMIDs or {@code null}
118       */
119      public Iterator<Integer> invalidatedBySubclass(RVMClass m) {
120        MethodSet s = noSubclassHash.get(m);
121        return (s == null) ? null : s.iterator();
122      }
123    
124      /**
125       * Record that if a particular RVMClass ever has a subclass, then
126       * the CompiledMethod encoded by the cmid must be invalidated.
127       */
128      public void addNoSubclassDependency(RVMClass source, int dependent_cmid) {
129        MethodSet s = findOrCreateMethodSet(noSubclassHash, source);
130        s.add(dependent_cmid);
131      }
132    
133      /**
134       * Delete a NoSubclassDependency. No effect if the dependency doesn't exist..
135       */
136      public void removeNoSubclassDependency(RVMClass source, int dependent_cmid) {
137        MethodSet s = noSubclassHash.get(source);
138        if (s != null) {
139          s.remove(dependent_cmid);
140        }
141      }
142    
143      /**
144       * Delete all NoSubclass dependencies on the argument RVMClass
145       */
146      public void removeNoSubclassDependency(RVMClass source) {
147        noSubclassHash.remove(source);
148      }
149    
150      /**
151       * Look up the MethodSet corresponding to a given key in the database.
152       * If none found, create one.
153       */
154      private <T> MethodSet findOrCreateMethodSet(HashMapRVM<T, MethodSet> hash, T key) {
155        MethodSet result = hash.get(key);
156        if (result == null) {
157          result = new MethodSet(key);
158          hash.put(key, result);
159        }
160        return result;
161      }
162    
163      /**
164       * The following defines a set of methods that share a common "key"
165       */
166      static final class MethodSet {
167        final Object key;
168        /**
169         * a set of cmids (Integers)
170         */
171        final HashSetRVM<Integer> methods = new HashSetRVM<Integer>();
172    
173        MethodSet(Object key) {
174          this.key = key;
175        }
176    
177        void add(int cmid) {
178          methods.add(cmid);
179        }
180    
181        void remove(int cmid) {
182          methods.remove(cmid);
183        }
184    
185        public Iterator<Integer> iterator() {
186          return methods.iterator();
187        }
188      }
189    }