1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.rop.cst; 18 19 import com.android.dx.rop.type.Prototype; 20 import com.android.dx.rop.type.Type; 21 import com.android.dx.rop.type.TypeBearer; 22 23 /** 24 * Base class for constants of "methodish" type. 25 * 26 * <p><b>Note:</b> As a {@link TypeBearer}, this class bears the return type 27 * of the method.</p> 28 */ 29 public abstract class CstBaseMethodRef 30 extends CstMemberRef { 31 /** {@code non-null;} the raw prototype for this method */ 32 private final Prototype prototype; 33 34 /** 35 * {@code null-ok;} the prototype for this method taken to be an instance 36 * method, or {@code null} if not yet calculated 37 */ 38 private Prototype instancePrototype; 39 40 /** 41 * Constructs an instance. 42 * 43 * @param definingClass {@code non-null;} the type of the defining class 44 * @param nat {@code non-null;} the name-and-type 45 */ 46 /*package*/ CstBaseMethodRef(CstType definingClass, CstNat nat) { 47 super(definingClass, nat); 48 49 String descriptor = getNat().getDescriptor().getString(); 50 if (isSignaturePolymorphic()) { 51 // The prototype for signature polymorphic methods is used to 52 // construct call-site information and select the true invocation 53 // target (invoke() or invokeExact(). The prototype is created 54 // without being interned to avoid polluting the DEX file with 55 // unused data. 56 this.prototype = Prototype.fromDescriptor(descriptor); 57 } else { 58 this.prototype = Prototype.intern(descriptor); 59 } 60 this.instancePrototype = null; 61 } 62 63 /** 64 * Gets the raw prototype of this method. This doesn't include a 65 * {@code this} argument. 66 * 67 * @return {@code non-null;} the method prototype 68 */ 69 public final Prototype getPrototype() { 70 return prototype; 71 } 72 73 /** 74 * Gets the prototype of this method as either a 75 * {@code static} or instance method. In the case of a 76 * {@code static} method, this is the same as the raw 77 * prototype. In the case of an instance method, this has an 78 * appropriately-typed {@code this} argument as the first 79 * one. 80 * 81 * @param isStatic whether the method should be considered static 82 * @return {@code non-null;} the method prototype 83 */ 84 public final Prototype getPrototype(boolean isStatic) { 85 if (isStatic) { 86 return prototype; 87 } else { 88 if (instancePrototype == null) { 89 Type thisType = getDefiningClass().getClassType(); 90 instancePrototype = prototype.withFirstParameter(thisType); 91 } 92 return instancePrototype; 93 } 94 } 95 96 /** {@inheritDoc} */ 97 @Override 98 protected final int compareTo0(Constant other) { 99 int cmp = super.compareTo0(other); 100 101 if (cmp != 0) { 102 return cmp; 103 } 104 105 CstBaseMethodRef otherMethod = (CstBaseMethodRef) other; 106 return prototype.compareTo(otherMethod.prototype); 107 } 108 109 /** 110 * {@inheritDoc} 111 * 112 * In this case, this method returns the <i>return type</i> of this method. 113 * 114 * @return {@code non-null;} the method's return type 115 */ 116 public final Type getType() { 117 return prototype.getReturnType(); 118 } 119 120 /** 121 * Gets the number of words of parameters required by this 122 * method's descriptor. Since instances of this class have no way 123 * to know if they will be used in a {@code static} or 124 * instance context, one has to indicate this explicitly as an 125 * argument. This method is just a convenient shorthand for 126 * {@code getPrototype().getParameterTypes().getWordCount()}, 127 * plus {@code 1} if the method is to be treated as an 128 * instance method. 129 * 130 * @param isStatic whether the method should be considered static 131 * @return {@code >= 0;} the argument word count 132 */ 133 public final int getParameterWordCount(boolean isStatic) { 134 return getPrototype(isStatic).getParameterTypes().getWordCount(); 135 } 136 137 /** 138 * Gets whether this is a reference to an instance initialization 139 * method. This is just a convenient shorthand for 140 * {@code getNat().isInstanceInit()}. 141 * 142 * @return {@code true} iff this is a reference to an 143 * instance initialization method 144 */ 145 public final boolean isInstanceInit() { 146 return getNat().isInstanceInit(); 147 } 148 149 /** 150 * Gets whether this is a reference to a class initialization 151 * method. This is just a convenient shorthand for 152 * {@code getNat().isClassInit()}. 153 * 154 * @return {@code true} iff this is a reference to an 155 * instance initialization method 156 */ 157 public final boolean isClassInit() { 158 return getNat().isClassInit(); 159 } 160 161 /** 162 * Get whether this is a reference to a signature polymorphic 163 * method. This means it is defined in {@code java.lang.invoke.MethodHandle} and 164 * is either the {@code invoke} or the {@code invokeExact} method. 165 * 166 * @return {@code true} iff this is a reference to a 167 * signature polymorphic method. 168 */ 169 public final boolean isSignaturePolymorphic() { 170 return (getDefiningClass().equals(CstType.METHOD_HANDLE) && 171 getNat().isSignaturePolymorphic()); 172 } 173 } 174