jaroslav@1646
|
1 |
/*
|
jaroslav@1646
|
2 |
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
jaroslav@1646
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
jaroslav@1646
|
4 |
*
|
jaroslav@1646
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
jaroslav@1646
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
jaroslav@1646
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
jaroslav@1646
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
jaroslav@1646
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
jaroslav@1646
|
10 |
*
|
jaroslav@1646
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
jaroslav@1646
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
jaroslav@1646
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
jaroslav@1646
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
jaroslav@1646
|
15 |
* accompanied this code).
|
jaroslav@1646
|
16 |
*
|
jaroslav@1646
|
17 |
* You should have received a copy of the GNU General Public License version
|
jaroslav@1646
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
jaroslav@1646
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
jaroslav@1646
|
20 |
*
|
jaroslav@1646
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
jaroslav@1646
|
22 |
* or visit www.oracle.com if you need additional information or have any
|
jaroslav@1646
|
23 |
* questions.
|
jaroslav@1646
|
24 |
*/
|
jaroslav@1646
|
25 |
|
jaroslav@1646
|
26 |
package java.lang.invoke;
|
jaroslav@1646
|
27 |
|
jaroslav@1646
|
28 |
import sun.invoke.util.BytecodeDescriptor;
|
jaroslav@1646
|
29 |
import sun.invoke.util.VerifyAccess;
|
jaroslav@1646
|
30 |
|
jaroslav@1646
|
31 |
import java.lang.reflect.Constructor;
|
jaroslav@1646
|
32 |
import java.lang.reflect.Field;
|
jaroslav@1646
|
33 |
import java.lang.reflect.Method;
|
jaroslav@1646
|
34 |
import java.lang.reflect.Member;
|
jaroslav@1646
|
35 |
import java.lang.reflect.Modifier;
|
jaroslav@1646
|
36 |
import java.util.ArrayList;
|
jaroslav@1646
|
37 |
import java.util.Arrays;
|
jaroslav@1646
|
38 |
import java.util.Collections;
|
jaroslav@1646
|
39 |
import java.util.Iterator;
|
jaroslav@1646
|
40 |
import java.util.List;
|
jaroslav@1646
|
41 |
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
jaroslav@1646
|
42 |
import static java.lang.invoke.MethodHandleStatics.*;
|
jaroslav@1646
|
43 |
import java.util.Objects;
|
jaroslav@1646
|
44 |
|
jaroslav@1646
|
45 |
/**
|
jaroslav@1646
|
46 |
* A {@code MemberName} is a compact symbolic datum which fully characterizes
|
jaroslav@1646
|
47 |
* a method or field reference.
|
jaroslav@1646
|
48 |
* A member name refers to a field, method, constructor, or member type.
|
jaroslav@1646
|
49 |
* Every member name has a simple name (a string) and a type (either a Class or MethodType).
|
jaroslav@1646
|
50 |
* A member name may also have a non-null declaring class, or it may be simply
|
jaroslav@1646
|
51 |
* a naked name/type pair.
|
jaroslav@1646
|
52 |
* A member name may also have non-zero modifier flags.
|
jaroslav@1646
|
53 |
* Finally, a member name may be either resolved or unresolved.
|
jaroslav@1646
|
54 |
* If it is resolved, the existence of the named
|
jaroslav@1646
|
55 |
* <p>
|
jaroslav@1646
|
56 |
* Whether resolved or not, a member name provides no access rights or
|
jaroslav@1646
|
57 |
* invocation capability to its possessor. It is merely a compact
|
jaroslav@1646
|
58 |
* representation of all symbolic information necessary to link to
|
jaroslav@1646
|
59 |
* and properly use the named member.
|
jaroslav@1646
|
60 |
* <p>
|
jaroslav@1646
|
61 |
* When resolved, a member name's internal implementation may include references to JVM metadata.
|
jaroslav@1646
|
62 |
* This representation is stateless and only decriptive.
|
jaroslav@1646
|
63 |
* It provides no private information and no capability to use the member.
|
jaroslav@1646
|
64 |
* <p>
|
jaroslav@1646
|
65 |
* By contrast, a {@linkplain java.lang.reflect.Method} contains fuller information
|
jaroslav@1646
|
66 |
* about the internals of a method (except its bytecodes) and also
|
jaroslav@1646
|
67 |
* allows invocation. A MemberName is much lighter than a Method,
|
jaroslav@1646
|
68 |
* since it contains about 7 fields to the 16 of Method (plus its sub-arrays),
|
jaroslav@1646
|
69 |
* and those seven fields omit much of the information in Method.
|
jaroslav@1646
|
70 |
* @author jrose
|
jaroslav@1646
|
71 |
*/
|
jaroslav@1646
|
72 |
/*non-public*/ final class MemberName implements Member, Cloneable {
|
jaroslav@1646
|
73 |
private Class<?> clazz; // class in which the method is defined
|
jaroslav@1646
|
74 |
private String name; // may be null if not yet materialized
|
jaroslav@1646
|
75 |
private Object type; // may be null if not yet materialized
|
jaroslav@1646
|
76 |
private int flags; // modifier bits; see reflect.Modifier
|
jaroslav@1646
|
77 |
//@Injected JVM_Method* vmtarget;
|
jaroslav@1646
|
78 |
//@Injected int vmindex;
|
jaroslav@1646
|
79 |
private Object resolution; // if null, this guy is resolved
|
jaroslav@1646
|
80 |
|
jaroslav@1646
|
81 |
/** Return the declaring class of this member.
|
jaroslav@1646
|
82 |
* In the case of a bare name and type, the declaring class will be null.
|
jaroslav@1646
|
83 |
*/
|
jaroslav@1646
|
84 |
public Class<?> getDeclaringClass() {
|
jaroslav@1646
|
85 |
return clazz;
|
jaroslav@1646
|
86 |
}
|
jaroslav@1646
|
87 |
|
jaroslav@1646
|
88 |
/** Utility method producing the class loader of the declaring class. */
|
jaroslav@1646
|
89 |
public ClassLoader getClassLoader() {
|
jaroslav@1646
|
90 |
return clazz.getClassLoader();
|
jaroslav@1646
|
91 |
}
|
jaroslav@1646
|
92 |
|
jaroslav@1646
|
93 |
/** Return the simple name of this member.
|
jaroslav@1646
|
94 |
* For a type, it is the same as {@link Class#getSimpleName}.
|
jaroslav@1646
|
95 |
* For a method or field, it is the simple name of the member.
|
jaroslav@1646
|
96 |
* For a constructor, it is always {@code "<init>"}.
|
jaroslav@1646
|
97 |
*/
|
jaroslav@1646
|
98 |
public String getName() {
|
jaroslav@1646
|
99 |
if (name == null) {
|
jaroslav@1646
|
100 |
expandFromVM();
|
jaroslav@1646
|
101 |
if (name == null) {
|
jaroslav@1646
|
102 |
return null;
|
jaroslav@1646
|
103 |
}
|
jaroslav@1646
|
104 |
}
|
jaroslav@1646
|
105 |
return name;
|
jaroslav@1646
|
106 |
}
|
jaroslav@1646
|
107 |
|
jaroslav@1646
|
108 |
public MethodType getMethodOrFieldType() {
|
jaroslav@1646
|
109 |
if (isInvocable())
|
jaroslav@1646
|
110 |
return getMethodType();
|
jaroslav@1646
|
111 |
if (isGetter())
|
jaroslav@1646
|
112 |
return MethodType.methodType(getFieldType());
|
jaroslav@1646
|
113 |
if (isSetter())
|
jaroslav@1646
|
114 |
return MethodType.methodType(void.class, getFieldType());
|
jaroslav@1646
|
115 |
throw new InternalError("not a method or field: "+this);
|
jaroslav@1646
|
116 |
}
|
jaroslav@1646
|
117 |
|
jaroslav@1646
|
118 |
/** Return the declared type of this member, which
|
jaroslav@1646
|
119 |
* must be a method or constructor.
|
jaroslav@1646
|
120 |
*/
|
jaroslav@1646
|
121 |
public MethodType getMethodType() {
|
jaroslav@1646
|
122 |
if (type == null) {
|
jaroslav@1646
|
123 |
expandFromVM();
|
jaroslav@1646
|
124 |
if (type == null) {
|
jaroslav@1646
|
125 |
return null;
|
jaroslav@1646
|
126 |
}
|
jaroslav@1646
|
127 |
}
|
jaroslav@1646
|
128 |
if (!isInvocable()) {
|
jaroslav@1646
|
129 |
throw newIllegalArgumentException("not invocable, no method type");
|
jaroslav@1646
|
130 |
}
|
jaroslav@1646
|
131 |
|
jaroslav@1646
|
132 |
{
|
jaroslav@1646
|
133 |
// Get a snapshot of type which doesn't get changed by racing threads.
|
jaroslav@1646
|
134 |
final Object type = this.type;
|
jaroslav@1646
|
135 |
if (type instanceof MethodType) {
|
jaroslav@1646
|
136 |
return (MethodType) type;
|
jaroslav@1646
|
137 |
}
|
jaroslav@1646
|
138 |
}
|
jaroslav@1646
|
139 |
|
jaroslav@1646
|
140 |
// type is not a MethodType yet. Convert it thread-safely.
|
jaroslav@1646
|
141 |
synchronized (this) {
|
jaroslav@1646
|
142 |
if (type instanceof String) {
|
jaroslav@1646
|
143 |
String sig = (String) type;
|
jaroslav@1646
|
144 |
MethodType res = MethodType.fromMethodDescriptorString(sig, getClassLoader());
|
jaroslav@1646
|
145 |
type = res;
|
jaroslav@1646
|
146 |
} else if (type instanceof Object[]) {
|
jaroslav@1646
|
147 |
Object[] typeInfo = (Object[]) type;
|
jaroslav@1646
|
148 |
Class<?>[] ptypes = (Class<?>[]) typeInfo[1];
|
jaroslav@1646
|
149 |
Class<?> rtype = (Class<?>) typeInfo[0];
|
jaroslav@1646
|
150 |
MethodType res = MethodType.methodType(rtype, ptypes);
|
jaroslav@1646
|
151 |
type = res;
|
jaroslav@1646
|
152 |
}
|
jaroslav@1646
|
153 |
// Make sure type is a MethodType for racing threads.
|
jaroslav@1646
|
154 |
assert type instanceof MethodType : "bad method type " + type;
|
jaroslav@1646
|
155 |
}
|
jaroslav@1646
|
156 |
return (MethodType) type;
|
jaroslav@1646
|
157 |
}
|
jaroslav@1646
|
158 |
|
jaroslav@1646
|
159 |
/** Return the actual type under which this method or constructor must be invoked.
|
jaroslav@1646
|
160 |
* For non-static methods or constructors, this is the type with a leading parameter,
|
jaroslav@1646
|
161 |
* a reference to declaring class. For static methods, it is the same as the declared type.
|
jaroslav@1646
|
162 |
*/
|
jaroslav@1646
|
163 |
public MethodType getInvocationType() {
|
jaroslav@1646
|
164 |
MethodType itype = getMethodOrFieldType();
|
jaroslav@1646
|
165 |
if (isConstructor() && getReferenceKind() == REF_newInvokeSpecial)
|
jaroslav@1646
|
166 |
return itype.changeReturnType(clazz);
|
jaroslav@1646
|
167 |
if (!isStatic())
|
jaroslav@1646
|
168 |
return itype.insertParameterTypes(0, clazz);
|
jaroslav@1646
|
169 |
return itype;
|
jaroslav@1646
|
170 |
}
|
jaroslav@1646
|
171 |
|
jaroslav@1646
|
172 |
/** Utility method producing the parameter types of the method type. */
|
jaroslav@1646
|
173 |
public Class<?>[] getParameterTypes() {
|
jaroslav@1646
|
174 |
return getMethodType().parameterArray();
|
jaroslav@1646
|
175 |
}
|
jaroslav@1646
|
176 |
|
jaroslav@1646
|
177 |
/** Utility method producing the return type of the method type. */
|
jaroslav@1646
|
178 |
public Class<?> getReturnType() {
|
jaroslav@1646
|
179 |
return getMethodType().returnType();
|
jaroslav@1646
|
180 |
}
|
jaroslav@1646
|
181 |
|
jaroslav@1646
|
182 |
/** Return the declared type of this member, which
|
jaroslav@1646
|
183 |
* must be a field or type.
|
jaroslav@1646
|
184 |
* If it is a type member, that type itself is returned.
|
jaroslav@1646
|
185 |
*/
|
jaroslav@1646
|
186 |
public Class<?> getFieldType() {
|
jaroslav@1646
|
187 |
if (type == null) {
|
jaroslav@1646
|
188 |
expandFromVM();
|
jaroslav@1646
|
189 |
if (type == null) {
|
jaroslav@1646
|
190 |
return null;
|
jaroslav@1646
|
191 |
}
|
jaroslav@1646
|
192 |
}
|
jaroslav@1646
|
193 |
if (isInvocable()) {
|
jaroslav@1646
|
194 |
throw newIllegalArgumentException("not a field or nested class, no simple type");
|
jaroslav@1646
|
195 |
}
|
jaroslav@1646
|
196 |
|
jaroslav@1646
|
197 |
{
|
jaroslav@1646
|
198 |
// Get a snapshot of type which doesn't get changed by racing threads.
|
jaroslav@1646
|
199 |
final Object type = this.type;
|
jaroslav@1646
|
200 |
if (type instanceof Class<?>) {
|
jaroslav@1646
|
201 |
return (Class<?>) type;
|
jaroslav@1646
|
202 |
}
|
jaroslav@1646
|
203 |
}
|
jaroslav@1646
|
204 |
|
jaroslav@1646
|
205 |
// type is not a Class yet. Convert it thread-safely.
|
jaroslav@1646
|
206 |
synchronized (this) {
|
jaroslav@1646
|
207 |
if (type instanceof String) {
|
jaroslav@1646
|
208 |
String sig = (String) type;
|
jaroslav@1646
|
209 |
MethodType mtype = MethodType.fromMethodDescriptorString("()"+sig, getClassLoader());
|
jaroslav@1646
|
210 |
Class<?> res = mtype.returnType();
|
jaroslav@1646
|
211 |
type = res;
|
jaroslav@1646
|
212 |
}
|
jaroslav@1646
|
213 |
// Make sure type is a Class for racing threads.
|
jaroslav@1646
|
214 |
assert type instanceof Class<?> : "bad field type " + type;
|
jaroslav@1646
|
215 |
}
|
jaroslav@1646
|
216 |
return (Class<?>) type;
|
jaroslav@1646
|
217 |
}
|
jaroslav@1646
|
218 |
|
jaroslav@1646
|
219 |
/** Utility method to produce either the method type or field type of this member. */
|
jaroslav@1646
|
220 |
public Object getType() {
|
jaroslav@1646
|
221 |
return (isInvocable() ? getMethodType() : getFieldType());
|
jaroslav@1646
|
222 |
}
|
jaroslav@1646
|
223 |
|
jaroslav@1646
|
224 |
/** Utility method to produce the signature of this member,
|
jaroslav@1646
|
225 |
* used within the class file format to describe its type.
|
jaroslav@1646
|
226 |
*/
|
jaroslav@1646
|
227 |
public String getSignature() {
|
jaroslav@1646
|
228 |
if (type == null) {
|
jaroslav@1646
|
229 |
expandFromVM();
|
jaroslav@1646
|
230 |
if (type == null) {
|
jaroslav@1646
|
231 |
return null;
|
jaroslav@1646
|
232 |
}
|
jaroslav@1646
|
233 |
}
|
jaroslav@1646
|
234 |
if (isInvocable())
|
jaroslav@1646
|
235 |
return BytecodeDescriptor.unparse(getMethodType());
|
jaroslav@1646
|
236 |
else
|
jaroslav@1646
|
237 |
return BytecodeDescriptor.unparse(getFieldType());
|
jaroslav@1646
|
238 |
}
|
jaroslav@1646
|
239 |
|
jaroslav@1646
|
240 |
/** Return the modifier flags of this member.
|
jaroslav@1646
|
241 |
* @see java.lang.reflect.Modifier
|
jaroslav@1646
|
242 |
*/
|
jaroslav@1646
|
243 |
public int getModifiers() {
|
jaroslav@1646
|
244 |
return (flags & RECOGNIZED_MODIFIERS);
|
jaroslav@1646
|
245 |
}
|
jaroslav@1646
|
246 |
|
jaroslav@1646
|
247 |
/** Return the reference kind of this member, or zero if none.
|
jaroslav@1646
|
248 |
*/
|
jaroslav@1646
|
249 |
public byte getReferenceKind() {
|
jaroslav@1646
|
250 |
return (byte) ((flags >>> MN_REFERENCE_KIND_SHIFT) & MN_REFERENCE_KIND_MASK);
|
jaroslav@1646
|
251 |
}
|
jaroslav@1646
|
252 |
private boolean referenceKindIsConsistent() {
|
jaroslav@1646
|
253 |
byte refKind = getReferenceKind();
|
jaroslav@1646
|
254 |
if (refKind == REF_NONE) return isType();
|
jaroslav@1646
|
255 |
if (isField()) {
|
jaroslav@1646
|
256 |
assert(staticIsConsistent());
|
jaroslav@1646
|
257 |
assert(MethodHandleNatives.refKindIsField(refKind));
|
jaroslav@1646
|
258 |
} else if (isConstructor()) {
|
jaroslav@1646
|
259 |
assert(refKind == REF_newInvokeSpecial || refKind == REF_invokeSpecial);
|
jaroslav@1646
|
260 |
} else if (isMethod()) {
|
jaroslav@1646
|
261 |
assert(staticIsConsistent());
|
jaroslav@1646
|
262 |
assert(MethodHandleNatives.refKindIsMethod(refKind));
|
jaroslav@1646
|
263 |
if (clazz.isInterface())
|
jaroslav@1646
|
264 |
assert(refKind == REF_invokeInterface ||
|
jaroslav@1646
|
265 |
refKind == REF_invokeStatic ||
|
jaroslav@1646
|
266 |
refKind == REF_invokeSpecial ||
|
jaroslav@1646
|
267 |
refKind == REF_invokeVirtual && isObjectPublicMethod());
|
jaroslav@1646
|
268 |
} else {
|
jaroslav@1646
|
269 |
assert(false);
|
jaroslav@1646
|
270 |
}
|
jaroslav@1646
|
271 |
return true;
|
jaroslav@1646
|
272 |
}
|
jaroslav@1646
|
273 |
private boolean isObjectPublicMethod() {
|
jaroslav@1646
|
274 |
if (clazz == Object.class) return true;
|
jaroslav@1646
|
275 |
MethodType mtype = getMethodType();
|
jaroslav@1646
|
276 |
if (name.equals("toString") && mtype.returnType() == String.class && mtype.parameterCount() == 0)
|
jaroslav@1646
|
277 |
return true;
|
jaroslav@1646
|
278 |
if (name.equals("hashCode") && mtype.returnType() == int.class && mtype.parameterCount() == 0)
|
jaroslav@1646
|
279 |
return true;
|
jaroslav@1646
|
280 |
if (name.equals("equals") && mtype.returnType() == boolean.class && mtype.parameterCount() == 1 && mtype.parameterType(0) == Object.class)
|
jaroslav@1646
|
281 |
return true;
|
jaroslav@1646
|
282 |
return false;
|
jaroslav@1646
|
283 |
}
|
jaroslav@1646
|
284 |
/*non-public*/ boolean referenceKindIsConsistentWith(int originalRefKind) {
|
jaroslav@1646
|
285 |
int refKind = getReferenceKind();
|
jaroslav@1646
|
286 |
if (refKind == originalRefKind) return true;
|
jaroslav@1646
|
287 |
switch (originalRefKind) {
|
jaroslav@1646
|
288 |
case REF_invokeInterface:
|
jaroslav@1646
|
289 |
// Looking up an interface method, can get (e.g.) Object.hashCode
|
jaroslav@1646
|
290 |
assert(refKind == REF_invokeVirtual ||
|
jaroslav@1646
|
291 |
refKind == REF_invokeSpecial) : this;
|
jaroslav@1646
|
292 |
return true;
|
jaroslav@1646
|
293 |
case REF_invokeVirtual:
|
jaroslav@1646
|
294 |
case REF_newInvokeSpecial:
|
jaroslav@1646
|
295 |
// Looked up a virtual, can get (e.g.) final String.hashCode.
|
jaroslav@1646
|
296 |
assert(refKind == REF_invokeSpecial) : this;
|
jaroslav@1646
|
297 |
return true;
|
jaroslav@1646
|
298 |
}
|
jaroslav@1646
|
299 |
assert(false) : this+" != "+MethodHandleNatives.refKindName((byte)originalRefKind);
|
jaroslav@1646
|
300 |
return true;
|
jaroslav@1646
|
301 |
}
|
jaroslav@1646
|
302 |
private boolean staticIsConsistent() {
|
jaroslav@1646
|
303 |
byte refKind = getReferenceKind();
|
jaroslav@1646
|
304 |
return MethodHandleNatives.refKindIsStatic(refKind) == isStatic() || getModifiers() == 0;
|
jaroslav@1646
|
305 |
}
|
jaroslav@1646
|
306 |
private boolean vminfoIsConsistent() {
|
jaroslav@1646
|
307 |
byte refKind = getReferenceKind();
|
jaroslav@1646
|
308 |
assert(isResolved()); // else don't call
|
jaroslav@1646
|
309 |
Object vminfo = MethodHandleNatives.getMemberVMInfo(this);
|
jaroslav@1646
|
310 |
assert(vminfo instanceof Object[]);
|
jaroslav@1646
|
311 |
long vmindex = (Long) ((Object[])vminfo)[0];
|
jaroslav@1646
|
312 |
Object vmtarget = ((Object[])vminfo)[1];
|
jaroslav@1646
|
313 |
if (MethodHandleNatives.refKindIsField(refKind)) {
|
jaroslav@1646
|
314 |
assert(vmindex >= 0) : vmindex + ":" + this;
|
jaroslav@1646
|
315 |
assert(vmtarget instanceof Class);
|
jaroslav@1646
|
316 |
} else {
|
jaroslav@1646
|
317 |
if (MethodHandleNatives.refKindDoesDispatch(refKind))
|
jaroslav@1646
|
318 |
assert(vmindex >= 0) : vmindex + ":" + this;
|
jaroslav@1646
|
319 |
else
|
jaroslav@1646
|
320 |
assert(vmindex < 0) : vmindex;
|
jaroslav@1646
|
321 |
assert(vmtarget instanceof MemberName) : vmtarget + " in " + this;
|
jaroslav@1646
|
322 |
}
|
jaroslav@1646
|
323 |
return true;
|
jaroslav@1646
|
324 |
}
|
jaroslav@1646
|
325 |
|
jaroslav@1646
|
326 |
private MemberName changeReferenceKind(byte refKind, byte oldKind) {
|
jaroslav@1646
|
327 |
assert(getReferenceKind() == oldKind);
|
jaroslav@1646
|
328 |
assert(MethodHandleNatives.refKindIsValid(refKind));
|
jaroslav@1646
|
329 |
flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT);
|
jaroslav@1646
|
330 |
// if (isConstructor() && refKind != REF_newInvokeSpecial)
|
jaroslav@1646
|
331 |
// flags += (IS_METHOD - IS_CONSTRUCTOR);
|
jaroslav@1646
|
332 |
// else if (refKind == REF_newInvokeSpecial && isMethod())
|
jaroslav@1646
|
333 |
// flags += (IS_CONSTRUCTOR - IS_METHOD);
|
jaroslav@1646
|
334 |
return this;
|
jaroslav@1646
|
335 |
}
|
jaroslav@1646
|
336 |
|
jaroslav@1646
|
337 |
private boolean testFlags(int mask, int value) {
|
jaroslav@1646
|
338 |
return (flags & mask) == value;
|
jaroslav@1646
|
339 |
}
|
jaroslav@1646
|
340 |
private boolean testAllFlags(int mask) {
|
jaroslav@1646
|
341 |
return testFlags(mask, mask);
|
jaroslav@1646
|
342 |
}
|
jaroslav@1646
|
343 |
private boolean testAnyFlags(int mask) {
|
jaroslav@1646
|
344 |
return !testFlags(mask, 0);
|
jaroslav@1646
|
345 |
}
|
jaroslav@1646
|
346 |
|
jaroslav@1646
|
347 |
/** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */
|
jaroslav@1646
|
348 |
public boolean isMethodHandleInvoke() {
|
jaroslav@1646
|
349 |
final int bits = MH_INVOKE_MODS;
|
jaroslav@1646
|
350 |
final int negs = Modifier.STATIC;
|
jaroslav@1646
|
351 |
if (testFlags(bits | negs, bits) &&
|
jaroslav@1646
|
352 |
clazz == MethodHandle.class) {
|
jaroslav@1646
|
353 |
return isMethodHandleInvokeName(name);
|
jaroslav@1646
|
354 |
}
|
jaroslav@1646
|
355 |
return false;
|
jaroslav@1646
|
356 |
}
|
jaroslav@1646
|
357 |
public static boolean isMethodHandleInvokeName(String name) {
|
jaroslav@1646
|
358 |
return name.equals("invoke") || name.equals("invokeExact");
|
jaroslav@1646
|
359 |
}
|
jaroslav@1646
|
360 |
private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC;
|
jaroslav@1646
|
361 |
|
jaroslav@1646
|
362 |
/** Utility method to query the modifier flags of this member. */
|
jaroslav@1646
|
363 |
public boolean isStatic() {
|
jaroslav@1646
|
364 |
return Modifier.isStatic(flags);
|
jaroslav@1646
|
365 |
}
|
jaroslav@1646
|
366 |
/** Utility method to query the modifier flags of this member. */
|
jaroslav@1646
|
367 |
public boolean isPublic() {
|
jaroslav@1646
|
368 |
return Modifier.isPublic(flags);
|
jaroslav@1646
|
369 |
}
|
jaroslav@1646
|
370 |
/** Utility method to query the modifier flags of this member. */
|
jaroslav@1646
|
371 |
public boolean isPrivate() {
|
jaroslav@1646
|
372 |
return Modifier.isPrivate(flags);
|
jaroslav@1646
|
373 |
}
|
jaroslav@1646
|
374 |
/** Utility method to query the modifier flags of this member. */
|
jaroslav@1646
|
375 |
public boolean isProtected() {
|
jaroslav@1646
|
376 |
return Modifier.isProtected(flags);
|
jaroslav@1646
|
377 |
}
|
jaroslav@1646
|
378 |
/** Utility method to query the modifier flags of this member. */
|
jaroslav@1646
|
379 |
public boolean isFinal() {
|
jaroslav@1646
|
380 |
return Modifier.isFinal(flags);
|
jaroslav@1646
|
381 |
}
|
jaroslav@1646
|
382 |
/** Utility method to query whether this member or its defining class is final. */
|
jaroslav@1646
|
383 |
public boolean canBeStaticallyBound() {
|
jaroslav@1646
|
384 |
return Modifier.isFinal(flags | clazz.getModifiers());
|
jaroslav@1646
|
385 |
}
|
jaroslav@1646
|
386 |
/** Utility method to query the modifier flags of this member. */
|
jaroslav@1646
|
387 |
public boolean isVolatile() {
|
jaroslav@1646
|
388 |
return Modifier.isVolatile(flags);
|
jaroslav@1646
|
389 |
}
|
jaroslav@1646
|
390 |
/** Utility method to query the modifier flags of this member. */
|
jaroslav@1646
|
391 |
public boolean isAbstract() {
|
jaroslav@1646
|
392 |
return Modifier.isAbstract(flags);
|
jaroslav@1646
|
393 |
}
|
jaroslav@1646
|
394 |
/** Utility method to query the modifier flags of this member. */
|
jaroslav@1646
|
395 |
public boolean isNative() {
|
jaroslav@1646
|
396 |
return Modifier.isNative(flags);
|
jaroslav@1646
|
397 |
}
|
jaroslav@1646
|
398 |
// let the rest (native, volatile, transient, etc.) be tested via Modifier.isFoo
|
jaroslav@1646
|
399 |
|
jaroslav@1646
|
400 |
// unofficial modifier flags, used by HotSpot:
|
jaroslav@1646
|
401 |
static final int BRIDGE = 0x00000040;
|
jaroslav@1646
|
402 |
static final int VARARGS = 0x00000080;
|
jaroslav@1646
|
403 |
static final int SYNTHETIC = 0x00001000;
|
jaroslav@1646
|
404 |
static final int ANNOTATION= 0x00002000;
|
jaroslav@1646
|
405 |
static final int ENUM = 0x00004000;
|
jaroslav@1646
|
406 |
/** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
|
jaroslav@1646
|
407 |
public boolean isBridge() {
|
jaroslav@1646
|
408 |
return testAllFlags(IS_METHOD | BRIDGE);
|
jaroslav@1646
|
409 |
}
|
jaroslav@1646
|
410 |
/** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
|
jaroslav@1646
|
411 |
public boolean isVarargs() {
|
jaroslav@1646
|
412 |
return testAllFlags(VARARGS) && isInvocable();
|
jaroslav@1646
|
413 |
}
|
jaroslav@1646
|
414 |
/** Utility method to query the modifier flags of this member; returns false if the member is not a method. */
|
jaroslav@1646
|
415 |
public boolean isSynthetic() {
|
jaroslav@1646
|
416 |
return testAllFlags(SYNTHETIC);
|
jaroslav@1646
|
417 |
}
|
jaroslav@1646
|
418 |
|
jaroslav@1646
|
419 |
static final String CONSTRUCTOR_NAME = "<init>"; // the ever-popular
|
jaroslav@1646
|
420 |
|
jaroslav@1646
|
421 |
// modifiers exported by the JVM:
|
jaroslav@1646
|
422 |
static final int RECOGNIZED_MODIFIERS = 0xFFFF;
|
jaroslav@1646
|
423 |
|
jaroslav@1646
|
424 |
// private flags, not part of RECOGNIZED_MODIFIERS:
|
jaroslav@1646
|
425 |
static final int
|
jaroslav@1646
|
426 |
IS_METHOD = MN_IS_METHOD, // method (not constructor)
|
jaroslav@1646
|
427 |
IS_CONSTRUCTOR = MN_IS_CONSTRUCTOR, // constructor
|
jaroslav@1646
|
428 |
IS_FIELD = MN_IS_FIELD, // field
|
jaroslav@1646
|
429 |
IS_TYPE = MN_IS_TYPE, // nested type
|
jaroslav@1646
|
430 |
CALLER_SENSITIVE = MN_CALLER_SENSITIVE; // @CallerSensitive annotation detected
|
jaroslav@1646
|
431 |
|
jaroslav@1646
|
432 |
static final int ALL_ACCESS = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;
|
jaroslav@1646
|
433 |
static final int ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE;
|
jaroslav@1646
|
434 |
static final int IS_INVOCABLE = IS_METHOD | IS_CONSTRUCTOR;
|
jaroslav@1646
|
435 |
static final int IS_FIELD_OR_METHOD = IS_METHOD | IS_FIELD;
|
jaroslav@1646
|
436 |
static final int SEARCH_ALL_SUPERS = MN_SEARCH_SUPERCLASSES | MN_SEARCH_INTERFACES;
|
jaroslav@1646
|
437 |
|
jaroslav@1646
|
438 |
/** Utility method to query whether this member is a method or constructor. */
|
jaroslav@1646
|
439 |
public boolean isInvocable() {
|
jaroslav@1646
|
440 |
return testAnyFlags(IS_INVOCABLE);
|
jaroslav@1646
|
441 |
}
|
jaroslav@1646
|
442 |
/** Utility method to query whether this member is a method, constructor, or field. */
|
jaroslav@1646
|
443 |
public boolean isFieldOrMethod() {
|
jaroslav@1646
|
444 |
return testAnyFlags(IS_FIELD_OR_METHOD);
|
jaroslav@1646
|
445 |
}
|
jaroslav@1646
|
446 |
/** Query whether this member is a method. */
|
jaroslav@1646
|
447 |
public boolean isMethod() {
|
jaroslav@1646
|
448 |
return testAllFlags(IS_METHOD);
|
jaroslav@1646
|
449 |
}
|
jaroslav@1646
|
450 |
/** Query whether this member is a constructor. */
|
jaroslav@1646
|
451 |
public boolean isConstructor() {
|
jaroslav@1646
|
452 |
return testAllFlags(IS_CONSTRUCTOR);
|
jaroslav@1646
|
453 |
}
|
jaroslav@1646
|
454 |
/** Query whether this member is a field. */
|
jaroslav@1646
|
455 |
public boolean isField() {
|
jaroslav@1646
|
456 |
return testAllFlags(IS_FIELD);
|
jaroslav@1646
|
457 |
}
|
jaroslav@1646
|
458 |
/** Query whether this member is a type. */
|
jaroslav@1646
|
459 |
public boolean isType() {
|
jaroslav@1646
|
460 |
return testAllFlags(IS_TYPE);
|
jaroslav@1646
|
461 |
}
|
jaroslav@1646
|
462 |
/** Utility method to query whether this member is neither public, private, nor protected. */
|
jaroslav@1646
|
463 |
public boolean isPackage() {
|
jaroslav@1646
|
464 |
return !testAnyFlags(ALL_ACCESS);
|
jaroslav@1646
|
465 |
}
|
jaroslav@1646
|
466 |
/** Query whether this member has a CallerSensitive annotation. */
|
jaroslav@1646
|
467 |
public boolean isCallerSensitive() {
|
jaroslav@1646
|
468 |
return testAllFlags(CALLER_SENSITIVE);
|
jaroslav@1646
|
469 |
}
|
jaroslav@1646
|
470 |
|
jaroslav@1646
|
471 |
/** Utility method to query whether this member is accessible from a given lookup class. */
|
jaroslav@1646
|
472 |
public boolean isAccessibleFrom(Class<?> lookupClass) {
|
jaroslav@1646
|
473 |
return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags,
|
jaroslav@1646
|
474 |
lookupClass, ALL_ACCESS|MethodHandles.Lookup.PACKAGE);
|
jaroslav@1646
|
475 |
}
|
jaroslav@1646
|
476 |
|
jaroslav@1646
|
477 |
/** Initialize a query. It is not resolved. */
|
jaroslav@1646
|
478 |
private void init(Class<?> defClass, String name, Object type, int flags) {
|
jaroslav@1646
|
479 |
// defining class is allowed to be null (for a naked name/type pair)
|
jaroslav@1646
|
480 |
//name.toString(); // null check
|
jaroslav@1646
|
481 |
//type.equals(type); // null check
|
jaroslav@1646
|
482 |
// fill in fields:
|
jaroslav@1646
|
483 |
this.clazz = defClass;
|
jaroslav@1646
|
484 |
this.name = name;
|
jaroslav@1646
|
485 |
this.type = type;
|
jaroslav@1646
|
486 |
this.flags = flags;
|
jaroslav@1646
|
487 |
assert(testAnyFlags(ALL_KINDS));
|
jaroslav@1646
|
488 |
assert(this.resolution == null); // nobody should have touched this yet
|
jaroslav@1646
|
489 |
//assert(referenceKindIsConsistent()); // do this after resolution
|
jaroslav@1646
|
490 |
}
|
jaroslav@1646
|
491 |
|
jaroslav@1646
|
492 |
/**
|
jaroslav@1646
|
493 |
* Calls down to the VM to fill in the fields. This method is
|
jaroslav@1646
|
494 |
* synchronized to avoid racing calls.
|
jaroslav@1646
|
495 |
*/
|
jaroslav@1646
|
496 |
private void expandFromVM() {
|
jaroslav@1646
|
497 |
if (type != null) {
|
jaroslav@1646
|
498 |
return;
|
jaroslav@1646
|
499 |
}
|
jaroslav@1646
|
500 |
if (!isResolved()) {
|
jaroslav@1646
|
501 |
return;
|
jaroslav@1646
|
502 |
}
|
jaroslav@1646
|
503 |
MethodHandleNatives.expand(this);
|
jaroslav@1646
|
504 |
}
|
jaroslav@1646
|
505 |
|
jaroslav@1646
|
506 |
// Capturing information from the Core Reflection API:
|
jaroslav@1646
|
507 |
private static int flagsMods(int flags, int mods, byte refKind) {
|
jaroslav@1646
|
508 |
assert((flags & RECOGNIZED_MODIFIERS) == 0);
|
jaroslav@1646
|
509 |
assert((mods & ~RECOGNIZED_MODIFIERS) == 0);
|
jaroslav@1646
|
510 |
assert((refKind & ~MN_REFERENCE_KIND_MASK) == 0);
|
jaroslav@1646
|
511 |
return flags | mods | (refKind << MN_REFERENCE_KIND_SHIFT);
|
jaroslav@1646
|
512 |
}
|
jaroslav@1646
|
513 |
/** Create a name for the given reflected method. The resulting name will be in a resolved state. */
|
jaroslav@1646
|
514 |
public MemberName(Method m) {
|
jaroslav@1646
|
515 |
this(m, false);
|
jaroslav@1646
|
516 |
}
|
jaroslav@1646
|
517 |
@SuppressWarnings("LeakingThisInConstructor")
|
jaroslav@1646
|
518 |
public MemberName(Method m, boolean wantSpecial) {
|
jaroslav@1646
|
519 |
m.getClass(); // NPE check
|
jaroslav@1646
|
520 |
// fill in vmtarget, vmindex while we have m in hand:
|
jaroslav@1646
|
521 |
MethodHandleNatives.init(this, m);
|
jaroslav@1646
|
522 |
if (clazz == null) { // MHN.init failed
|
jaroslav@1646
|
523 |
if (m.getDeclaringClass() == MethodHandle.class &&
|
jaroslav@1646
|
524 |
isMethodHandleInvokeName(m.getName())) {
|
jaroslav@1646
|
525 |
// The JVM did not reify this signature-polymorphic instance.
|
jaroslav@1646
|
526 |
// Need a special case here.
|
jaroslav@1646
|
527 |
// See comments on MethodHandleNatives.linkMethod.
|
jaroslav@1646
|
528 |
MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
|
jaroslav@1646
|
529 |
int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
|
jaroslav@1646
|
530 |
init(MethodHandle.class, m.getName(), type, flags);
|
jaroslav@1646
|
531 |
if (isMethodHandleInvoke())
|
jaroslav@1646
|
532 |
return;
|
jaroslav@1646
|
533 |
}
|
jaroslav@1646
|
534 |
throw new LinkageError(m.toString());
|
jaroslav@1646
|
535 |
}
|
jaroslav@1646
|
536 |
assert(isResolved() && this.clazz != null);
|
jaroslav@1646
|
537 |
this.name = m.getName();
|
jaroslav@1646
|
538 |
if (this.type == null)
|
jaroslav@1646
|
539 |
this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
|
jaroslav@1646
|
540 |
if (wantSpecial) {
|
jaroslav@1646
|
541 |
if (isAbstract())
|
jaroslav@1646
|
542 |
throw new AbstractMethodError(this.toString());
|
jaroslav@1646
|
543 |
if (getReferenceKind() == REF_invokeVirtual)
|
jaroslav@1646
|
544 |
changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
|
jaroslav@1646
|
545 |
else if (getReferenceKind() == REF_invokeInterface)
|
jaroslav@1646
|
546 |
// invokeSpecial on a default method
|
jaroslav@1646
|
547 |
changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
|
jaroslav@1646
|
548 |
}
|
jaroslav@1646
|
549 |
}
|
jaroslav@1646
|
550 |
public MemberName asSpecial() {
|
jaroslav@1646
|
551 |
switch (getReferenceKind()) {
|
jaroslav@1646
|
552 |
case REF_invokeSpecial: return this;
|
jaroslav@1646
|
553 |
case REF_invokeVirtual: return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
|
jaroslav@1646
|
554 |
case REF_invokeInterface: return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
|
jaroslav@1646
|
555 |
case REF_newInvokeSpecial: return clone().changeReferenceKind(REF_invokeSpecial, REF_newInvokeSpecial);
|
jaroslav@1646
|
556 |
}
|
jaroslav@1646
|
557 |
throw new IllegalArgumentException(this.toString());
|
jaroslav@1646
|
558 |
}
|
jaroslav@1646
|
559 |
/** If this MN is not REF_newInvokeSpecial, return a clone with that ref. kind.
|
jaroslav@1646
|
560 |
* In that case it must already be REF_invokeSpecial.
|
jaroslav@1646
|
561 |
*/
|
jaroslav@1646
|
562 |
public MemberName asConstructor() {
|
jaroslav@1646
|
563 |
switch (getReferenceKind()) {
|
jaroslav@1646
|
564 |
case REF_invokeSpecial: return clone().changeReferenceKind(REF_newInvokeSpecial, REF_invokeSpecial);
|
jaroslav@1646
|
565 |
case REF_newInvokeSpecial: return this;
|
jaroslav@1646
|
566 |
}
|
jaroslav@1646
|
567 |
throw new IllegalArgumentException(this.toString());
|
jaroslav@1646
|
568 |
}
|
jaroslav@1646
|
569 |
/** If this MN is a REF_invokeSpecial, return a clone with the "normal" kind
|
jaroslav@1646
|
570 |
* REF_invokeVirtual; also switch either to REF_invokeInterface if clazz.isInterface.
|
jaroslav@1646
|
571 |
* The end result is to get a fully virtualized version of the MN.
|
jaroslav@1646
|
572 |
* (Note that resolving in the JVM will sometimes devirtualize, changing
|
jaroslav@1646
|
573 |
* REF_invokeVirtual of a final to REF_invokeSpecial, and REF_invokeInterface
|
jaroslav@1646
|
574 |
* in some corner cases to either of the previous two; this transform
|
jaroslav@1646
|
575 |
* undoes that change under the assumption that it occurred.)
|
jaroslav@1646
|
576 |
*/
|
jaroslav@1646
|
577 |
public MemberName asNormalOriginal() {
|
jaroslav@1646
|
578 |
byte normalVirtual = clazz.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
|
jaroslav@1646
|
579 |
byte refKind = getReferenceKind();
|
jaroslav@1646
|
580 |
byte newRefKind = refKind;
|
jaroslav@1646
|
581 |
MemberName result = this;
|
jaroslav@1646
|
582 |
switch (refKind) {
|
jaroslav@1646
|
583 |
case REF_invokeInterface:
|
jaroslav@1646
|
584 |
case REF_invokeVirtual:
|
jaroslav@1646
|
585 |
case REF_invokeSpecial:
|
jaroslav@1646
|
586 |
newRefKind = normalVirtual;
|
jaroslav@1646
|
587 |
break;
|
jaroslav@1646
|
588 |
}
|
jaroslav@1646
|
589 |
if (newRefKind == refKind)
|
jaroslav@1646
|
590 |
return this;
|
jaroslav@1646
|
591 |
result = clone().changeReferenceKind(newRefKind, refKind);
|
jaroslav@1646
|
592 |
assert(this.referenceKindIsConsistentWith(result.getReferenceKind()));
|
jaroslav@1646
|
593 |
return result;
|
jaroslav@1646
|
594 |
}
|
jaroslav@1646
|
595 |
/** Create a name for the given reflected constructor. The resulting name will be in a resolved state. */
|
jaroslav@1646
|
596 |
@SuppressWarnings("LeakingThisInConstructor")
|
jaroslav@1646
|
597 |
public MemberName(Constructor<?> ctor) {
|
jaroslav@1646
|
598 |
ctor.getClass(); // NPE check
|
jaroslav@1646
|
599 |
// fill in vmtarget, vmindex while we have ctor in hand:
|
jaroslav@1646
|
600 |
MethodHandleNatives.init(this, ctor);
|
jaroslav@1646
|
601 |
assert(isResolved() && this.clazz != null);
|
jaroslav@1646
|
602 |
this.name = CONSTRUCTOR_NAME;
|
jaroslav@1646
|
603 |
if (this.type == null)
|
jaroslav@1646
|
604 |
this.type = new Object[] { void.class, ctor.getParameterTypes() };
|
jaroslav@1646
|
605 |
}
|
jaroslav@1646
|
606 |
/** Create a name for the given reflected field. The resulting name will be in a resolved state.
|
jaroslav@1646
|
607 |
*/
|
jaroslav@1646
|
608 |
public MemberName(Field fld) {
|
jaroslav@1646
|
609 |
this(fld, false);
|
jaroslav@1646
|
610 |
}
|
jaroslav@1646
|
611 |
@SuppressWarnings("LeakingThisInConstructor")
|
jaroslav@1646
|
612 |
public MemberName(Field fld, boolean makeSetter) {
|
jaroslav@1646
|
613 |
fld.getClass(); // NPE check
|
jaroslav@1646
|
614 |
// fill in vmtarget, vmindex while we have fld in hand:
|
jaroslav@1646
|
615 |
MethodHandleNatives.init(this, fld);
|
jaroslav@1646
|
616 |
assert(isResolved() && this.clazz != null);
|
jaroslav@1646
|
617 |
this.name = fld.getName();
|
jaroslav@1646
|
618 |
this.type = fld.getType();
|
jaroslav@1646
|
619 |
assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
|
jaroslav@1646
|
620 |
byte refKind = this.getReferenceKind();
|
jaroslav@1646
|
621 |
assert(refKind == (isStatic() ? REF_getStatic : REF_getField));
|
jaroslav@1646
|
622 |
if (makeSetter) {
|
jaroslav@1646
|
623 |
changeReferenceKind((byte)(refKind + (REF_putStatic - REF_getStatic)), refKind);
|
jaroslav@1646
|
624 |
}
|
jaroslav@1646
|
625 |
}
|
jaroslav@1646
|
626 |
public boolean isGetter() {
|
jaroslav@1646
|
627 |
return MethodHandleNatives.refKindIsGetter(getReferenceKind());
|
jaroslav@1646
|
628 |
}
|
jaroslav@1646
|
629 |
public boolean isSetter() {
|
jaroslav@1646
|
630 |
return MethodHandleNatives.refKindIsSetter(getReferenceKind());
|
jaroslav@1646
|
631 |
}
|
jaroslav@1646
|
632 |
public MemberName asSetter() {
|
jaroslav@1646
|
633 |
byte refKind = getReferenceKind();
|
jaroslav@1646
|
634 |
assert(MethodHandleNatives.refKindIsGetter(refKind));
|
jaroslav@1646
|
635 |
assert((REF_putStatic - REF_getStatic) == (REF_putField - REF_getField));
|
jaroslav@1646
|
636 |
byte setterRefKind = (byte)(refKind + (REF_putField - REF_getField));
|
jaroslav@1646
|
637 |
return clone().changeReferenceKind(setterRefKind, refKind);
|
jaroslav@1646
|
638 |
}
|
jaroslav@1646
|
639 |
/** Create a name for the given class. The resulting name will be in a resolved state. */
|
jaroslav@1646
|
640 |
public MemberName(Class<?> type) {
|
jaroslav@1646
|
641 |
init(type.getDeclaringClass(), type.getSimpleName(), type,
|
jaroslav@1646
|
642 |
flagsMods(IS_TYPE, type.getModifiers(), REF_NONE));
|
jaroslav@1646
|
643 |
initResolved(true);
|
jaroslav@1646
|
644 |
}
|
jaroslav@1646
|
645 |
|
jaroslav@1646
|
646 |
/**
|
jaroslav@1646
|
647 |
* Create a name for a signature-polymorphic invoker.
|
jaroslav@1646
|
648 |
* This is a placeholder for a signature-polymorphic instance
|
jaroslav@1646
|
649 |
* (of MH.invokeExact, etc.) that the JVM does not reify.
|
jaroslav@1646
|
650 |
* See comments on {@link MethodHandleNatives#linkMethod}.
|
jaroslav@1646
|
651 |
*/
|
jaroslav@1646
|
652 |
static MemberName makeMethodHandleInvoke(String name, MethodType type) {
|
jaroslav@1646
|
653 |
return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
|
jaroslav@1646
|
654 |
}
|
jaroslav@1646
|
655 |
static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) {
|
jaroslav@1646
|
656 |
MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual);
|
jaroslav@1646
|
657 |
mem.flags |= mods; // it's not resolved, but add these modifiers anyway
|
jaroslav@1646
|
658 |
assert(mem.isMethodHandleInvoke()) : mem;
|
jaroslav@1646
|
659 |
return mem;
|
jaroslav@1646
|
660 |
}
|
jaroslav@1646
|
661 |
|
jaroslav@1646
|
662 |
// bare-bones constructor; the JVM will fill it in
|
jaroslav@1646
|
663 |
MemberName() { }
|
jaroslav@1646
|
664 |
|
jaroslav@1646
|
665 |
// locally useful cloner
|
jaroslav@1646
|
666 |
@Override protected MemberName clone() {
|
jaroslav@1646
|
667 |
try {
|
jaroslav@1646
|
668 |
return (MemberName) super.clone();
|
jaroslav@1646
|
669 |
} catch (CloneNotSupportedException ex) {
|
jaroslav@1646
|
670 |
throw newInternalError(ex);
|
jaroslav@1646
|
671 |
}
|
jaroslav@1646
|
672 |
}
|
jaroslav@1646
|
673 |
|
jaroslav@1646
|
674 |
/** Get the definition of this member name.
|
jaroslav@1646
|
675 |
* This may be in a super-class of the declaring class of this member.
|
jaroslav@1646
|
676 |
*/
|
jaroslav@1646
|
677 |
public MemberName getDefinition() {
|
jaroslav@1646
|
678 |
if (!isResolved()) throw new IllegalStateException("must be resolved: "+this);
|
jaroslav@1646
|
679 |
if (isType()) return this;
|
jaroslav@1646
|
680 |
MemberName res = this.clone();
|
jaroslav@1646
|
681 |
res.clazz = null;
|
jaroslav@1646
|
682 |
res.type = null;
|
jaroslav@1646
|
683 |
res.name = null;
|
jaroslav@1646
|
684 |
res.resolution = res;
|
jaroslav@1646
|
685 |
res.expandFromVM();
|
jaroslav@1646
|
686 |
assert(res.getName().equals(this.getName()));
|
jaroslav@1646
|
687 |
return res;
|
jaroslav@1646
|
688 |
}
|
jaroslav@1646
|
689 |
|
jaroslav@1646
|
690 |
@Override
|
jaroslav@1646
|
691 |
public int hashCode() {
|
jaroslav@1646
|
692 |
return Objects.hash(clazz, getReferenceKind(), name, getType());
|
jaroslav@1646
|
693 |
}
|
jaroslav@1646
|
694 |
@Override
|
jaroslav@1646
|
695 |
public boolean equals(Object that) {
|
jaroslav@1646
|
696 |
return (that instanceof MemberName && this.equals((MemberName)that));
|
jaroslav@1646
|
697 |
}
|
jaroslav@1646
|
698 |
|
jaroslav@1646
|
699 |
/** Decide if two member names have exactly the same symbolic content.
|
jaroslav@1646
|
700 |
* Does not take into account any actual class members, so even if
|
jaroslav@1646
|
701 |
* two member names resolve to the same actual member, they may
|
jaroslav@1646
|
702 |
* be distinct references.
|
jaroslav@1646
|
703 |
*/
|
jaroslav@1646
|
704 |
public boolean equals(MemberName that) {
|
jaroslav@1646
|
705 |
if (this == that) return true;
|
jaroslav@1646
|
706 |
if (that == null) return false;
|
jaroslav@1646
|
707 |
return this.clazz == that.clazz
|
jaroslav@1646
|
708 |
&& this.getReferenceKind() == that.getReferenceKind()
|
jaroslav@1646
|
709 |
&& Objects.equals(this.name, that.name)
|
jaroslav@1646
|
710 |
&& Objects.equals(this.getType(), that.getType());
|
jaroslav@1646
|
711 |
}
|
jaroslav@1646
|
712 |
|
jaroslav@1646
|
713 |
// Construction from symbolic parts, for queries:
|
jaroslav@1646
|
714 |
/** Create a field or type name from the given components:
|
jaroslav@1646
|
715 |
* Declaring class, name, type, reference kind.
|
jaroslav@1646
|
716 |
* The declaring class may be supplied as null if this is to be a bare name and type.
|
jaroslav@1646
|
717 |
* The resulting name will in an unresolved state.
|
jaroslav@1646
|
718 |
*/
|
jaroslav@1646
|
719 |
public MemberName(Class<?> defClass, String name, Class<?> type, byte refKind) {
|
jaroslav@1646
|
720 |
init(defClass, name, type, flagsMods(IS_FIELD, 0, refKind));
|
jaroslav@1646
|
721 |
initResolved(false);
|
jaroslav@1646
|
722 |
}
|
jaroslav@1646
|
723 |
/** Create a field or type name from the given components: Declaring class, name, type.
|
jaroslav@1646
|
724 |
* The declaring class may be supplied as null if this is to be a bare name and type.
|
jaroslav@1646
|
725 |
* The modifier flags default to zero.
|
jaroslav@1646
|
726 |
* The resulting name will in an unresolved state.
|
jaroslav@1646
|
727 |
*/
|
jaroslav@1646
|
728 |
public MemberName(Class<?> defClass, String name, Class<?> type, Void unused) {
|
jaroslav@1646
|
729 |
this(defClass, name, type, REF_NONE);
|
jaroslav@1646
|
730 |
initResolved(false);
|
jaroslav@1646
|
731 |
}
|
jaroslav@1646
|
732 |
/** Create a method or constructor name from the given components: Declaring class, name, type, modifiers.
|
jaroslav@1646
|
733 |
* It will be a constructor if and only if the name is {@code "<init>"}.
|
jaroslav@1646
|
734 |
* The declaring class may be supplied as null if this is to be a bare name and type.
|
jaroslav@1646
|
735 |
* The last argument is optional, a boolean which requests REF_invokeSpecial.
|
jaroslav@1646
|
736 |
* The resulting name will in an unresolved state.
|
jaroslav@1646
|
737 |
*/
|
jaroslav@1646
|
738 |
public MemberName(Class<?> defClass, String name, MethodType type, byte refKind) {
|
jaroslav@1646
|
739 |
int initFlags = (name != null && name.equals(CONSTRUCTOR_NAME) ? IS_CONSTRUCTOR : IS_METHOD);
|
jaroslav@1646
|
740 |
init(defClass, name, type, flagsMods(initFlags, 0, refKind));
|
jaroslav@1646
|
741 |
initResolved(false);
|
jaroslav@1646
|
742 |
}
|
jaroslav@1646
|
743 |
/** Create a method, constructor, or field name from the given components:
|
jaroslav@1646
|
744 |
* Reference kind, declaring class, name, type.
|
jaroslav@1646
|
745 |
*/
|
jaroslav@1646
|
746 |
public MemberName(byte refKind, Class<?> defClass, String name, Object type) {
|
jaroslav@1646
|
747 |
int kindFlags;
|
jaroslav@1646
|
748 |
if (MethodHandleNatives.refKindIsField(refKind)) {
|
jaroslav@1646
|
749 |
kindFlags = IS_FIELD;
|
jaroslav@1646
|
750 |
if (!(type instanceof Class))
|
jaroslav@1646
|
751 |
throw newIllegalArgumentException("not a field type");
|
jaroslav@1646
|
752 |
} else if (MethodHandleNatives.refKindIsMethod(refKind)) {
|
jaroslav@1646
|
753 |
kindFlags = IS_METHOD;
|
jaroslav@1646
|
754 |
if (!(type instanceof MethodType))
|
jaroslav@1646
|
755 |
throw newIllegalArgumentException("not a method type");
|
jaroslav@1646
|
756 |
} else if (refKind == REF_newInvokeSpecial) {
|
jaroslav@1646
|
757 |
kindFlags = IS_CONSTRUCTOR;
|
jaroslav@1646
|
758 |
if (!(type instanceof MethodType) ||
|
jaroslav@1646
|
759 |
!CONSTRUCTOR_NAME.equals(name))
|
jaroslav@1646
|
760 |
throw newIllegalArgumentException("not a constructor type or name");
|
jaroslav@1646
|
761 |
} else {
|
jaroslav@1646
|
762 |
throw newIllegalArgumentException("bad reference kind "+refKind);
|
jaroslav@1646
|
763 |
}
|
jaroslav@1646
|
764 |
init(defClass, name, type, flagsMods(kindFlags, 0, refKind));
|
jaroslav@1646
|
765 |
initResolved(false);
|
jaroslav@1646
|
766 |
}
|
jaroslav@1646
|
767 |
/** Query whether this member name is resolved to a non-static, non-final method.
|
jaroslav@1646
|
768 |
*/
|
jaroslav@1646
|
769 |
public boolean hasReceiverTypeDispatch() {
|
jaroslav@1646
|
770 |
return MethodHandleNatives.refKindDoesDispatch(getReferenceKind());
|
jaroslav@1646
|
771 |
}
|
jaroslav@1646
|
772 |
|
jaroslav@1646
|
773 |
/** Query whether this member name is resolved.
|
jaroslav@1646
|
774 |
* A resolved member name is one for which the JVM has found
|
jaroslav@1646
|
775 |
* a method, constructor, field, or type binding corresponding exactly to the name.
|
jaroslav@1646
|
776 |
* (Document?)
|
jaroslav@1646
|
777 |
*/
|
jaroslav@1646
|
778 |
public boolean isResolved() {
|
jaroslav@1646
|
779 |
return resolution == null;
|
jaroslav@1646
|
780 |
}
|
jaroslav@1646
|
781 |
|
jaroslav@1646
|
782 |
private void initResolved(boolean isResolved) {
|
jaroslav@1646
|
783 |
assert(this.resolution == null); // not initialized yet!
|
jaroslav@1646
|
784 |
if (!isResolved)
|
jaroslav@1646
|
785 |
this.resolution = this;
|
jaroslav@1646
|
786 |
assert(isResolved() == isResolved);
|
jaroslav@1646
|
787 |
}
|
jaroslav@1646
|
788 |
|
jaroslav@1646
|
789 |
void checkForTypeAlias() {
|
jaroslav@1646
|
790 |
if (isInvocable()) {
|
jaroslav@1646
|
791 |
MethodType type;
|
jaroslav@1646
|
792 |
if (this.type instanceof MethodType)
|
jaroslav@1646
|
793 |
type = (MethodType) this.type;
|
jaroslav@1646
|
794 |
else
|
jaroslav@1646
|
795 |
this.type = type = getMethodType();
|
jaroslav@1646
|
796 |
if (type.erase() == type) return;
|
jaroslav@1646
|
797 |
if (VerifyAccess.isTypeVisible(type, clazz)) return;
|
jaroslav@1646
|
798 |
throw new LinkageError("bad method type alias: "+type+" not visible from "+clazz);
|
jaroslav@1646
|
799 |
} else {
|
jaroslav@1646
|
800 |
Class<?> type;
|
jaroslav@1646
|
801 |
if (this.type instanceof Class<?>)
|
jaroslav@1646
|
802 |
type = (Class<?>) this.type;
|
jaroslav@1646
|
803 |
else
|
jaroslav@1646
|
804 |
this.type = type = getFieldType();
|
jaroslav@1646
|
805 |
if (VerifyAccess.isTypeVisible(type, clazz)) return;
|
jaroslav@1646
|
806 |
throw new LinkageError("bad field type alias: "+type+" not visible from "+clazz);
|
jaroslav@1646
|
807 |
}
|
jaroslav@1646
|
808 |
}
|
jaroslav@1646
|
809 |
|
jaroslav@1646
|
810 |
|
jaroslav@1646
|
811 |
/** Produce a string form of this member name.
|
jaroslav@1646
|
812 |
* For types, it is simply the type's own string (as reported by {@code toString}).
|
jaroslav@1646
|
813 |
* For fields, it is {@code "DeclaringClass.name/type"}.
|
jaroslav@1646
|
814 |
* For methods and constructors, it is {@code "DeclaringClass.name(ptype...)rtype"}.
|
jaroslav@1646
|
815 |
* If the declaring class is null, the prefix {@code "DeclaringClass."} is omitted.
|
jaroslav@1646
|
816 |
* If the member is unresolved, a prefix {@code "*."} is prepended.
|
jaroslav@1646
|
817 |
*/
|
jaroslav@1646
|
818 |
@SuppressWarnings("LocalVariableHidesMemberVariable")
|
jaroslav@1646
|
819 |
@Override
|
jaroslav@1646
|
820 |
public String toString() {
|
jaroslav@1646
|
821 |
if (isType())
|
jaroslav@1646
|
822 |
return type.toString(); // class java.lang.String
|
jaroslav@1646
|
823 |
// else it is a field, method, or constructor
|
jaroslav@1646
|
824 |
StringBuilder buf = new StringBuilder();
|
jaroslav@1646
|
825 |
if (getDeclaringClass() != null) {
|
jaroslav@1646
|
826 |
buf.append(getName(clazz));
|
jaroslav@1646
|
827 |
buf.append('.');
|
jaroslav@1646
|
828 |
}
|
jaroslav@1646
|
829 |
String name = getName();
|
jaroslav@1646
|
830 |
buf.append(name == null ? "*" : name);
|
jaroslav@1646
|
831 |
Object type = getType();
|
jaroslav@1646
|
832 |
if (!isInvocable()) {
|
jaroslav@1646
|
833 |
buf.append('/');
|
jaroslav@1646
|
834 |
buf.append(type == null ? "*" : getName(type));
|
jaroslav@1646
|
835 |
} else {
|
jaroslav@1646
|
836 |
buf.append(type == null ? "(*)*" : getName(type));
|
jaroslav@1646
|
837 |
}
|
jaroslav@1646
|
838 |
byte refKind = getReferenceKind();
|
jaroslav@1646
|
839 |
if (refKind != REF_NONE) {
|
jaroslav@1646
|
840 |
buf.append('/');
|
jaroslav@1646
|
841 |
buf.append(MethodHandleNatives.refKindName(refKind));
|
jaroslav@1646
|
842 |
}
|
jaroslav@1646
|
843 |
//buf.append("#").append(System.identityHashCode(this));
|
jaroslav@1646
|
844 |
return buf.toString();
|
jaroslav@1646
|
845 |
}
|
jaroslav@1646
|
846 |
private static String getName(Object obj) {
|
jaroslav@1646
|
847 |
if (obj instanceof Class<?>)
|
jaroslav@1646
|
848 |
return ((Class<?>)obj).getName();
|
jaroslav@1646
|
849 |
return String.valueOf(obj);
|
jaroslav@1646
|
850 |
}
|
jaroslav@1646
|
851 |
|
jaroslav@1646
|
852 |
public IllegalAccessException makeAccessException(String message, Object from) {
|
jaroslav@1646
|
853 |
message = message + ": "+ toString();
|
jaroslav@1646
|
854 |
if (from != null) message += ", from " + from;
|
jaroslav@1646
|
855 |
return new IllegalAccessException(message);
|
jaroslav@1646
|
856 |
}
|
jaroslav@1646
|
857 |
private String message() {
|
jaroslav@1646
|
858 |
if (isResolved())
|
jaroslav@1646
|
859 |
return "no access";
|
jaroslav@1646
|
860 |
else if (isConstructor())
|
jaroslav@1646
|
861 |
return "no such constructor";
|
jaroslav@1646
|
862 |
else if (isMethod())
|
jaroslav@1646
|
863 |
return "no such method";
|
jaroslav@1646
|
864 |
else
|
jaroslav@1646
|
865 |
return "no such field";
|
jaroslav@1646
|
866 |
}
|
jaroslav@1646
|
867 |
public ReflectiveOperationException makeAccessException() {
|
jaroslav@1646
|
868 |
String message = message() + ": "+ toString();
|
jaroslav@1646
|
869 |
ReflectiveOperationException ex;
|
jaroslav@1646
|
870 |
if (isResolved() || !(resolution instanceof NoSuchMethodError ||
|
jaroslav@1646
|
871 |
resolution instanceof NoSuchFieldError))
|
jaroslav@1646
|
872 |
ex = new IllegalAccessException(message);
|
jaroslav@1646
|
873 |
else if (isConstructor())
|
jaroslav@1646
|
874 |
ex = new NoSuchMethodException(message);
|
jaroslav@1646
|
875 |
else if (isMethod())
|
jaroslav@1646
|
876 |
ex = new NoSuchMethodException(message);
|
jaroslav@1646
|
877 |
else
|
jaroslav@1646
|
878 |
ex = new NoSuchFieldException(message);
|
jaroslav@1646
|
879 |
if (resolution instanceof Throwable)
|
jaroslav@1646
|
880 |
ex.initCause((Throwable) resolution);
|
jaroslav@1646
|
881 |
return ex;
|
jaroslav@1646
|
882 |
}
|
jaroslav@1646
|
883 |
|
jaroslav@1646
|
884 |
/** Actually making a query requires an access check. */
|
jaroslav@1646
|
885 |
/*non-public*/ static Factory getFactory() {
|
jaroslav@1646
|
886 |
return Factory.INSTANCE;
|
jaroslav@1646
|
887 |
}
|
jaroslav@1646
|
888 |
/** A factory type for resolving member names with the help of the VM.
|
jaroslav@1646
|
889 |
* TBD: Define access-safe public constructors for this factory.
|
jaroslav@1646
|
890 |
*/
|
jaroslav@1646
|
891 |
/*non-public*/ static class Factory {
|
jaroslav@1646
|
892 |
private Factory() { } // singleton pattern
|
jaroslav@1646
|
893 |
static Factory INSTANCE = new Factory();
|
jaroslav@1646
|
894 |
|
jaroslav@1646
|
895 |
private static int ALLOWED_FLAGS = ALL_KINDS;
|
jaroslav@1646
|
896 |
|
jaroslav@1646
|
897 |
/// Queries
|
jaroslav@1646
|
898 |
List<MemberName> getMembers(Class<?> defc,
|
jaroslav@1646
|
899 |
String matchName, Object matchType,
|
jaroslav@1646
|
900 |
int matchFlags, Class<?> lookupClass) {
|
jaroslav@1646
|
901 |
matchFlags &= ALLOWED_FLAGS;
|
jaroslav@1646
|
902 |
String matchSig = null;
|
jaroslav@1646
|
903 |
if (matchType != null) {
|
jaroslav@1646
|
904 |
matchSig = BytecodeDescriptor.unparse(matchType);
|
jaroslav@1646
|
905 |
if (matchSig.startsWith("("))
|
jaroslav@1646
|
906 |
matchFlags &= ~(ALL_KINDS & ~IS_INVOCABLE);
|
jaroslav@1646
|
907 |
else
|
jaroslav@1646
|
908 |
matchFlags &= ~(ALL_KINDS & ~IS_FIELD);
|
jaroslav@1646
|
909 |
}
|
jaroslav@1646
|
910 |
final int BUF_MAX = 0x2000;
|
jaroslav@1646
|
911 |
int len1 = matchName == null ? 10 : matchType == null ? 4 : 1;
|
jaroslav@1646
|
912 |
MemberName[] buf = newMemberBuffer(len1);
|
jaroslav@1646
|
913 |
int totalCount = 0;
|
jaroslav@1646
|
914 |
ArrayList<MemberName[]> bufs = null;
|
jaroslav@1646
|
915 |
int bufCount = 0;
|
jaroslav@1646
|
916 |
for (;;) {
|
jaroslav@1646
|
917 |
bufCount = MethodHandleNatives.getMembers(defc,
|
jaroslav@1646
|
918 |
matchName, matchSig, matchFlags,
|
jaroslav@1646
|
919 |
lookupClass,
|
jaroslav@1646
|
920 |
totalCount, buf);
|
jaroslav@1646
|
921 |
if (bufCount <= buf.length) {
|
jaroslav@1646
|
922 |
if (bufCount < 0) bufCount = 0;
|
jaroslav@1646
|
923 |
totalCount += bufCount;
|
jaroslav@1646
|
924 |
break;
|
jaroslav@1646
|
925 |
}
|
jaroslav@1646
|
926 |
// JVM returned to us with an intentional overflow!
|
jaroslav@1646
|
927 |
totalCount += buf.length;
|
jaroslav@1646
|
928 |
int excess = bufCount - buf.length;
|
jaroslav@1646
|
929 |
if (bufs == null) bufs = new ArrayList<>(1);
|
jaroslav@1646
|
930 |
bufs.add(buf);
|
jaroslav@1646
|
931 |
int len2 = buf.length;
|
jaroslav@1646
|
932 |
len2 = Math.max(len2, excess);
|
jaroslav@1646
|
933 |
len2 = Math.max(len2, totalCount / 4);
|
jaroslav@1646
|
934 |
buf = newMemberBuffer(Math.min(BUF_MAX, len2));
|
jaroslav@1646
|
935 |
}
|
jaroslav@1646
|
936 |
ArrayList<MemberName> result = new ArrayList<>(totalCount);
|
jaroslav@1646
|
937 |
if (bufs != null) {
|
jaroslav@1646
|
938 |
for (MemberName[] buf0 : bufs) {
|
jaroslav@1646
|
939 |
Collections.addAll(result, buf0);
|
jaroslav@1646
|
940 |
}
|
jaroslav@1646
|
941 |
}
|
jaroslav@1646
|
942 |
result.addAll(Arrays.asList(buf).subList(0, bufCount));
|
jaroslav@1646
|
943 |
// Signature matching is not the same as type matching, since
|
jaroslav@1646
|
944 |
// one signature might correspond to several types.
|
jaroslav@1646
|
945 |
// So if matchType is a Class or MethodType, refilter the results.
|
jaroslav@1646
|
946 |
if (matchType != null && matchType != matchSig) {
|
jaroslav@1646
|
947 |
for (Iterator<MemberName> it = result.iterator(); it.hasNext();) {
|
jaroslav@1646
|
948 |
MemberName m = it.next();
|
jaroslav@1646
|
949 |
if (!matchType.equals(m.getType()))
|
jaroslav@1646
|
950 |
it.remove();
|
jaroslav@1646
|
951 |
}
|
jaroslav@1646
|
952 |
}
|
jaroslav@1646
|
953 |
return result;
|
jaroslav@1646
|
954 |
}
|
jaroslav@1646
|
955 |
/** Produce a resolved version of the given member.
|
jaroslav@1646
|
956 |
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
jaroslav@1646
|
957 |
* Access checking is performed on behalf of the given {@code lookupClass}.
|
jaroslav@1646
|
958 |
* If lookup fails or access is not permitted, null is returned.
|
jaroslav@1646
|
959 |
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
|
jaroslav@1646
|
960 |
*/
|
jaroslav@1646
|
961 |
private MemberName resolve(byte refKind, MemberName ref, Class<?> lookupClass) {
|
jaroslav@1646
|
962 |
MemberName m = ref.clone(); // JVM will side-effect the ref
|
jaroslav@1646
|
963 |
assert(refKind == m.getReferenceKind());
|
jaroslav@1646
|
964 |
try {
|
jaroslav@1646
|
965 |
m = MethodHandleNatives.resolve(m, lookupClass);
|
jaroslav@1646
|
966 |
m.checkForTypeAlias();
|
jaroslav@1646
|
967 |
m.resolution = null;
|
jaroslav@1646
|
968 |
} catch (LinkageError ex) {
|
jaroslav@1646
|
969 |
// JVM reports that the "bytecode behavior" would get an error
|
jaroslav@1646
|
970 |
assert(!m.isResolved());
|
jaroslav@1646
|
971 |
m.resolution = ex;
|
jaroslav@1646
|
972 |
return m;
|
jaroslav@1646
|
973 |
}
|
jaroslav@1646
|
974 |
assert(m.referenceKindIsConsistent());
|
jaroslav@1646
|
975 |
m.initResolved(true);
|
jaroslav@1646
|
976 |
assert(m.vminfoIsConsistent());
|
jaroslav@1646
|
977 |
return m;
|
jaroslav@1646
|
978 |
}
|
jaroslav@1646
|
979 |
/** Produce a resolved version of the given member.
|
jaroslav@1646
|
980 |
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
jaroslav@1646
|
981 |
* Access checking is performed on behalf of the given {@code lookupClass}.
|
jaroslav@1646
|
982 |
* If lookup fails or access is not permitted, a {@linkplain ReflectiveOperationException} is thrown.
|
jaroslav@1646
|
983 |
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
|
jaroslav@1646
|
984 |
*/
|
jaroslav@1646
|
985 |
public
|
jaroslav@1646
|
986 |
<NoSuchMemberException extends ReflectiveOperationException>
|
jaroslav@1646
|
987 |
MemberName resolveOrFail(byte refKind, MemberName m, Class<?> lookupClass,
|
jaroslav@1646
|
988 |
Class<NoSuchMemberException> nsmClass)
|
jaroslav@1646
|
989 |
throws IllegalAccessException, NoSuchMemberException {
|
jaroslav@1646
|
990 |
MemberName result = resolve(refKind, m, lookupClass);
|
jaroslav@1646
|
991 |
if (result.isResolved())
|
jaroslav@1646
|
992 |
return result;
|
jaroslav@1646
|
993 |
ReflectiveOperationException ex = result.makeAccessException();
|
jaroslav@1646
|
994 |
if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex;
|
jaroslav@1646
|
995 |
throw nsmClass.cast(ex);
|
jaroslav@1646
|
996 |
}
|
jaroslav@1646
|
997 |
/** Produce a resolved version of the given member.
|
jaroslav@1646
|
998 |
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
jaroslav@1646
|
999 |
* Access checking is performed on behalf of the given {@code lookupClass}.
|
jaroslav@1646
|
1000 |
* If lookup fails or access is not permitted, return null.
|
jaroslav@1646
|
1001 |
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
|
jaroslav@1646
|
1002 |
*/
|
jaroslav@1646
|
1003 |
public
|
jaroslav@1646
|
1004 |
MemberName resolveOrNull(byte refKind, MemberName m, Class<?> lookupClass) {
|
jaroslav@1646
|
1005 |
MemberName result = resolve(refKind, m, lookupClass);
|
jaroslav@1646
|
1006 |
if (result.isResolved())
|
jaroslav@1646
|
1007 |
return result;
|
jaroslav@1646
|
1008 |
return null;
|
jaroslav@1646
|
1009 |
}
|
jaroslav@1646
|
1010 |
/** Return a list of all methods defined by the given class.
|
jaroslav@1646
|
1011 |
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
jaroslav@1646
|
1012 |
* Access checking is performed on behalf of the given {@code lookupClass}.
|
jaroslav@1646
|
1013 |
* Inaccessible members are not added to the last.
|
jaroslav@1646
|
1014 |
*/
|
jaroslav@1646
|
1015 |
public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
|
jaroslav@1646
|
1016 |
Class<?> lookupClass) {
|
jaroslav@1646
|
1017 |
return getMethods(defc, searchSupers, null, null, lookupClass);
|
jaroslav@1646
|
1018 |
}
|
jaroslav@1646
|
1019 |
/** Return a list of matching methods defined by the given class.
|
jaroslav@1646
|
1020 |
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
jaroslav@1646
|
1021 |
* Returned methods will match the name (if not null) and the type (if not null).
|
jaroslav@1646
|
1022 |
* Access checking is performed on behalf of the given {@code lookupClass}.
|
jaroslav@1646
|
1023 |
* Inaccessible members are not added to the last.
|
jaroslav@1646
|
1024 |
*/
|
jaroslav@1646
|
1025 |
public List<MemberName> getMethods(Class<?> defc, boolean searchSupers,
|
jaroslav@1646
|
1026 |
String name, MethodType type, Class<?> lookupClass) {
|
jaroslav@1646
|
1027 |
int matchFlags = IS_METHOD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
|
jaroslav@1646
|
1028 |
return getMembers(defc, name, type, matchFlags, lookupClass);
|
jaroslav@1646
|
1029 |
}
|
jaroslav@1646
|
1030 |
/** Return a list of all constructors defined by the given class.
|
jaroslav@1646
|
1031 |
* Access checking is performed on behalf of the given {@code lookupClass}.
|
jaroslav@1646
|
1032 |
* Inaccessible members are not added to the last.
|
jaroslav@1646
|
1033 |
*/
|
jaroslav@1646
|
1034 |
public List<MemberName> getConstructors(Class<?> defc, Class<?> lookupClass) {
|
jaroslav@1646
|
1035 |
return getMembers(defc, null, null, IS_CONSTRUCTOR, lookupClass);
|
jaroslav@1646
|
1036 |
}
|
jaroslav@1646
|
1037 |
/** Return a list of all fields defined by the given class.
|
jaroslav@1646
|
1038 |
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
jaroslav@1646
|
1039 |
* Access checking is performed on behalf of the given {@code lookupClass}.
|
jaroslav@1646
|
1040 |
* Inaccessible members are not added to the last.
|
jaroslav@1646
|
1041 |
*/
|
jaroslav@1646
|
1042 |
public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
|
jaroslav@1646
|
1043 |
Class<?> lookupClass) {
|
jaroslav@1646
|
1044 |
return getFields(defc, searchSupers, null, null, lookupClass);
|
jaroslav@1646
|
1045 |
}
|
jaroslav@1646
|
1046 |
/** Return a list of all fields defined by the given class.
|
jaroslav@1646
|
1047 |
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
jaroslav@1646
|
1048 |
* Returned fields will match the name (if not null) and the type (if not null).
|
jaroslav@1646
|
1049 |
* Access checking is performed on behalf of the given {@code lookupClass}.
|
jaroslav@1646
|
1050 |
* Inaccessible members are not added to the last.
|
jaroslav@1646
|
1051 |
*/
|
jaroslav@1646
|
1052 |
public List<MemberName> getFields(Class<?> defc, boolean searchSupers,
|
jaroslav@1646
|
1053 |
String name, Class<?> type, Class<?> lookupClass) {
|
jaroslav@1646
|
1054 |
int matchFlags = IS_FIELD | (searchSupers ? SEARCH_ALL_SUPERS : 0);
|
jaroslav@1646
|
1055 |
return getMembers(defc, name, type, matchFlags, lookupClass);
|
jaroslav@1646
|
1056 |
}
|
jaroslav@1646
|
1057 |
/** Return a list of all nested types defined by the given class.
|
jaroslav@1646
|
1058 |
* Super types are searched (for inherited members) if {@code searchSupers} is true.
|
jaroslav@1646
|
1059 |
* Access checking is performed on behalf of the given {@code lookupClass}.
|
jaroslav@1646
|
1060 |
* Inaccessible members are not added to the last.
|
jaroslav@1646
|
1061 |
*/
|
jaroslav@1646
|
1062 |
public List<MemberName> getNestedTypes(Class<?> defc, boolean searchSupers,
|
jaroslav@1646
|
1063 |
Class<?> lookupClass) {
|
jaroslav@1646
|
1064 |
int matchFlags = IS_TYPE | (searchSupers ? SEARCH_ALL_SUPERS : 0);
|
jaroslav@1646
|
1065 |
return getMembers(defc, null, null, matchFlags, lookupClass);
|
jaroslav@1646
|
1066 |
}
|
jaroslav@1646
|
1067 |
private static MemberName[] newMemberBuffer(int length) {
|
jaroslav@1646
|
1068 |
MemberName[] buf = new MemberName[length];
|
jaroslav@1646
|
1069 |
// fill the buffer with dummy structs for the JVM to fill in
|
jaroslav@1646
|
1070 |
for (int i = 0; i < length; i++)
|
jaroslav@1646
|
1071 |
buf[i] = new MemberName();
|
jaroslav@1646
|
1072 |
return buf;
|
jaroslav@1646
|
1073 |
}
|
jaroslav@1646
|
1074 |
}
|
jaroslav@1646
|
1075 |
|
jaroslav@1646
|
1076 |
// static {
|
jaroslav@1646
|
1077 |
// System.out.println("Hello world! My methods are:");
|
jaroslav@1646
|
1078 |
// System.out.println(Factory.INSTANCE.getMethods(MemberName.class, true, null));
|
jaroslav@1646
|
1079 |
// }
|
jaroslav@1646
|
1080 |
}
|