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.classloader; 014 015 import java.util.StringTokenizer; 016 import org.jikesrvm.VM; 017 import org.jikesrvm.util.ImmutableEntryHashSetRVM; 018 import org.vmmagic.pragma.Uninterruptible; 019 020 /** 021 * A class to represent the reference in a class file to some 022 * member (field or method). 023 * A member reference is uniquely defined by 024 * <ul> 025 * <li> a type reference 026 * <li> a method name 027 * <li> a descriptor 028 * </ul> 029 * Resolving a MemberReference to a RVMMember can 030 * be an expensive operation. Therefore we canonicalize 031 * MemberReference instances and cache the result of resolution. 032 */ 033 public abstract class MemberReference { 034 035 /** 036 * Used to canonicalize memberReferences 037 */ 038 private static final ImmutableEntryHashSetRVM<MemberReference> dictionary = 039 new ImmutableEntryHashSetRVM<MemberReference>(); 040 041 /** 042 * 2^LOG_ROW_SIZE is the number of elements per row 043 */ 044 private static final int LOG_ROW_SIZE = 10; 045 /** 046 * Mask to ascertain row from id number 047 */ 048 private static final int ROW_MASK = (1 << LOG_ROW_SIZE)-1; 049 /** 050 * Dictionary of all MemberReference instances. 051 */ 052 private static MemberReference[][] members = new MemberReference[16][1 << LOG_ROW_SIZE]; 053 054 /** 055 * Used to assign ids. Id 0 is not used to support usage of member reference id's in JNI. 056 */ 057 private static int nextId = 1; 058 059 /** 060 * Unique id for the member reference (ignored in .equals comparison) 061 */ 062 protected final int id; 063 064 /** 065 * The type reference 066 */ 067 protected final TypeReference type; 068 069 /** 070 * The member name 071 */ 072 protected final Atom name; 073 074 /** 075 * The descriptor 076 */ 077 protected final Atom descriptor; 078 079 /** 080 * Find or create the canonical MemberReference instance for 081 * the given tuple. 082 * @param tRef the type reference 083 * @param mn the name of the member 084 * @param md the descriptor of the member 085 */ 086 public static synchronized MemberReference findOrCreate(TypeReference tRef, Atom mn, Atom md) { 087 MemberReference key; 088 if (md.isMethodDescriptor()) { 089 if (tRef.isArrayType() && !tRef.isUnboxedArrayType()) { 090 tRef = RVMType.JavaLangObjectType.getTypeRef(); 091 } 092 key = new MethodReference(tRef, mn, md, nextId + 1); 093 } else { 094 key = new FieldReference(tRef, mn, md, nextId + 1); 095 } 096 MemberReference val = dictionary.get(key); 097 if (val != null) return val; 098 nextId++; 099 TableBasedDynamicLinker.ensureCapacity(key.id); 100 int column = key.id >> LOG_ROW_SIZE; 101 if (column == members.length) { 102 MemberReference[][] tmp = new MemberReference[column+1][]; 103 for (int i=0; i < column; i++) { 104 tmp[i] = members[i]; 105 } 106 members = tmp; 107 members[column] = new MemberReference[1 << LOG_ROW_SIZE]; 108 } 109 members[column][key.id & ROW_MASK] = key; 110 dictionary.add(key); 111 return key; 112 } 113 114 /** 115 * Given a StringTokenizer currently pointing to the start of a {@link 116 * MemberReference} (created by doing a toString() on a 117 * MemberReference), parse it and find/create the appropriate 118 * MemberReference. Consumes all of the tokens corresponding to the 119 * member reference. 120 */ 121 public static MemberReference parse(StringTokenizer parser) { 122 return parse(parser, false); 123 } 124 125 public static MemberReference parse(StringTokenizer parser, boolean boot) { 126 String clName = null; 127 try { 128 parser.nextToken(); // discard < 129 clName = parser.nextToken(); 130 if ((!clName.equals(BootstrapClassLoader.myName)) && (boot)) { 131 return null; 132 } 133 Atom dc = Atom.findOrCreateUnicodeAtom(parser.nextToken()); 134 Atom mn = Atom.findOrCreateUnicodeAtom(parser.nextToken()); 135 Atom md = Atom.findOrCreateUnicodeAtom(parser.nextToken()); 136 parser.nextToken(); // discard '>' 137 ClassLoader cl = null; 138 if (clName.equals(BootstrapClassLoader.myName)) { 139 cl = BootstrapClassLoader.getBootstrapClassLoader(); 140 } else if (clName.equals(ApplicationClassLoader.myName)) { 141 cl = RVMClassLoader.getApplicationClassLoader(); 142 } else { 143 cl = RVMClassLoader.findWorkableClassloader(dc); 144 } 145 TypeReference tref = TypeReference.findOrCreate(cl, dc); 146 return findOrCreate(tref, mn, md); 147 } catch (Exception e) { 148 VM.sysWriteln("Warning: error parsing for class "+clName+": "+e); 149 return null; 150 } 151 } 152 153 //BEGIN HRM 154 public static int getNextId() { 155 return nextId; 156 } 157 //END HRM 158 159 @Uninterruptible 160 public static MemberReference getMemberRef(int id) { 161 return members[id >> LOG_ROW_SIZE][id & ROW_MASK]; 162 } 163 164 /** 165 * @param tRef the type reference 166 * @param mn the field or method name 167 * @param d the field or method descriptor 168 * @param id the new ID of the member were a new member required (ignored in 169 * .equals test) 170 */ 171 protected MemberReference(TypeReference tRef, Atom mn, Atom d, int id) { 172 type = tRef; 173 name = mn; 174 descriptor = d; 175 this.id = id; 176 } 177 178 /** 179 * @return the type reference component of this member reference 180 */ 181 @Uninterruptible 182 public final TypeReference getType() { 183 return type; 184 } 185 186 /** 187 * @return the member name component of this member reference 188 */ 189 @Uninterruptible 190 public final Atom getName() { 191 return name; 192 } 193 194 /** 195 * @return the descriptor component of this member reference 196 */ 197 @Uninterruptible 198 public final Atom getDescriptor() { 199 return descriptor; 200 } 201 202 /** 203 * @return the dynamic linking id to use for this member. 204 */ 205 @Uninterruptible 206 public final int getId() { 207 return id; 208 } 209 210 /** 211 * Is this member reference to a field? 212 */ 213 @Uninterruptible 214 public final boolean isFieldReference() { 215 return this instanceof FieldReference; 216 } 217 218 /** 219 * Is this member reference to a method? 220 */ 221 @Uninterruptible 222 public final boolean isMethodReference() { 223 return this instanceof MethodReference; 224 } 225 226 /** 227 * @return this cast to a FieldReference 228 */ 229 @Uninterruptible 230 public final FieldReference asFieldReference() { 231 return (FieldReference) this; 232 } 233 234 /** 235 * @return this cast to a MethodReference 236 */ 237 @Uninterruptible 238 public final MethodReference asMethodReference() { 239 return (MethodReference) this; 240 } 241 242 /** 243 * @return the RVMMember this reference resolves to if it is already known 244 * or {@code null} if it cannot be resolved without risking class loading. 245 */ 246 public final RVMMember peekResolvedMember() { 247 if (isFieldReference()) { 248 return this.asFieldReference().peekResolvedField(); 249 } else { 250 return this.asMethodReference().peekResolvedMethod(); 251 } 252 } 253 254 /** 255 * Force resolution and return the resolved member. 256 * Will cause classloading if necessary 257 */ 258 public final RVMMember resolveMember() { 259 if (isFieldReference()) { 260 return this.asFieldReference().resolve(); 261 } else { 262 return this.asMethodReference().resolve(); 263 } 264 } 265 266 /** 267 * Is dynamic linking code required to access "this" member when 268 * referenced from "that" method? 269 */ 270 public final boolean needsDynamicLink(RVMMethod that) { 271 RVMMember resolvedThis = this.peekResolvedMember(); 272 273 if (resolvedThis == null) { 274 // can't tell because we haven't resolved the member reference 275 // sufficiently to even know exactly where it is declared. 276 return true; 277 } 278 RVMClass thisClass = resolvedThis.getDeclaringClass(); 279 280 if (thisClass == that.getDeclaringClass()) { 281 // Intra-class references don't need to be compiled with dynamic linking 282 // because they execute *after* class has been loaded/resolved/compiled. 283 return false; 284 } 285 286 if (thisClass.isInitialized()) { 287 // No dynamic linking code is required to access this member 288 // because its size and offset are known and its class's static 289 // initializer has already run. 290 return false; 291 } 292 293 if (isFieldReference() && thisClass.isResolved() && thisClass.getClassInitializerMethod() == null) { 294 // No dynamic linking code is required to access this field 295 // because its size and offset is known and its class has no static 296 // initializer, therefore its value need not be specially initialized 297 // (its default value of zero or null is sufficient). 298 return false; 299 } 300 301 if (VM.writingBootImage && thisClass.isInBootImage()) { 302 // Loads, stores, and calls within boot image are compiled without dynamic 303 // linking code because all boot image classes are explicitly 304 // loaded/resolved/compiled and have had their static initializers 305 // run by the boot image writer. 306 if (VM.VerifyAssertions) VM._assert(thisClass.isResolved()); 307 return false; 308 } 309 310 // This member needs size and offset to be computed, or its class's static 311 // initializer needs to be run when the member is first "touched", so 312 // dynamic linking code is required to access the member. 313 return true; 314 } 315 316 @Override 317 public final int hashCode() { 318 return type.hashCode() + name.hashCode() + descriptor.hashCode(); 319 } 320 321 @Override 322 public final boolean equals(Object other) { 323 if (other instanceof MemberReference) { 324 MemberReference that = (MemberReference) other; 325 return type == that.type && name == that.name && descriptor == that.descriptor; 326 } else { 327 return false; 328 } 329 } 330 331 @Override 332 public final String toString() { 333 return "< " + type.getClassLoader() + ", " + type.getName() + ", " + name + ", " + descriptor + " >"; 334 } 335 }