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 */ 013package org.jikesrvm.compilers.opt.inlining; 014 015import java.util.Iterator; 016import org.jikesrvm.classloader.RVMClass; 017import org.jikesrvm.classloader.RVMMethod; 018import org.jikesrvm.util.HashMapRVM; 019import 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 */ 041public 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 /** 062 * Returns an iteration of CMID's (compiled method ids) that are dependent 063 * on the argument RVMMethod not being overridden. If there are no dependent 064 * methods, {@code null} will be returned.<p> 065 * 066 * NOTE: {@code null} is used instead of {@code EmptyIterator.getInstance} 067 * as part of delicate dance to avoid recursive classloading. 068 * 069 * @param m a method that can be overridden 070 * @return an iterator of CMIDs or {@code null} 071 */ 072 public Iterator<Integer> invalidatedByOverriddenMethod(RVMMethod m) { 073 MethodSet s = nonOverriddenHash.get(m); 074 return (s == null) ? null : s.iterator(); 075 } 076 077 /** 078 * Records that if a particular RVMMethod method is ever overridden, then 079 * the CompiledMethod encoded by the cmid must be invalidated. 080 * 081 * @param source a method 082 * @param dependent_cmid id of the method that must be invalidated 083 */ 084 public void addNotOverriddenDependency(RVMMethod source, int dependent_cmid) { 085 MethodSet s = findOrCreateMethodSet(nonOverriddenHash, source); 086 s.add(dependent_cmid); 087 } 088 089 /** 090 * Deletes a NotOverriddenDependency. 091 * No effect if the dependency doesn't exist.. 092 * 093 * @param source a method 094 * @param dependent_cmid id of the method that must be invalidated 095 */ 096 public void removeNotOverriddenDependency(RVMMethod source, int dependent_cmid) { 097 MethodSet s = nonOverriddenHash.get(source); 098 if (s != null) { 099 s.remove(dependent_cmid); 100 } 101 } 102 103 /** 104 * Delete all NotOverridden dependencies on the argument RVMMethod 105 * 106 * @param source a method 107 */ 108 public void removeNotOverriddenDependency(RVMMethod source) { 109 nonOverriddenHash.remove(source); 110 } 111 112 ///////////////////// 113 // (2) Dependency on a particular RVMClass not having any subclasses. 114 ///////////////////// 115 116 /** 117 * Returns an iteration of CMID's (compiled method ids) that are dependent 118 * on the argument RVMMethod not having any subclasses. If there are no 119 * dependent methods, {@code null} will be returned.<p> 120 * 121 * NOTE: {@code null} is used instead of {@code EmptyIterator.getInstance} 122 * as part of delicate dance to avoid recursive classloading. 123 * 124 * @param m a method that can be overridden 125 * @return an iterator of CMIDs or {@code null} 126 */ 127 public Iterator<Integer> invalidatedBySubclass(RVMClass m) { 128 MethodSet s = noSubclassHash.get(m); 129 return (s == null) ? null : s.iterator(); 130 } 131 132 /** 133 * Records that if a particular RVMClass ever has a subclass, then 134 * the CompiledMethod encoded by the cmid must be invalidated. 135 * 136 * @param source a class 137 * @param dependent_cmid id of the method that must be invalidated 138 */ 139 public void addNoSubclassDependency(RVMClass source, int dependent_cmid) { 140 MethodSet s = findOrCreateMethodSet(noSubclassHash, source); 141 s.add(dependent_cmid); 142 } 143 144 /** 145 * Delete as NoSubclassDependency. No effect if the dependency doesn't exist.. 146 * 147 * @param source a class 148 * @param dependent_cmid id of the method that must be invalidated 149 */ 150 public void removeNoSubclassDependency(RVMClass source, int dependent_cmid) { 151 MethodSet s = noSubclassHash.get(source); 152 if (s != null) { 153 s.remove(dependent_cmid); 154 } 155 } 156 157 /** 158 * Deletes all NoSubclass dependencies on the argument RVMClass. 159 * 160 * @param source class whose dependencies are to be removed 161 */ 162 public void removeNoSubclassDependency(RVMClass source) { 163 noSubclassHash.remove(source); 164 } 165 166 /** 167 * Looks up the MethodSet corresponding to a given key in the database. 168 * 169 * @param <T> type of the key in the database 170 * @param hash the database 171 * @param key the key 172 * @return the method set for the given key 173 */ 174 private <T> MethodSet findOrCreateMethodSet(HashMapRVM<T, MethodSet> hash, T key) { 175 MethodSet result = hash.get(key); 176 if (result == null) { 177 result = new MethodSet(key); 178 hash.put(key, result); 179 } 180 return result; 181 } 182 183 /** 184 * The following defines a set of methods that share a common "key" 185 */ 186 static final class MethodSet { 187 final Object key; 188 /** 189 * a set of cmids (Integers) 190 */ 191 final HashSetRVM<Integer> methods = new HashSetRVM<Integer>(); 192 193 MethodSet(Object key) { 194 this.key = key; 195 } 196 197 void add(int cmid) { 198 methods.add(cmid); 199 } 200 201 void remove(int cmid) { 202 methods.remove(cmid); 203 } 204 205 public Iterator<Integer> iterator() { 206 return methods.iterator(); 207 } 208 } 209}