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