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.specialization;
014    
015    import java.util.Iterator;
016    
017    import org.jikesrvm.classloader.RVMMethod;
018    import org.jikesrvm.util.ImmutableEntryHashMapRVM;
019    import org.jikesrvm.util.HashSetRVM;
020    
021    /**
022     * Database to store multiple specialized versions for a given method.
023     *
024     * <p> The overall design is very similar to that of the
025     * InvalidationDatabase (see InvalidationDatabase.java)
026     * In this database, the key is the RVMMethod object of the source method
027     * and the value is a method set. The method set is a list of
028     * specialized versions of the method pointed by the key. Specialized
029     * versions are represented by using the SpecializedMethod class.
030     * There is no provision for removing/deleting method versions as classes
031     * are never unloaded and the ClassLoader.compiledMethods[] is never cleaned.
032     */
033    public final class SpecializationDatabase {
034    
035      private static boolean specializationInProgress;
036    
037      private static final HashSetRVM<SpecializedMethod> deferredMethods =
038        new HashSetRVM<SpecializedMethod>();
039    
040      private static final ImmutableEntryHashMapRVM<RVMMethod, MethodSet<RVMMethod>> specialVersionsHash =
041          new ImmutableEntryHashMapRVM<RVMMethod, MethodSet<RVMMethod>>();
042    
043      /**
044       * Drain the queue of methods waiting for specialized code
045       * generation.
046       */
047      public static synchronized void doDeferredSpecializations() {
048        // prevent recursive entry to this method
049        if (specializationInProgress) {
050          return;
051        }
052        specializationInProgress = true;
053        Iterator<SpecializedMethod> methods = deferredMethods.iterator();
054        while (methods.hasNext()) {
055          SpecializedMethod m = methods.next();
056          if (m.getCompiledMethod() == null) {
057            m.compile();
058            registerCompiledMethod(m);
059          }
060          deferredMethods.remove(m);
061          // since we modified the set, reset the iterator.
062          // TODO: use a better abstraction
063          // (ModifiableSetIterator of some kind?)
064          methods = deferredMethods.iterator();
065        }
066        specializationInProgress = false;
067      }
068    
069      // write the new compiled method in the specialized method pool
070      private static void registerCompiledMethod(SpecializedMethod m) {
071        SpecializedMethodPool.registerCompiledMethod(m);
072      }
073    
074      /**
075       * Return an iteration of SpecializedMethods that represents
076       * specialized compiled versions of the method pointed by RVMMethod
077       * @return null if no specialized versions
078       */
079      static synchronized Iterator<SpecializedMethod> getSpecialVersions(RVMMethod m) {
080        MethodSet<RVMMethod> s = specialVersionsHash.get(m);
081        if (s == null) {
082          return null;
083        } else {
084          return s.iterator();
085        }
086      }
087    
088      static int getSpecialVersionCount(RVMMethod m) {
089        Iterator<SpecializedMethod> versions = getSpecialVersions(m);
090        int count = 0;
091        if (versions != null) {
092          while (versions.hasNext() && (versions.next() != null)) {
093            count++;
094          }
095        }
096        return count;
097      }
098    
099      /**
100       * Record a new specialized method in this database.
101       * Also remember that this method will need to be compiled later,
102       * at the next call to <code> doDeferredSpecializations() </code>
103       */
104      static synchronized void registerSpecialVersion(SpecializedMethod spMethod) {
105        RVMMethod source = spMethod.getMethod();
106        MethodSet<RVMMethod> s = findOrCreateMethodSet(specialVersionsHash, source);
107        s.add(spMethod);
108        deferredMethods.add(spMethod);
109      }
110    
111      /**
112       * Look up the MethodSet corresponding to a given key in the database
113       * If none found, create one.
114       */
115      private static <T> MethodSet<T> findOrCreateMethodSet(ImmutableEntryHashMapRVM<T, MethodSet<T>> hash, T key) {
116        MethodSet<T> result = hash.get(key);
117        if (result == null) {
118          result = new MethodSet<T>(key);
119          hash.put(key, result);
120        }
121        return result;
122      }
123    
124      /**
125       * The following defines a set of methods that share a common "key"
126       */
127      static class MethodSet<T> {
128        final T key;
129    
130        /**
131         * a set of SpecializedMethod
132         */
133        final HashSetRVM<SpecializedMethod> methods = new HashSetRVM<SpecializedMethod>();
134    
135        MethodSet(T key) {
136          this.key = key;
137        }
138    
139        void add(SpecializedMethod spMethod) {
140          methods.add(spMethod);
141        }
142    
143        public Iterator<SpecializedMethod> iterator() {
144          return methods.iterator();
145        }
146      }
147    }