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 org.jikesrvm.VM; 016 import org.vmmagic.pragma.Pure; 017 import org.vmmagic.pragma.Uninterruptible; 018 019 /** 020 * A class to represent the reference in a class file to a method of 021 * that class or interface. 022 */ 023 public final class MethodReference extends MemberReference { 024 025 /** 026 * type of return value 027 */ 028 private final TypeReference returnType; 029 030 /** 031 * types of parameters (not including "this", if virtual) 032 */ 033 private final TypeReference[] parameterTypes; 034 035 /** 036 * The RVMMethod that this method reference resolved to (null if not yet resolved). 037 */ 038 private RVMMethod resolvedMember; 039 040 /** 041 * Find or create a method reference 042 * @see MemberReference#findOrCreate(TypeReference, Atom, Atom) 043 */ 044 @Pure 045 public static MethodReference findOrCreate(TypeReference tRef, Atom mn, Atom md) { 046 return MemberReference.findOrCreate(tRef, mn, md).asMethodReference(); 047 } 048 049 /** 050 * @param tr a type reference to the defining class in which this method 051 * appears. (e.g., "Ljava/lang/String;") 052 * @param mn the name of this method (e.g., "equals") 053 * @param d the method descriptor (e.g., "(Ljava/lang/Object;)Z") 054 * @param id the new ID of the member were a new member required 055 */ 056 MethodReference(TypeReference tr, Atom mn, Atom d, int id) { 057 super(tr, mn, d, id); 058 ClassLoader cl = tr.getClassLoader(); 059 returnType = d.parseForReturnType(cl); 060 parameterTypes = d.parseForParameterTypes(cl); 061 } 062 063 /** 064 * @return return type of the method 065 */ 066 @Uninterruptible 067 public TypeReference getReturnType() { 068 return returnType; 069 } 070 071 /** 072 * @return parameter types of the method 073 */ 074 @Uninterruptible 075 public TypeReference[] getParameterTypes() { 076 return parameterTypes; 077 } 078 079 /** 080 * Space required by method for its parameters, in words. 081 * Note: does *not* include implicit "this" parameter, if any. 082 */ 083 @Uninterruptible 084 public int getParameterWords() { 085 int pw = 0; 086 for (TypeReference parameterType : parameterTypes) pw += parameterType.getStackWords(); 087 return pw; 088 } 089 090 /** 091 * Do this and that definitely refer to the different methods? 092 */ 093 public boolean definitelyDifferent(MethodReference that) { 094 if (this == that) return false; 095 if (name != that.name || descriptor != that.descriptor) return true; 096 RVMMethod mine = peekResolvedMethod(); 097 RVMMethod theirs = that.peekResolvedMethod(); 098 if (mine == null || theirs == null) return false; 099 return mine != theirs; 100 } 101 102 /** 103 * Do this and that definitely refer to the same method? 104 */ 105 public boolean definitelySame(MethodReference that) { 106 if (this == that) return true; 107 if (name != that.name || descriptor != that.descriptor) return false; 108 RVMMethod mine = peekResolvedMethod(); 109 RVMMethod theirs = that.peekResolvedMethod(); 110 if (mine == null || theirs == null) return false; 111 return mine == theirs; 112 } 113 114 /** 115 * Has the method reference already been resolved into a target method? 116 */ 117 public boolean isResolved() { 118 return resolvedMember != null; 119 } 120 121 /** 122 * Get the member this reference has been resolved to, if 123 * it has already been resolved. Does NOT force resolution. 124 */ 125 @Uninterruptible 126 public RVMMethod getResolvedMember() { 127 return resolvedMember; 128 } 129 130 /** 131 * For use by RVMMethod constructor 132 */ 133 void setResolvedMember(RVMMethod it) { 134 if (VM.VerifyAssertions) VM._assert(resolvedMember == null || resolvedMember == it); 135 resolvedMember = it; 136 } 137 138 /** 139 * Resolve the method reference for an invoke special into a target 140 * method, if that is possible without causing classloading. 141 * 142 * @return target method or {@code null} if the method cannot be resolved without classloading. 143 */ 144 public synchronized RVMMethod resolveInvokeSpecial() { 145 RVMClass thisClass = (RVMClass) type.peekType(); 146 if (thisClass == null && name != RVMClassLoader.StandardObjectInitializerMethodName) { 147 thisClass = (RVMClass) type.resolve(); 148 /* Can't fail to resolve thisClass; we're at compile time doing 149 resolution of an invocation to a private method or super call. We 150 must have loaded the class already */ 151 } 152 if (thisClass == null) { 153 return null; // can't be found now. 154 } 155 RVMMethod sought = resolveInternal(thisClass); 156 157 if (sought.isObjectInitializer()) { 158 return sought; // <init> 159 } 160 161 RVMClass cls = sought.getDeclaringClass(); 162 if (!cls.isSpecial()) { 163 return sought; // old-style invokespecial semantics 164 } 165 166 for (; cls != null; cls = cls.getSuperClass()) { 167 RVMMethod found = cls.findDeclaredMethod(sought.getName(), sought.getDescriptor()); 168 if (found != null) { 169 return found; // new-style invokespecial semantics 170 } 171 } 172 return null; // cannot be found 173 } 174 175 /** 176 * Find the RVMMethod that this method reference refers to using 177 * the search order specified in JVM spec 5.4.3.3. 178 * @return the RVMMethod that this method ref resolved to or {@code null} if it cannot be resolved. 179 */ 180 public RVMMethod peekResolvedMethod() { 181 if (resolvedMember != null) return resolvedMember; 182 183 // Hasn't been resolved yet. Try to do it now without triggering class loading. 184 RVMType declaringClass = type.peekType(); 185 if (declaringClass == null) return null; 186 return resolveInternal((RVMClass)declaringClass); 187 } 188 189 /** 190 * Find the RVMMethod that this field reference refers to using 191 * the search order specified in JVM specification 5.4.3.3. 192 * @return the RVMMethod that this method reference resolved to. 193 */ 194 public synchronized RVMMethod resolve() { 195 if (resolvedMember != null) return resolvedMember; 196 197 // Hasn't been resolved yet. Do it now triggering class loading if necessary. 198 return resolveInternal((RVMClass) type.resolve()); 199 } 200 201 /** 202 * Return {@code true} iff this member reference refers to a method which 203 * is declared as part of an abstract class but actually is an 204 * interface method, known formally as a "miranda method". 205 * <p> 206 * This method is necessary to handle the special case where an 207 * invokevirtual is defined on an abstract class, where the 208 * method invocation points to a method inherited from an 209 * interface. 210 * 211 * @return boolean {@code true} iff this member method reference is a miranda method 212 */ 213 public boolean isMiranda() { 214 215 // Hasn't been resolved yet. Try to do it now without triggering class loading. 216 RVMClass declaringClass = (RVMClass) type.peekType(); 217 if (declaringClass == null) { return false; } 218 219 if (!declaringClass.isResolved()) { 220 declaringClass.resolve(); 221 } 222 223 // See if method is explicitly declared in any superclass 224 for (RVMClass c = declaringClass; c != null; c = c.getSuperClass()) { 225 226 if (c.findDeclaredMethod(name, descriptor) != null) { 227 // Method declared in superclass => not interface method 228 return false; 229 } 230 } 231 232 // Not declared in any superclass; now check to see if it is coming from an interface somewhere 233 for (RVMClass c = declaringClass; c != null; c = c.getSuperClass()) { 234 // See if method is in any interfaces of c 235 for (RVMClass intf : c.getDeclaredInterfaces()) { 236 if (searchInterfaceMethods(intf) != null) { 237 // Found method in interface or superinterface 238 return true; 239 } 240 } 241 } 242 243 // neither in superclass or interface => not interface method 244 return false; 245 } 246 247 /** 248 * Is the method reference to a magic method? NB. In the case of 249 * SysCall annotated methods we don't know until they are resolved. 250 */ 251 public boolean isMagic() { 252 return getType().isMagicType() || ((resolvedMember != null) && (resolvedMember.isSysCall() || resolvedMember.isSpecializedInvoke())); 253 } 254 255 /** 256 * Is the method reference to a specialized invoke? NB. we don't know until they are resolved. 257 */ 258 public boolean isSpecializedInvoke() { 259 return (resolvedMember != null) && (resolvedMember.isSpecializedInvoke()); 260 } 261 262 /** 263 * Is the method reference to a magic method? NB. In the case of 264 * SysCall annotated methods we don't know until they are resolved. 265 */ 266 public boolean isSysCall() { 267 return (getType() == TypeReference.SysCall) || ((resolvedMember != null) && (resolvedMember.isSysCall())); 268 } 269 270 /** 271 * Find the RVMMethod that this member reference refers to using 272 * the search order specified in JVM spec 5.4.3.3. 273 * @return the RVMMethod that this method ref resolved to. 274 */ 275 private RVMMethod resolveInternal(RVMClass declaringClass) { 276 final boolean DBG=false; 277 if (!declaringClass.isResolved()) { 278 declaringClass.resolve(); 279 } 280 for (RVMClass c = declaringClass; c != null; c = c.getSuperClass()) { 281 if (DBG) { 282 VM.sysWrite("Checking for <" + name + "," + descriptor + "> in class " + c + "..."); 283 } 284 285 RVMMethod it = c.findDeclaredMethod(name, descriptor); 286 if (it != null) { 287 if (DBG) { 288 VM.sysWriteln("...found <" + name + "," + descriptor + "> in class " + c); 289 } 290 resolvedMember = it; 291 return resolvedMember; 292 } 293 if (DBG) { 294 VM.sysWriteln("...NOT found <" + name + "," + descriptor + "> in class " + c); 295 } 296 } 297 if (!VM.fullyBooted) { 298 VM.sysWrite("MethodReference.resolveInternal():"); 299 VM.sysWrite(" Unable to find a method named "); 300 name.sysWrite(); 301 VM.sysWrite(" with descriptor "); 302 descriptor.sysWrite(); 303 VM.sysWrite(" in the class "); 304 declaringClass.getDescriptor().sysWrite(); 305 if (VM.runningVM) { 306 VM.sysWriteln(", while booting the VM"); 307 VM.sysFail("MethodReference.resolveInternal(): Unable to resolve a method during VM booting"); 308 309 } else { 310 VM.sysWriteln(", while writing the boot image"); 311 Thread.dumpStack(); 312 throw new Error("MethodReference.resolveInternal(): Unable to resolve a method during boot image writing"); 313 } 314 } 315 throw new NoSuchMethodError(this.toString()); 316 } 317 318 /** 319 * Find the RVMMethod that this member reference refers to using 320 * the search order specified in JVM spec 5.4.3.4. 321 * @return the RVMMethod that this method ref resolved to or {@code null} if it cannot be resolved without trigering class loading 322 */ 323 public RVMMethod peekInterfaceMethod() { 324 if (resolvedMember != null) return resolvedMember; 325 326 // Hasn't been resolved yet. Try to do it now. 327 RVMClass declaringClass = (RVMClass) type.peekType(); 328 if (declaringClass == null) return null; 329 if (!declaringClass.isResolved()) { 330 declaringClass.resolve(); 331 } 332 if (!declaringClass.isInterface()) return null; 333 return resolveInterfaceMethodInternal(declaringClass); 334 } 335 336 /** 337 * Find the RVMMethod that this member reference refers to using 338 * the search order specified in JVM spec 5.4.3.4. 339 * @return the RVMMethod that this method ref resolved to 340 */ 341 public RVMMethod resolveInterfaceMethod() throws IncompatibleClassChangeError, NoSuchMethodError { 342 if (resolvedMember != null) return resolvedMember; 343 344 // Hasn't been resolved yet. Do it now. 345 RVMClass declaringClass = (RVMClass) type.resolve(); 346 if (!declaringClass.isResolved()) { 347 declaringClass.resolve(); 348 } 349 350 /* Interface method may be either in interface, or a miranda. 351 */ 352 if (!declaringClass.isInterface() && !isMiranda()) { 353 throw new IncompatibleClassChangeError(); 354 } 355 RVMMethod ans = resolveInterfaceMethodInternal(declaringClass); 356 if (ans == null) { 357 throw new NoSuchMethodError(this.toString()); 358 } 359 return ans; 360 } 361 362 /** 363 * Find the RVMMethod that this member reference refers to using 364 * the search order specified in JVM spec 5.4.3.4. 365 * @return the RVMMethod that this method ref resolved to or {@code null} for error 366 */ 367 private RVMMethod resolveInterfaceMethodInternal(RVMClass declaringClass) { 368 RVMMethod it = declaringClass.findDeclaredMethod(name, descriptor); 369 if (it != null) { 370 resolvedMember = it; 371 return resolvedMember; 372 } 373 for (RVMClass intf : declaringClass.getDeclaredInterfaces()) { 374 it = searchInterfaceMethods(intf); 375 if (it != null) { 376 resolvedMember = it; 377 return resolvedMember; 378 } 379 } 380 return null; 381 } 382 383 private RVMMethod searchInterfaceMethods(RVMClass c) { 384 if (!c.isResolved()) c.resolve(); 385 RVMMethod it = c.findDeclaredMethod(name, descriptor); 386 if (it != null) return it; 387 for (RVMClass intf : c.getDeclaredInterfaces()) { 388 it = searchInterfaceMethods(intf); 389 if (it != null) return it; 390 } 391 return null; 392 } 393 }