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.Member;
26 import java.lang.reflect.Method;
27 import java.lang.reflect.Modifier;
28 
29 // Android-changed: Android specific implementation.
30 // The whole class was implemented from scratch for the Android runtime based
31 // on the specification of the MethodHandle class.
32 // The code does not originate from upstream OpenJDK.
33 /**
34  * A method handle that's directly associated with an ArtField or an ArtMethod and
35  * specifies no additional transformations.
36  *
37  * @hide
38  */
39 public class MethodHandleImpl extends MethodHandle implements Cloneable {
40     private HandleInfo info;
41 
MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type)42     MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type) {
43         super(artFieldOrMethod, handleKind, type);
44     }
45 
46     @Override
clone()47     public Object clone() throws CloneNotSupportedException {
48         return super.clone();
49     }
50 
reveal()51     MethodHandleInfo reveal() {
52         if (info == null) {
53             final Member member = getMemberInternal();
54             info = new HandleInfo(member, this);
55         }
56 
57         return info;
58     }
59 
60     /**
61      * Materialize a member from this method handle's ArtField or ArtMethod pointer.
62      */
getMemberInternal()63     public native Member getMemberInternal();
64 
65     /**
66      * Implementation of {@code MethodHandleInfo} in terms of the handle being cracked
67      * and its corresponding {@code java.lang.reflect.Member}.
68      */
69     static class HandleInfo implements MethodHandleInfo {
70         private final Member member;
71         private final MethodHandle handle;
72 
HandleInfo(Member member, MethodHandle handle)73         HandleInfo(Member member, MethodHandle handle) {
74             this.member = member;
75             this.handle = handle;
76         }
77 
78         @Override
getReferenceKind()79         public int getReferenceKind() {
80             switch (handle.getHandleKind()) {
81                 case INVOKE_VIRTUAL: {
82                     if (member.getDeclaringClass().isInterface()) {
83                         return REF_invokeInterface;
84                     } else {
85                         return REF_invokeVirtual;
86                     }
87                 }
88 
89                 case INVOKE_DIRECT: {
90                     if (member instanceof Constructor) {
91                         return REF_newInvokeSpecial;
92                     } else {
93                         return REF_invokeSpecial;
94                     }
95                 }
96 
97                 case INVOKE_SUPER:
98                     return MethodHandleInfo.REF_invokeSpecial;
99                 case INVOKE_STATIC:
100                     return MethodHandleInfo.REF_invokeStatic;
101                 case IGET:
102                     return MethodHandleInfo.REF_getField;
103                 case IPUT:
104                     return MethodHandleInfo.REF_putField;
105                 case SGET:
106                     return MethodHandleInfo.REF_getStatic;
107                 case SPUT:
108                     return MethodHandleInfo.REF_putStatic;
109                 default:
110                     throw new AssertionError("Unexpected handle kind: " + handle.getHandleKind());
111             }
112         }
113 
114         @Override
getDeclaringClass()115         public Class<?> getDeclaringClass() {
116             return member.getDeclaringClass();
117         }
118 
119         @Override
getName()120         public String getName() {
121             if (member instanceof Constructor) {
122                 return "<init>";
123             }
124 
125             return member.getName();
126         }
127 
128         @Override
getMethodType()129         public MethodType getMethodType() {
130             // The "nominal" type of a cracked method handle is the same as the type
131             // of the handle itself, except in the cases enumerated below.
132             MethodType handleType = handle.type();
133 
134             boolean omitLeadingParam = false;
135 
136             // For constructs, the return type is always void.class, and not the type of
137             // the object returned. We also need to omit the leading reference, which is
138             // nominally the type of the object being constructed.
139             if (member instanceof Constructor) {
140                 handleType = handleType.changeReturnType(void.class);
141                 omitLeadingParam = true;
142             }
143 
144             // For instance field gets/puts and instance method gets/puts, we omit the
145             // leading reference parameter to |this|.
146             switch (handle.getHandleKind()) {
147                 case IGET:
148                 case IPUT:
149                 case INVOKE_INTERFACE:
150                 case INVOKE_DIRECT:
151                 case INVOKE_VIRTUAL:
152                 case INVOKE_SUPER:
153                     omitLeadingParam = true;
154             }
155 
156             return omitLeadingParam ? handleType.dropParameterTypes(0, 1) : handleType;
157         }
158 
159         @Override
reflectAs(Class<T> expected, MethodHandles.Lookup lookup)160         public <T extends Member> T reflectAs(Class<T> expected, MethodHandles.Lookup lookup) {
161             try {
162                 final Class declaringClass = member.getDeclaringClass();
163                 if (Modifier.isNative(getModifiers()) &&
164                         (MethodHandle.class.isAssignableFrom(declaringClass)
165                                 || VarHandle.class.isAssignableFrom(declaringClass))) {
166                     if (member instanceof Method) {
167                         Method m = (Method) member;
168                         if (m.isVarArgs()) {
169                             // Signature-polymorphic methods should not be reflected as there
170                             // is no support for invoking them via reflection.
171                             //
172                             // We've identified this method as signature-polymorphic due to
173                             // its flags (var-args and native) and its class.
174                             throw new IllegalArgumentException(
175                                     "Reflecting signature polymorphic method");
176                         }
177                     }
178                 }
179                 lookup.checkAccess(
180                         declaringClass, declaringClass, member.getModifiers(), member.getName());
181             } catch (IllegalAccessException exception) {
182                 throw new IllegalArgumentException("Unable to access member.", exception);
183             }
184 
185             return (T) member;
186         }
187 
188         @Override
getModifiers()189         public int getModifiers() {
190             return member.getModifiers();
191         }
192 
193         @Override
toString()194         public String toString() {
195             return MethodHandleInfo.toString(
196                     getReferenceKind(), getDeclaringClass(), getName(), getMethodType());
197         }
198     }
199 }
200