/*
* 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.inlining;
import java.util.Iterator;
import org.jikesrvm.classloader.RVMClass;
import org.jikesrvm.classloader.RVMMethod;
import org.jikesrvm.util.HashMapRVM;
import org.jikesrvm.util.HashSetRVM;
/**
* This class holds the dependencies that define invalidation
* requirements for the opt compiled methods.
*
* <p> Currently we only support 2 kinds of dependencies:
* The set of compiled method id's that depend on a RVMMethod
* not being overridden.
* The set of compiled method id's that depend on a RVMClass
* having no subclasses
*
* <p> Note we track by compiled method ids instead of pointers to
* compiled methods because we don't have weak pointers.
* We don't want the invalidaton database to keep code alive!
* This would be an ideal use of weak references if we had them.
*
* <p> TODO: In the future, we should think about implementing a general
* dependency mechanism.
* See Chambers, Dean, Grove in ICSE-17 (1995) for one possible design
* and pointers to related work.
*/
public final class InvalidationDatabase {
/**
* A mapping from RVMMethod to MethodSet: holds the set of methods which
* depend on a particular method being "final"
*/
private final HashMapRVM<RVMMethod, MethodSet> nonOverriddenHash =
new HashMapRVM<RVMMethod, MethodSet>();
/**
* A mapping from RVMClass to MethodSet: holds the set of methods which
* depend on a particular class being "final"
*/
private final HashMapRVM<RVMClass, MethodSet> noSubclassHash =
new HashMapRVM<RVMClass, MethodSet>();
/////////////////////
// (1) Dependency on a particular RVMMethod not being overridden.
/////////////////////
/**
* Returns an iteration of CMID's (compiled method ids) that are dependent
* on the argument RVMMethod not being overridden. If there are no dependent
* methods, {@code null} will be returned.<p>
*
* NOTE: {@code null} is used instead of {@code EmptyIterator.getInstance}
* as part of delicate dance to avoid recursive classloading.
*
* @param m a method that can be overridden
* @return an iterator of CMIDs or {@code null}
*/
public Iterator<Integer> invalidatedByOverriddenMethod(RVMMethod m) {
MethodSet s = nonOverriddenHash.get(m);
return (s == null) ? null : s.iterator();
}
/**
* Records that if a particular RVMMethod method is ever overridden, then
* the CompiledMethod encoded by the cmid must be invalidated.
*
* @param source a method
* @param dependent_cmid id of the method that must be invalidated
*/
public void addNotOverriddenDependency(RVMMethod source, int dependent_cmid) {
MethodSet s = findOrCreateMethodSet(nonOverriddenHash, source);
s.add(dependent_cmid);
}
/**
* Deletes a NotOverriddenDependency.
* No effect if the dependency doesn't exist..
*
* @param source a method
* @param dependent_cmid id of the method that must be invalidated
*/
public void removeNotOverriddenDependency(RVMMethod source, int dependent_cmid) {
MethodSet s = nonOverriddenHash.get(source);
if (s != null) {
s.remove(dependent_cmid);
}
}
/**
* Delete all NotOverridden dependencies on the argument RVMMethod
*
* @param source a method
*/
public void removeNotOverriddenDependency(RVMMethod source) {
nonOverriddenHash.remove(source);
}
/////////////////////
// (2) Dependency on a particular RVMClass not having any subclasses.
/////////////////////
/**
* Returns an iteration of CMID's (compiled method ids) that are dependent
* on the argument RVMMethod not having any subclasses. If there are no
* dependent methods, {@code null} will be returned.<p>
*
* NOTE: {@code null} is used instead of {@code EmptyIterator.getInstance}
* as part of delicate dance to avoid recursive classloading.
*
* @param m a method that can be overridden
* @return an iterator of CMIDs or {@code null}
*/
public Iterator<Integer> invalidatedBySubclass(RVMClass m) {
MethodSet s = noSubclassHash.get(m);
return (s == null) ? null : s.iterator();
}
/**
* Records that if a particular RVMClass ever has a subclass, then
* the CompiledMethod encoded by the cmid must be invalidated.
*
* @param source a class
* @param dependent_cmid id of the method that must be invalidated
*/
public void addNoSubclassDependency(RVMClass source, int dependent_cmid) {
MethodSet s = findOrCreateMethodSet(noSubclassHash, source);
s.add(dependent_cmid);
}
/**
* Delete as NoSubclassDependency. No effect if the dependency doesn't exist..
*
* @param source a class
* @param dependent_cmid id of the method that must be invalidated
*/
public void removeNoSubclassDependency(RVMClass source, int dependent_cmid) {
MethodSet s = noSubclassHash.get(source);
if (s != null) {
s.remove(dependent_cmid);
}
}
/**
* Deletes all NoSubclass dependencies on the argument RVMClass.
*
* @param source class whose dependencies are to be removed
*/
public void removeNoSubclassDependency(RVMClass source) {
noSubclassHash.remove(source);
}
/**
* 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 <T> MethodSet findOrCreateMethodSet(HashMapRVM<T, MethodSet> hash, T key) {
MethodSet result = hash.get(key);
if (result == null) {
result = new MethodSet(key);
hash.put(key, result);
}
return result;
}
/**
* The following defines a set of methods that share a common "key"
*/
static final class MethodSet {
final Object key;
/**
* a set of cmids (Integers)
*/
final HashSetRVM<Integer> methods = new HashSetRVM<Integer>();
MethodSet(Object key) {
this.key = key;
}
void add(int cmid) {
methods.add(cmid);
}
void remove(int cmid) {
methods.remove(cmid);
}
public Iterator<Integer> iterator() {
return methods.iterator();
}
}
}