1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. The Android Open Source 7 * Project designates this particular file as subject to the "Classpath" 8 * exception as provided by The Android Open Source Project in the LICENSE 9 * file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 */ 21 22 package java.lang.invoke; 23 24 import java.lang.reflect.Constructor; 25 import java.lang.reflect.Field; 26 import java.lang.reflect.Member; 27 import java.lang.reflect.Method; 28 import java.lang.reflect.Modifier; 29 import java.util.ArrayList; 30 import java.util.List; 31 32 // Android-changed: Android specific implementation. 33 // The whole class was implemented from scratch for the Android runtime based 34 // on the specification of the MethodHandle class. 35 // The code does not originate from upstream OpenJDK. 36 /** 37 * A method handle that's directly associated with an ArtField or an ArtMethod and 38 * specifies no additional transformations. 39 * 40 * @hide 41 */ 42 public class MethodHandleImpl extends MethodHandle implements Cloneable { 43 // TODO(b/297147201): create separate AccessorMethodHandle class and move target and field 44 // into it. 45 // Used by runtime only. 46 private final long target; 47 private Object targetClassOrMethodHandleInfo; 48 Field field; 49 MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type)50 MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type) { 51 super(artFieldOrMethod, handleKind, type); 52 this.targetClassOrMethodHandleInfo = getMemberInternal().getDeclaringClass(); 53 this.target = 0; 54 } 55 MethodHandleImpl(Field field, int handleKind, MethodType type)56 MethodHandleImpl(Field field, int handleKind, MethodType type) { 57 super(field.getArtField(), handleKind, type); 58 // To make sure that we won't operate on uninitialized fields. 59 // TODO (b/399619087): make initialization lazy. 60 MethodHandleStatics.UNSAFE.ensureClassInitialized(field.getDeclaringClass()); 61 this.targetClassOrMethodHandleInfo = getMemberInternal().getDeclaringClass(); 62 this.field = field; 63 this.target = resolveTarget(handleKind, field); 64 } 65 resolveTarget(int handleKind, Field field)66 private static long resolveTarget(int handleKind, Field field) { 67 StringBuilder name = new StringBuilder(); 68 69 if (handleKind == MethodHandle.SGET || handleKind == MethodHandle.IGET) { 70 name.append("get"); 71 } else if (handleKind == MethodHandle.SPUT || handleKind == MethodHandle.IPUT) { 72 name.append("put"); 73 } else { 74 throw new AssertionError("Unexpected handleKind: " + handleKind); 75 } 76 77 Class<?> type = field.getType(); 78 79 if (type.isPrimitive()) { 80 String fieldTypeName = type.getName(); 81 name.append(Character.toUpperCase(fieldTypeName.charAt(0))); 82 name.append(fieldTypeName.substring(1)); 83 } else { 84 name.append("Reference"); 85 } 86 87 if (Modifier.isVolatile(field.getModifiers())) { 88 name.append("Volatile"); 89 } 90 91 List<Class<?>> signature = new ArrayList<>(3); 92 if (!Modifier.isStatic(field.getModifiers())) { 93 signature.add(Object.class); 94 } 95 if (handleKind == MethodHandle.SPUT || handleKind == MethodHandle.IPUT) { 96 if (type.isPrimitive()) { 97 signature.add(type); 98 } else { 99 signature.add(Object.class); 100 } 101 } 102 signature.add(MethodHandleImpl.class); 103 Method target = DirectMethodHandle.getImplementation(name.toString(), signature); 104 if (target == null) { 105 throw new InternalError("DirectMethodHandle$Holder is missing a method"); 106 } 107 return target.getArtMethod(); 108 } 109 110 @Override clone()111 public Object clone() throws CloneNotSupportedException { 112 return super.clone(); 113 } 114 reveal()115 MethodHandleInfo reveal() { 116 if (!(targetClassOrMethodHandleInfo instanceof HandleInfo handleInfo)) { 117 MethodHandleInfo info = new HandleInfo(getMemberInternal(), this); 118 targetClassOrMethodHandleInfo = info; 119 return info; 120 } 121 122 return handleInfo; 123 } 124 125 /** 126 * Materialize a member from this method handle's ArtField or ArtMethod pointer. 127 */ getMemberInternal()128 public native Member getMemberInternal(); 129 130 /** 131 * Implementation of {@code MethodHandleInfo} in terms of the handle being cracked 132 * and its corresponding {@code java.lang.reflect.Member}. 133 */ 134 static class HandleInfo implements MethodHandleInfo { 135 private final Member member; 136 private final MethodHandle handle; 137 HandleInfo(Member member, MethodHandle handle)138 HandleInfo(Member member, MethodHandle handle) { 139 this.member = member; 140 this.handle = handle; 141 } 142 143 @Override getReferenceKind()144 public int getReferenceKind() { 145 switch (handle.getHandleKind()) { 146 case INVOKE_VIRTUAL: { 147 if (member.getDeclaringClass().isInterface()) { 148 return REF_invokeInterface; 149 } else { 150 return REF_invokeVirtual; 151 } 152 } 153 154 case INVOKE_DIRECT: { 155 if (member instanceof Constructor) { 156 return REF_newInvokeSpecial; 157 } else { 158 return REF_invokeSpecial; 159 } 160 } 161 162 case INVOKE_SUPER: 163 return MethodHandleInfo.REF_invokeSpecial; 164 case INVOKE_STATIC: 165 return MethodHandleInfo.REF_invokeStatic; 166 case IGET: 167 return MethodHandleInfo.REF_getField; 168 case IPUT: 169 return MethodHandleInfo.REF_putField; 170 case SGET: 171 return MethodHandleInfo.REF_getStatic; 172 case SPUT: 173 return MethodHandleInfo.REF_putStatic; 174 default: 175 throw new AssertionError("Unexpected handle kind: " + handle.getHandleKind()); 176 } 177 } 178 179 @Override getDeclaringClass()180 public Class<?> getDeclaringClass() { 181 return member.getDeclaringClass(); 182 } 183 184 @Override getName()185 public String getName() { 186 if (member instanceof Constructor) { 187 return "<init>"; 188 } 189 190 return member.getName(); 191 } 192 193 @Override getMethodType()194 public MethodType getMethodType() { 195 // The "nominal" type of a cracked method handle is the same as the type 196 // of the handle itself, except in the cases enumerated below. 197 MethodType handleType = handle.type(); 198 199 boolean omitLeadingParam = false; 200 201 // For constructs, the return type is always void.class, and not the type of 202 // the object returned. We also need to omit the leading reference, which is 203 // nominally the type of the object being constructed. 204 if (member instanceof Constructor) { 205 handleType = handleType.changeReturnType(void.class); 206 omitLeadingParam = true; 207 } 208 209 // For instance field gets/puts and instance method gets/puts, we omit the 210 // leading reference parameter to |this|. 211 switch (handle.getHandleKind()) { 212 case IGET: 213 case IPUT: 214 case INVOKE_INTERFACE: 215 case INVOKE_DIRECT: 216 case INVOKE_VIRTUAL: 217 case INVOKE_SUPER: 218 omitLeadingParam = true; 219 } 220 221 return omitLeadingParam ? handleType.dropParameterTypes(0, 1) : handleType; 222 } 223 224 @Override reflectAs(Class<T> expected, MethodHandles.Lookup lookup)225 public <T extends Member> T reflectAs(Class<T> expected, MethodHandles.Lookup lookup) { 226 try { 227 final Class declaringClass = member.getDeclaringClass(); 228 if (Modifier.isNative(getModifiers()) && 229 (MethodHandle.class.isAssignableFrom(declaringClass) 230 || VarHandle.class.isAssignableFrom(declaringClass))) { 231 if (member instanceof Method) { 232 Method m = (Method) member; 233 if (m.isVarArgs()) { 234 // Signature-polymorphic methods should not be reflected as there 235 // is no support for invoking them via reflection. 236 // 237 // We've identified this method as signature-polymorphic due to 238 // its flags (var-args and native) and its class. 239 throw new IllegalArgumentException( 240 "Reflecting signature polymorphic method"); 241 } 242 } 243 } 244 lookup.checkAccess( 245 declaringClass, declaringClass, member.getModifiers(), member.getName()); 246 } catch (IllegalAccessException exception) { 247 throw new IllegalArgumentException("Unable to access member.", exception); 248 } 249 250 return (T) member; 251 } 252 253 @Override getModifiers()254 public int getModifiers() { 255 return member.getModifiers(); 256 } 257 258 @Override toString()259 public String toString() { 260 return MethodHandleInfo.toString( 261 getReferenceKind(), getDeclaringClass(), getName(), getMethodType()); 262 } 263 } 264 } 265