/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.specialization;
import java.util.Iterator;
import org.jikesrvm.classloader.RVMMethod;
import org.jikesrvm.util.ImmutableEntryHashMapRVM;
import org.jikesrvm.util.HashSetRVM;
/**
* Database to store multiple specialized versions for a given method.
*
* <p> The overall design is very similar to that of the
* InvalidationDatabase (see InvalidationDatabase.java)
* In this database, the key is the RVMMethod object of the source method
* and the value is a method set. The method set is a list of
* specialized versions of the method pointed by the key. Specialized
* versions are represented by using the SpecializedMethod class.
* There is no provision for removing/deleting method versions as classes
* are never unloaded and the ClassLoader.compiledMethods[] is never cleaned.
*/
public final class SpecializationDatabase {
private static boolean specializationInProgress;
private static final HashSetRVM<SpecializedMethod> deferredMethods =
new HashSetRVM<SpecializedMethod>();
private static final ImmutableEntryHashMapRVM<RVMMethod, MethodSet<RVMMethod>> specialVersionsHash =
new ImmutableEntryHashMapRVM<RVMMethod, MethodSet<RVMMethod>>();
/**
* Drain the queue of methods waiting for specialized code
* generation.
*/
public static synchronized void doDeferredSpecializations() {
// prevent recursive entry to this method
if (specializationInProgress) {
return;
}
specializationInProgress = true;
Iterator<SpecializedMethod> methods = deferredMethods.iterator();
while (methods.hasNext()) {
SpecializedMethod m = methods.next();
if (m.getCompiledMethod() == null) {
m.compile();
registerCompiledMethod(m);
}
deferredMethods.remove(m);
// since we modified the set, reset the iterator.
// TODO: use a better abstraction
// (ModifiableSetIterator of some kind?)
methods = deferredMethods.iterator();
}
specializationInProgress = false;
}
// write the new compiled method in the specialized method pool
private static void registerCompiledMethod(SpecializedMethod m) {
SpecializedMethodPool.registerCompiledMethod(m);
}
/**
* @param m the method whose specialized methods are queried
* @return an iteration of specialized compiled versions, {@code null}
* if no specialized versions
*/
static synchronized Iterator<SpecializedMethod> getSpecialVersions(RVMMethod m) {
MethodSet<RVMMethod> s = specialVersionsHash.get(m);
if (s == null) {
return null;
} else {
return s.iterator();
}
}
static int getSpecialVersionCount(RVMMethod m) {
Iterator<SpecializedMethod> versions = getSpecialVersions(m);
int count = 0;
if (versions != null) {
while (versions.hasNext() && (versions.next() != null)) {
count++;
}
}
return count;
}
/**
* Records a new specialized method in this database.
* Also remember that this method will need to be compiled later,
* at the next call to <code> doDeferredSpecializations() </code>
*
* @param spMethod the method to register
*/
static synchronized void registerSpecialVersion(SpecializedMethod spMethod) {
RVMMethod source = spMethod.getMethod();
MethodSet<RVMMethod> s = findOrCreateMethodSet(specialVersionsHash, source);
s.add(spMethod);
deferredMethods.add(spMethod);
}
/**
* Looks up the MethodSet corresponding to a given key in the database.
*
* @param <T> type of the key in the database
* @param hash the database
* @param key the key
* @return the method set for the given key
*/
private static <T> MethodSet<T> findOrCreateMethodSet(ImmutableEntryHashMapRVM<T, MethodSet<T>> hash, T key) {
MethodSet<T> result = hash.get(key);
if (result == null) {
result = new MethodSet<T>(key);
hash.put(key, result);
}
return result;
}
/**
* The following defines a set of methods that share a common "key"
*/
static class MethodSet<T> {
final T key;
/**
* a set of SpecializedMethod
*/
final HashSetRVM<SpecializedMethod> methods = new HashSetRVM<SpecializedMethod>();
MethodSet(T key) {
this.key = key;
}
void add(SpecializedMethod spMethod) {
methods.add(spMethod);
}
public Iterator<SpecializedMethod> iterator() {
return methods.iterator();
}
}
}