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 * specialied 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 }