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 */ CstBaseMethodRef(CstType definingClass, CstNat nat)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 */ getPrototype()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 */ getPrototype(boolean isStatic)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 compareTo0(Constant other)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 @Override getType()117 public final Type getType() { 118 return prototype.getReturnType(); 119 } 120 121 /** 122 * Gets the number of words of parameters required by this 123 * method's descriptor. Since instances of this class have no way 124 * to know if they will be used in a {@code static} or 125 * instance context, one has to indicate this explicitly as an 126 * argument. This method is just a convenient shorthand for 127 * {@code getPrototype().getParameterTypes().getWordCount()}, 128 * plus {@code 1} if the method is to be treated as an 129 * instance method. 130 * 131 * @param isStatic whether the method should be considered static 132 * @return {@code >= 0;} the argument word count 133 */ getParameterWordCount(boolean isStatic)134 public final int getParameterWordCount(boolean isStatic) { 135 return getPrototype(isStatic).getParameterTypes().getWordCount(); 136 } 137 138 /** 139 * Gets whether this is a reference to an instance initialization 140 * method. This is just a convenient shorthand for 141 * {@code getNat().isInstanceInit()}. 142 * 143 * @return {@code true} iff this is a reference to an 144 * instance initialization method 145 */ isInstanceInit()146 public final boolean isInstanceInit() { 147 return getNat().isInstanceInit(); 148 } 149 150 /** 151 * Gets whether this is a reference to a class initialization 152 * method. This is just a convenient shorthand for 153 * {@code getNat().isClassInit()}. 154 * 155 * @return {@code true} iff this is a reference to an 156 * instance initialization method 157 */ isClassInit()158 public final boolean isClassInit() { 159 return getNat().isClassInit(); 160 } 161 162 /** 163 * Get whether this is a reference to a signature polymorphic 164 * method. This means it is defined in {@code java.lang.invoke.MethodHandle} and 165 * is either the {@code invoke} or the {@code invokeExact} method. 166 * 167 * @return {@code true} iff this is a reference to a 168 * signature polymorphic method. 169 */ isSignaturePolymorphic()170 public final boolean isSignaturePolymorphic() { 171 CstType definingClass = getDefiningClass(); 172 if (definingClass.equals(CstType.METHOD_HANDLE)) { 173 switch (getNat().getName().getString()) { 174 case "invoke": 175 case "invokeExact": 176 return true; 177 } 178 } else if (definingClass.equals(CstType.VAR_HANDLE)) { 179 switch (getNat().getName().getString()) { 180 case "compareAndExchange": 181 case "compareAndExchangeAcquire": 182 case "compareAndExchangeRelease": 183 case "compareAndSet": 184 case "get": 185 case "getAcquire": 186 case "getAndAdd": 187 case "getAndAddAcquire": 188 case "getAndAddRelease": 189 case "getAndBitwiseAnd": 190 case "getAndBitwiseAndAcquire": 191 case "getAndBitwiseAndRelease": 192 case "getAndBitwiseOr": 193 case "getAndBitwiseOrAcquire": 194 case "getAndBitwiseOrRelease": 195 case "getAndBitwiseXor": 196 case "getAndBitwiseXorAcquire": 197 case "getAndBitwiseXorRelease": 198 case "getAndSet": 199 case "getAndSetAcquire": 200 case "getAndSetRelease": 201 case "getOpaque": 202 case "getVolatile": 203 case "set": 204 case "setOpaque": 205 case "setRelease": 206 case "setVolatile": 207 case "weakCompareAndSet": 208 case "weakCompareAndSetAcquire": 209 case "weakCompareAndSetPlain": 210 case "weakCompareAndSetRelease": 211 return true; 212 } 213 } 214 return false; 215 } 216 } 217