• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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