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.specialization; 014 015import java.util.Iterator; 016 017import org.jikesrvm.classloader.RVMMethod; 018import org.jikesrvm.util.ImmutableEntryHashMapRVM; 019import 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 */ 033public 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 * @param m the method whose specialized methods are queried 076 * @return an iteration of specialized compiled versions, {@code null} 077 * 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 * Records 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 * @param spMethod the method to register 105 */ 106 static synchronized void registerSpecialVersion(SpecializedMethod spMethod) { 107 RVMMethod source = spMethod.getMethod(); 108 MethodSet<RVMMethod> s = findOrCreateMethodSet(specialVersionsHash, source); 109 s.add(spMethod); 110 deferredMethods.add(spMethod); 111 } 112 113 /** 114 * Looks up the MethodSet corresponding to a given key in the database. 115 * 116 * @param <T> type of the key in the database 117 * @param hash the database 118 * @param key the key 119 * @return the method set for the given key 120 */ 121 private static <T> MethodSet<T> findOrCreateMethodSet(ImmutableEntryHashMapRVM<T, MethodSet<T>> hash, T key) { 122 MethodSet<T> result = hash.get(key); 123 if (result == null) { 124 result = new MethodSet<T>(key); 125 hash.put(key, result); 126 } 127 return result; 128 } 129 130 /** 131 * The following defines a set of methods that share a common "key" 132 */ 133 static class MethodSet<T> { 134 final T key; 135 136 /** 137 * a set of SpecializedMethod 138 */ 139 final HashSetRVM<SpecializedMethod> methods = new HashSetRVM<SpecializedMethod>(); 140 141 MethodSet(T key) { 142 this.key = key; 143 } 144 145 void add(SpecializedMethod spMethod) { 146 methods.add(spMethod); 147 } 148 149 public Iterator<SpecializedMethod> iterator() { 150 return methods.iterator(); 151 } 152 } 153}