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