1 /* 2 * Copyright 2016 Google Inc. 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. Google designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Google in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 package java.lang.invoke; 22 23 import java.lang.reflect.Constructor; 24 import java.lang.reflect.Member; 25 import java.lang.reflect.Method; 26 import java.lang.reflect.Modifier; 27 28 /** 29 * A method handle that's directly associated with an ArtField or an ArtMethod and 30 * specifies no additional transformations. 31 * 32 * @hide 33 */ 34 public class MethodHandleImpl extends MethodHandle implements Cloneable { 35 private HandleInfo info; 36 MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type)37 MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type) { 38 super(artFieldOrMethod, handleKind, type); 39 } 40 41 @Override clone()42 public Object clone() throws CloneNotSupportedException { 43 return super.clone(); 44 } 45 reveal()46 MethodHandleInfo reveal() { 47 if (info == null) { 48 final Member member = getMemberInternal(); 49 info = new HandleInfo(member, this); 50 } 51 52 return info; 53 } 54 55 /** 56 * Materialize a member from this method handle's ArtField or ArtMethod pointer. 57 */ getMemberInternal()58 public native Member getMemberInternal(); 59 60 /** 61 * Implementation of {@code MethodHandleInfo} in terms of the handle being cracked 62 * and its corresponding {@code java.lang.reflect.Member}. 63 */ 64 static class HandleInfo implements MethodHandleInfo { 65 private final Member member; 66 private final MethodHandle handle; 67 HandleInfo(Member member, MethodHandle handle)68 HandleInfo(Member member, MethodHandle handle) { 69 this.member = member; 70 this.handle = handle; 71 } 72 73 @Override getReferenceKind()74 public int getReferenceKind() { 75 switch (handle.getHandleKind()) { 76 case INVOKE_VIRTUAL: { 77 if (member.getDeclaringClass().isInterface()) { 78 return REF_invokeInterface; 79 } else { 80 return REF_invokeVirtual; 81 } 82 } 83 84 case INVOKE_DIRECT: { 85 if (member instanceof Constructor) { 86 return REF_newInvokeSpecial; 87 } else { 88 return REF_invokeSpecial; 89 } 90 } 91 92 case INVOKE_SUPER: 93 return MethodHandleInfo.REF_invokeSpecial; 94 case INVOKE_STATIC: 95 return MethodHandleInfo.REF_invokeStatic; 96 case IGET: 97 return MethodHandleInfo.REF_getField; 98 case IPUT: 99 return MethodHandleInfo.REF_putField; 100 case SGET: 101 return MethodHandleInfo.REF_getStatic; 102 case SPUT: 103 return MethodHandleInfo.REF_putStatic; 104 default: 105 throw new AssertionError("Unexpected handle kind: " + handle.getHandleKind()); 106 } 107 } 108 109 @Override getDeclaringClass()110 public Class<?> getDeclaringClass() { 111 return member.getDeclaringClass(); 112 } 113 114 @Override getName()115 public String getName() { 116 if (member instanceof Constructor) { 117 return "<init>"; 118 } 119 120 return member.getName(); 121 } 122 123 @Override getMethodType()124 public MethodType getMethodType() { 125 // The "nominal" type of a cracked method handle is the same as the type 126 // of the handle itself, except in the cases enumerated below. 127 MethodType handleType = handle.type(); 128 129 boolean omitLeadingParam = false; 130 131 // For constructs, the return type is always void.class, and not the type of 132 // the object returned. We also need to omit the leading reference, which is 133 // nominally the type of the object being constructed. 134 if (member instanceof Constructor) { 135 handleType = handleType.changeReturnType(void.class); 136 omitLeadingParam = true; 137 } 138 139 // For instance field gets/puts and instance method gets/puts, we omit the 140 // leading reference parameter to |this|. 141 switch (handle.getHandleKind()) { 142 case IGET: 143 case IPUT: 144 case INVOKE_INTERFACE: 145 case INVOKE_DIRECT: 146 case INVOKE_VIRTUAL: 147 case INVOKE_SUPER: 148 omitLeadingParam = true; 149 } 150 151 return omitLeadingParam ? handleType.dropParameterTypes(0, 1) : handleType; 152 } 153 154 @Override reflectAs(Class<T> expected, MethodHandles.Lookup lookup)155 public <T extends Member> T reflectAs(Class<T> expected, MethodHandles.Lookup lookup) { 156 try { 157 lookup.checkAccess(member.getDeclaringClass(), member.getDeclaringClass(), 158 member.getModifiers(), member.getName()); 159 } catch (IllegalAccessException exception) { 160 throw new IllegalArgumentException("Unable to access member.", exception); 161 } 162 163 return (T) member; 164 } 165 166 @Override getModifiers()167 public int getModifiers() { 168 return member.getModifiers(); 169 } 170 } 171 } 172