Batch of classes necessary to implement invoke dynamic interfaces. Taken from JDK8 build 132
2 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
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).
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.
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
26 package java.lang.invoke;
28 import java.security.AccessController;
29 import java.security.PrivilegedAction;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.HashMap;
33 import sun.invoke.empty.Empty;
34 import sun.invoke.util.ValueConversions;
35 import sun.invoke.util.VerifyType;
36 import sun.invoke.util.Wrapper;
37 import sun.reflect.CallerSensitive;
38 import sun.reflect.Reflection;
39 import static java.lang.invoke.LambdaForm.*;
40 import static java.lang.invoke.MethodHandleStatics.*;
41 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
44 * Trusted implementation code for MethodHandle.
47 /*non-public*/ abstract class MethodHandleImpl {
48 /// Factory methods to create method handles:
50 static void initStatics() {
51 // Trigger selected static initializations.
52 MemberName.Factory.INSTANCE.getClass();
55 static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
56 if (!arrayClass.isArray())
57 throw newIllegalArgumentException("not an array: "+arrayClass);
58 MethodHandle accessor = ArrayAccessor.getAccessor(arrayClass, isSetter);
59 MethodType srcType = accessor.type().erase();
60 MethodType lambdaType = srcType.invokerType();
61 Name[] names = arguments(1, lambdaType);
62 Name[] args = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount());
63 names[names.length - 1] = new Name(accessor.asType(srcType), (Object[]) args);
64 LambdaForm form = new LambdaForm("getElement", lambdaType.parameterCount(), names);
65 MethodHandle mh = SimpleMethodHandle.make(srcType, form);
66 if (ArrayAccessor.needCast(arrayClass)) {
67 mh = mh.bindTo(arrayClass);
69 mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter));
73 static final class ArrayAccessor {
74 /// Support for array element access
75 static final HashMap<Class<?>, MethodHandle> GETTER_CACHE = new HashMap<>(); // TODO use it
76 static final HashMap<Class<?>, MethodHandle> SETTER_CACHE = new HashMap<>(); // TODO use it
78 static int getElementI(int[] a, int i) { return a[i]; }
79 static long getElementJ(long[] a, int i) { return a[i]; }
80 static float getElementF(float[] a, int i) { return a[i]; }
81 static double getElementD(double[] a, int i) { return a[i]; }
82 static boolean getElementZ(boolean[] a, int i) { return a[i]; }
83 static byte getElementB(byte[] a, int i) { return a[i]; }
84 static short getElementS(short[] a, int i) { return a[i]; }
85 static char getElementC(char[] a, int i) { return a[i]; }
86 static Object getElementL(Object[] a, int i) { return a[i]; }
88 static void setElementI(int[] a, int i, int x) { a[i] = x; }
89 static void setElementJ(long[] a, int i, long x) { a[i] = x; }
90 static void setElementF(float[] a, int i, float x) { a[i] = x; }
91 static void setElementD(double[] a, int i, double x) { a[i] = x; }
92 static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
93 static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
94 static void setElementS(short[] a, int i, short x) { a[i] = x; }
95 static void setElementC(char[] a, int i, char x) { a[i] = x; }
96 static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
98 static Object getElementL(Class<?> arrayClass, Object[] a, int i) { arrayClass.cast(a); return a[i]; }
99 static void setElementL(Class<?> arrayClass, Object[] a, int i, Object x) { arrayClass.cast(a); a[i] = x; }
101 // Weakly typed wrappers of Object[] accessors:
102 static Object getElementL(Object a, int i) { return getElementL((Object[])a, i); }
103 static void setElementL(Object a, int i, Object x) { setElementL((Object[]) a, i, x); }
104 static Object getElementL(Object arrayClass, Object a, int i) { return getElementL((Class<?>) arrayClass, (Object[])a, i); }
105 static void setElementL(Object arrayClass, Object a, int i, Object x) { setElementL((Class<?>) arrayClass, (Object[])a, i, x); }
107 static boolean needCast(Class<?> arrayClass) {
108 Class<?> elemClass = arrayClass.getComponentType();
109 return !elemClass.isPrimitive() && elemClass != Object.class;
111 static String name(Class<?> arrayClass, boolean isSetter) {
112 Class<?> elemClass = arrayClass.getComponentType();
113 if (elemClass == null) throw new IllegalArgumentException();
114 return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
116 static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false; // FIXME: decide
117 static MethodType type(Class<?> arrayClass, boolean isSetter) {
118 Class<?> elemClass = arrayClass.getComponentType();
119 Class<?> arrayArgClass = arrayClass;
120 if (!elemClass.isPrimitive()) {
121 arrayArgClass = Object[].class;
122 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
123 arrayArgClass = Object.class;
125 if (!needCast(arrayClass)) {
127 MethodType.methodType(elemClass, arrayArgClass, int.class) :
128 MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
130 Class<?> classArgClass = Class.class;
131 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
132 classArgClass = Object.class;
134 MethodType.methodType(Object.class, classArgClass, arrayArgClass, int.class) :
135 MethodType.methodType(void.class, classArgClass, arrayArgClass, int.class, Object.class);
138 static MethodType correctType(Class<?> arrayClass, boolean isSetter) {
139 Class<?> elemClass = arrayClass.getComponentType();
141 MethodType.methodType(elemClass, arrayClass, int.class) :
142 MethodType.methodType(void.class, arrayClass, int.class, elemClass);
144 static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
145 String name = name(arrayClass, isSetter);
146 MethodType type = type(arrayClass, isSetter);
148 return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
149 } catch (ReflectiveOperationException ex) {
150 throw uncaughtException(ex);
156 * Create a JVM-level adapter method handle to conform the given method
157 * handle to the similar newType, using only pairwise argument conversions.
158 * For each argument, convert incoming argument to the exact type needed.
159 * The argument conversions allowed are casting, boxing and unboxing,
160 * integral widening or narrowing, and floating point widening or narrowing.
161 * @param srcType required call type
162 * @param target original method handle
163 * @param level which strength of conversion is allowed
164 * @return an adapter to the original handle with the desired new type,
165 * or the original target if the types are already identical
166 * or null if the adaptation cannot be made
168 static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
169 assert(level >= 0 && level <= 2);
170 MethodType dstType = target.type();
171 assert(dstType.parameterCount() == target.type().parameterCount());
172 if (srcType == dstType)
175 // Calculate extra arguments (temporaries) required in the names array.
176 // FIXME: Use an ArrayList<Name>. Some arguments require more than one conversion step.
177 final int INARG_COUNT = srcType.parameterCount();
179 boolean[] needConv = new boolean[1+INARG_COUNT];
180 for (int i = 0; i <= INARG_COUNT; i++) {
181 Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
182 Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
183 if (!VerifyType.isNullConversion(src, dst) ||
184 level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
189 boolean retConv = needConv[INARG_COUNT];
192 final int INARG_BASE = 1;
193 final int INARG_LIMIT = INARG_BASE + INARG_COUNT;
194 final int NAME_LIMIT = INARG_LIMIT + conversions + 1;
195 final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1);
196 final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
198 // Now build a LambdaForm.
199 MethodType lambdaType = srcType.basicType().invokerType();
200 Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
202 // Collect the arguments to the outgoing call, maybe with conversions:
203 final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0]
204 Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
206 int nameCursor = INARG_LIMIT;
207 for (int i = 0; i < INARG_COUNT; i++) {
208 Class<?> src = srcType.parameterType(i);
209 Class<?> dst = dstType.parameterType(i);
212 // do nothing: difference is trivial
213 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
217 // Tricky case analysis follows.
218 MethodHandle fn = null;
219 if (src.isPrimitive()) {
220 if (dst.isPrimitive()) {
221 fn = ValueConversions.convertPrimitive(src, dst);
223 Wrapper w = Wrapper.forPrimitiveType(src);
224 MethodHandle boxMethod = ValueConversions.box(w);
225 if (dst == w.wrapperType())
228 fn = boxMethod.asType(MethodType.methodType(dst, src));
231 if (dst.isPrimitive()) {
232 // Caller has boxed a primitive. Unbox it for the target.
233 Wrapper w = Wrapper.forPrimitiveType(dst);
234 if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType())) {
235 fn = ValueConversions.unbox(dst);
236 } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
237 // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
238 // must include additional conversions
239 // src must be examined at runtime, to detect Byte, Character, etc.
240 MethodHandle unboxMethod = (level == 1
241 ? ValueConversions.unbox(dst)
242 : ValueConversions.unboxCast(dst));
245 // Example: Byte->int
246 // Do this by reformulating the problem to Byte->byte.
247 Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
248 MethodHandle unbox = ValueConversions.unbox(srcPrim);
249 // Compose the two conversions. FIXME: should make two Names for this job
250 fn = unbox.asType(MethodType.methodType(dst, src));
253 // Simple reference conversion.
254 // Note: Do not check for a class hierarchy relation
255 // between src and dst. In all cases a 'null' argument
256 // will pass the cast conversion.
257 fn = ValueConversions.cast(dst);
260 Name conv = new Name(fn, names[INARG_BASE + i]);
261 assert(names[nameCursor] == null);
262 names[nameCursor++] = conv;
263 assert(outArgs[OUTARG_BASE + i] == null);
264 outArgs[OUTARG_BASE + i] = conv;
267 // Build argument array for the call.
268 assert(nameCursor == OUT_CALL);
269 names[OUT_CALL] = new Name(target, outArgs);
271 if (RETURN_CONV < 0) {
272 assert(OUT_CALL == names.length-1);
274 Class<?> needReturn = srcType.returnType();
275 Class<?> haveReturn = dstType.returnType();
277 Object[] arg = { names[OUT_CALL] };
278 if (haveReturn == void.class) {
279 // synthesize a zero value for the given void
280 Object zero = Wrapper.forBasicType(needReturn).zero();
281 fn = MethodHandles.constant(needReturn, zero);
282 arg = new Object[0]; // don't pass names[OUT_CALL] to conversion
284 MethodHandle identity = MethodHandles.identity(needReturn);
285 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
286 fn = makePairwiseConvert(identity, needConversion, level);
288 assert(names[RETURN_CONV] == null);
289 names[RETURN_CONV] = new Name(fn, arg);
290 assert(RETURN_CONV == names.length-1);
293 LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names);
294 return SimpleMethodHandle.make(srcType, form);
297 static MethodHandle makeReferenceIdentity(Class<?> refType) {
298 MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
299 Name[] names = arguments(1, lambdaType);
300 names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
301 LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
302 return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
305 static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
306 MethodType type = target.type();
307 int last = type.parameterCount() - 1;
308 if (type.parameterType(last) != arrayType)
309 target = target.asType(type.changeParameterType(last, arrayType));
310 target = target.asFixedArity(); // make sure this attribute is turned off
311 return new AsVarargsCollector(target, target.type(), arrayType);
314 static class AsVarargsCollector extends MethodHandle {
315 private final MethodHandle target;
316 private final Class<?> arrayType;
317 private /*@Stable*/ MethodHandle asCollectorCache;
319 AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
320 super(type, reinvokerForm(target));
321 this.target = target;
322 this.arrayType = arrayType;
323 this.asCollectorCache = target.asCollector(arrayType, 0);
326 @Override MethodHandle reinvokerTarget() { return target; }
329 public boolean isVarargsCollector() {
334 public MethodHandle asFixedArity() {
339 public MethodHandle asTypeUncached(MethodType newType) {
340 MethodType type = this.type();
341 int collectArg = type.parameterCount() - 1;
342 int newArity = newType.parameterCount();
343 if (newArity == collectArg+1 &&
344 type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
345 // if arity and trailing parameter are compatible, do normal thing
346 return asTypeCache = asFixedArity().asType(newType);
349 MethodHandle acc = asCollectorCache;
350 if (acc != null && acc.type().parameterCount() == newArity)
351 return asTypeCache = acc.asType(newType);
352 // build and cache a collector
353 int arrayLength = newArity - collectArg;
354 MethodHandle collector;
356 collector = asFixedArity().asCollector(arrayType, arrayLength);
357 assert(collector.type().parameterCount() == newArity) : "newArity="+newArity+" but collector="+collector;
358 } catch (IllegalArgumentException ex) {
359 throw new WrongMethodTypeException("cannot build collector", ex);
361 asCollectorCache = collector;
362 return asTypeCache = collector.asType(newType);
366 MethodHandle setVarargs(MemberName member) {
367 if (member.isVarargs()) return this;
368 return asFixedArity();
372 MethodHandle viewAsType(MethodType newType) {
373 if (newType.lastParameterType() != type().lastParameterType())
374 throw new InternalError();
375 MethodHandle newTarget = asFixedArity().viewAsType(newType);
376 // put back the varargs bit:
377 return new AsVarargsCollector(newTarget, newType, arrayType);
381 MemberName internalMemberName() {
382 return asFixedArity().internalMemberName();
385 Class<?> internalCallerClass() {
386 return asFixedArity().internalCallerClass();
391 boolean isInvokeSpecial() {
392 return asFixedArity().isInvokeSpecial();
397 MethodHandle bindArgument(int pos, char basicType, Object value) {
398 return asFixedArity().bindArgument(pos, basicType, value);
402 MethodHandle bindReceiver(Object receiver) {
403 return asFixedArity().bindReceiver(receiver);
407 MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
408 return asFixedArity().dropArguments(srcType, pos, drops);
412 MethodHandle permuteArguments(MethodType newType, int[] reorder) {
413 return asFixedArity().permuteArguments(newType, reorder);
417 /** Factory method: Spread selected argument. */
418 static MethodHandle makeSpreadArguments(MethodHandle target,
419 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
420 MethodType targetType = target.type();
422 for (int i = 0; i < spreadArgCount; i++) {
423 Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i);
424 if (arg == null) arg = Object.class;
425 targetType = targetType.changeParameterType(spreadArgPos + i, arg);
427 target = target.asType(targetType);
429 MethodType srcType = targetType
430 .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType);
431 // Now build a LambdaForm.
432 MethodType lambdaType = srcType.invokerType();
433 Name[] names = arguments(spreadArgCount + 2, lambdaType);
434 int nameCursor = lambdaType.parameterCount();
435 int[] indexes = new int[targetType.parameterCount()];
437 for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) {
438 Class<?> src = lambdaType.parameterType(i);
439 if (i == spreadArgPos) {
441 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
442 Name array = names[argIndex];
443 names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount);
444 for (int j = 0; j < spreadArgCount; i++, j++) {
445 indexes[i] = nameCursor;
446 names[nameCursor++] = new Name(aload, array, j);
448 } else if (i < indexes.length) {
449 indexes[i] = argIndex;
452 assert(nameCursor == names.length-1); // leave room for the final call
454 // Build argument array for the call.
455 Name[] targetArgs = new Name[targetType.parameterCount()];
456 for (int i = 0; i < targetType.parameterCount(); i++) {
457 int idx = indexes[i];
458 targetArgs[i] = names[idx];
460 names[names.length - 1] = new Name(target, (Object[]) targetArgs);
462 LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names);
463 return SimpleMethodHandle.make(srcType, form);
466 static void checkSpreadArgument(Object av, int n) {
469 } else if (av instanceof Object[]) {
470 int len = ((Object[])av).length;
471 if (len == n) return;
473 int len = java.lang.reflect.Array.getLength(av);
474 if (len == n) return;
476 // fall through to error:
477 throw newIllegalArgumentException("array is not of length "+n);
481 * Pre-initialized NamedFunctions for bootstrapping purposes.
482 * Factored in an inner class to delay initialization until first usage.
484 private static class Lazy {
485 static final NamedFunction NF_checkSpreadArgument;
488 NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
489 .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
490 NF_checkSpreadArgument.resolve();
491 } catch (ReflectiveOperationException ex) {
492 throw newInternalError(ex);
497 /** Factory method: Collect or filter selected argument(s). */
498 static MethodHandle makeCollectArguments(MethodHandle target,
499 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
500 MethodType targetType = target.type(); // (a..., c, [b...])=>r
501 MethodType collectorType = collector.type(); // (b...)=>c
502 int collectArgCount = collectorType.parameterCount();
503 Class<?> collectValType = collectorType.returnType();
504 int collectValCount = (collectValType == void.class ? 0 : 1);
505 MethodType srcType = targetType // (a..., [b...])=>r
506 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
507 if (!retainOriginalArgs) { // (a..., b...)=>r
508 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
510 // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ]
511 // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
512 // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
514 // Now build a LambdaForm.
515 MethodType lambdaType = srcType.invokerType();
516 Name[] names = arguments(2, lambdaType);
517 final int collectNamePos = names.length - 2;
518 final int targetNamePos = names.length - 1;
520 Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount);
521 names[collectNamePos] = new Name(collector, (Object[]) collectorArgs);
523 // Build argument array for the target.
524 // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ].
525 // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ].
526 Name[] targetArgs = new Name[targetType.parameterCount()];
527 int inputArgPos = 1; // incoming LF args to copy to target
528 int targetArgPos = 0; // fill pointer for targetArgs
529 int chunk = collectArgPos; // |headArgs|
530 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
531 inputArgPos += chunk;
532 targetArgPos += chunk;
533 if (collectValType != void.class) {
534 targetArgs[targetArgPos++] = names[collectNamePos];
536 chunk = collectArgCount;
537 if (retainOriginalArgs) {
538 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
539 targetArgPos += chunk; // optionally pass on the collected chunk
541 inputArgPos += chunk;
542 chunk = targetArgs.length - targetArgPos; // all the rest
543 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
544 assert(inputArgPos + chunk == collectNamePos); // use of rest of input args also
545 names[targetNamePos] = new Name(target, (Object[]) targetArgs);
547 LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names);
548 return SimpleMethodHandle.make(srcType, form);
552 MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
553 return testResult ? target : fallback;
556 static MethodHandle SELECT_ALTERNATIVE;
557 static MethodHandle selectAlternative() {
558 if (SELECT_ALTERNATIVE != null) return SELECT_ALTERNATIVE;
561 = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
562 MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
563 } catch (ReflectiveOperationException ex) {
564 throw new RuntimeException(ex);
566 return SELECT_ALTERNATIVE;
570 MethodHandle makeGuardWithTest(MethodHandle test,
572 MethodHandle fallback) {
573 MethodType basicType = target.type().basicType();
574 MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType);
575 int arity = basicType.parameterCount();
577 MethodType lambdaType = basicType.invokerType();
578 Name[] names = arguments(extraNames, lambdaType);
580 Object[] testArgs = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class);
581 Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class);
584 names[arity + 1] = new Name(test, testArgs);
586 // call selectAlternative
587 Object[] selectArgs = { names[arity + 1], target, fallback };
588 names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs);
589 targetArgs[0] = names[arity + 2];
591 // call target or fallback
592 names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
594 LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
595 return SimpleMethodHandle.make(target.type(), form);
598 private static class GuardWithCatch {
599 private final MethodHandle target;
600 private final Class<? extends Throwable> exType;
601 private final MethodHandle catcher;
602 // FIXME: Build the control flow out of foldArguments.
603 GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
604 this.target = target;
605 this.exType = exType;
606 this.catcher = catcher;
609 private Object invoke_V(Object... av) throws Throwable {
611 return target.invokeExact(av);
612 } catch (Throwable t) {
613 if (!exType.isInstance(t)) throw t;
614 return catcher.invokeExact(t, av);
618 private Object invoke_L0() throws Throwable {
620 return target.invokeExact();
621 } catch (Throwable t) {
622 if (!exType.isInstance(t)) throw t;
623 return catcher.invokeExact(t);
627 private Object invoke_L1(Object a0) throws Throwable {
629 return target.invokeExact(a0);
630 } catch (Throwable t) {
631 if (!exType.isInstance(t)) throw t;
632 return catcher.invokeExact(t, a0);
636 private Object invoke_L2(Object a0, Object a1) throws Throwable {
638 return target.invokeExact(a0, a1);
639 } catch (Throwable t) {
640 if (!exType.isInstance(t)) throw t;
641 return catcher.invokeExact(t, a0, a1);
645 private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
647 return target.invokeExact(a0, a1, a2);
648 } catch (Throwable t) {
649 if (!exType.isInstance(t)) throw t;
650 return catcher.invokeExact(t, a0, a1, a2);
654 private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
656 return target.invokeExact(a0, a1, a2, a3);
657 } catch (Throwable t) {
658 if (!exType.isInstance(t)) throw t;
659 return catcher.invokeExact(t, a0, a1, a2, a3);
663 private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
665 return target.invokeExact(a0, a1, a2, a3, a4);
666 } catch (Throwable t) {
667 if (!exType.isInstance(t)) throw t;
668 return catcher.invokeExact(t, a0, a1, a2, a3, a4);
672 private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
674 return target.invokeExact(a0, a1, a2, a3, a4, a5);
675 } catch (Throwable t) {
676 if (!exType.isInstance(t)) throw t;
677 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
681 private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
683 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
684 } catch (Throwable t) {
685 if (!exType.isInstance(t)) throw t;
686 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
690 private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
692 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
693 } catch (Throwable t) {
694 if (!exType.isInstance(t)) throw t;
695 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
698 static MethodHandle[] makeInvokes() {
699 ArrayList<MethodHandle> invokes = new ArrayList<>();
700 MethodHandles.Lookup lookup = IMPL_LOOKUP;
702 int nargs = invokes.size();
703 String name = "invoke_L"+nargs;
704 MethodHandle invoke = null;
706 invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs));
707 } catch (ReflectiveOperationException ex) {
709 if (invoke == null) break;
712 assert(invokes.size() == 9); // current number of methods
713 return invokes.toArray(new MethodHandle[0]);
715 static final MethodHandle[] INVOKES = makeInvokes();
716 // For testing use this:
717 //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
718 static final MethodHandle VARARGS_INVOKE;
721 VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
722 } catch (ReflectiveOperationException ex) {
723 throw uncaughtException(ex);
730 MethodHandle makeGuardWithCatch(MethodHandle target,
731 Class<? extends Throwable> exType,
732 MethodHandle catcher) {
733 MethodType type = target.type();
734 MethodType ctype = catcher.type();
735 int nargs = type.parameterCount();
736 if (nargs < GuardWithCatch.INVOKES.length) {
737 MethodType gtype = type.generic();
738 MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
739 // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
740 MethodHandle gtarget = makePairwiseConvert(target, gtype, 2);
741 MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2);
742 GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
743 if (gtarget == null || gcatcher == null) throw new InternalError();
744 MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard);
745 return makePairwiseConvert(ginvoker, type, 2);
747 target = target.asType(type.changeReturnType(Object.class));
748 MethodHandle gtarget = makeSpreadArguments(target, Object[].class, 0, nargs);
749 MethodType catcherType = ctype.changeParameterType(0, Throwable.class)
750 .changeReturnType(Object.class);
751 catcher = catcher.asType(catcherType);
752 MethodHandle gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs);
753 GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
754 if (gtarget == null || gcatcher == null) throw new InternalError();
755 MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard);
756 MethodHandle gcollect = makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false);
757 return makePairwiseConvert(gcollect, type, 2);
762 MethodHandle throwException(MethodType type) {
763 assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
764 int arity = type.parameterCount();
766 return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
768 return makePairwiseConvert(throwException(), type, 2);
771 static MethodHandle THROW_EXCEPTION;
772 static MethodHandle throwException() {
773 MethodHandle mh = THROW_EXCEPTION;
774 if (mh != null) return mh;
777 = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
778 MethodType.methodType(Empty.class, Throwable.class));
779 } catch (ReflectiveOperationException ex) {
780 throw new RuntimeException(ex);
782 THROW_EXCEPTION = mh;
785 static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
787 static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
788 static MethodHandle fakeMethodHandleInvoke(MemberName method) {
790 assert(method.isMethodHandleInvoke());
791 switch (method.getName()) {
792 case "invoke": idx = 0; break;
793 case "invokeExact": idx = 1; break;
794 default: throw new InternalError(method.getName());
796 MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
797 if (mh != null) return mh;
798 MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
799 MethodHandle.class, Object[].class);
800 mh = throwException(type);
801 mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
802 if (!method.getInvocationType().equals(mh.type()))
803 throw new InternalError(method.toString());
804 mh = mh.withInternalMemberName(method);
805 mh = mh.asVarargsCollector(Object[].class);
806 assert(method.isVarargs());
807 FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
812 * Create an alias for the method handle which, when called,
813 * appears to be called from the same class loader and protection domain
815 * This is an expensive no-op unless the method which is called
816 * is sensitive to its caller. A small number of system methods
817 * are in this category, including Class.forName and Method.invoke.
820 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
821 return BindCaller.bindCaller(mh, hostClass);
824 // Put the whole mess into its own nested class.
825 // That way we can lazily load the code and set up the constants.
826 private static class BindCaller {
828 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
829 // Do not use this function to inject calls into system classes.
830 if (hostClass == null
831 || (hostClass.isArray() ||
832 hostClass.isPrimitive() ||
833 hostClass.getName().startsWith("java.") ||
834 hostClass.getName().startsWith("sun."))) {
835 throw new InternalError(); // does not happen, and should not anyway
837 // For simplicity, convert mh to a varargs-like method.
838 MethodHandle vamh = prepareForInvoker(mh);
839 // Cache the result of makeInjectedInvoker once per argument class.
840 MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
841 return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass);
844 private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
845 Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null);
846 if (hostClass.getClassLoader() != bcc.getClassLoader())
847 throw new InternalError(hostClass.getName()+" (CL)");
849 if (hostClass.getProtectionDomain() != bcc.getProtectionDomain())
850 throw new InternalError(hostClass.getName()+" (PD)");
851 } catch (SecurityException ex) {
852 // Self-check was blocked by security manager. This is OK.
853 // In fact the whole try body could be turned into an assertion.
856 MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class));
857 init.invokeExact(); // force initialization of the class
858 } catch (Throwable ex) {
859 throw uncaughtException(ex);
861 MethodHandle bccInvoker;
863 MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
864 bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT);
865 } catch (ReflectiveOperationException ex) {
866 throw uncaughtException(ex);
868 // Test the invoker, to ensure that it really injects into the right place.
870 MethodHandle vamh = prepareForInvoker(MH_checkCallerClass);
871 Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc});
872 } catch (Throwable ex) {
873 throw new InternalError(ex);
877 private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() {
878 @Override protected MethodHandle computeValue(Class<?> hostClass) {
879 return makeInjectedInvoker(hostClass);
883 // Adapt mh so that it can be called directly from an injected invoker:
884 private static MethodHandle prepareForInvoker(MethodHandle mh) {
885 mh = mh.asFixedArity();
886 MethodType mt = mh.type();
887 int arity = mt.parameterCount();
888 MethodHandle vamh = mh.asType(mt.generic());
889 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames
890 vamh = vamh.asSpreader(Object[].class, arity);
891 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames
895 // Undo the adapter effect of prepareForInvoker:
896 private static MethodHandle restoreToType(MethodHandle vamh, MethodType type,
898 Class<?> hostClass) {
899 MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
900 mh = mh.asType(type);
901 mh = new WrappedMember(mh, type, member, hostClass);
905 private static final MethodHandle MH_checkCallerClass;
907 final Class<?> THIS_CLASS = BindCaller.class;
908 assert(checkCallerClass(THIS_CLASS, THIS_CLASS));
910 MH_checkCallerClass = IMPL_LOOKUP
911 .findStatic(THIS_CLASS, "checkCallerClass",
912 MethodType.methodType(boolean.class, Class.class, Class.class));
913 assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS));
914 } catch (Throwable ex) {
915 throw new InternalError(ex);
920 private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) {
921 // This method is called via MH_checkCallerClass and so it's
922 // correct to ask for the immediate caller here.
923 Class<?> actual = Reflection.getCallerClass();
924 if (actual != expected && actual != expected2)
925 throw new InternalError("found "+actual.getName()+", expected "+expected.getName()
926 +(expected == expected2 ? "" : ", or else "+expected2.getName()));
930 private static final byte[] T_BYTES;
932 final Object[] values = {null};
933 AccessController.doPrivileged(new PrivilegedAction<Void>() {
936 Class<T> tClass = T.class;
937 String tName = tClass.getName();
938 String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class";
939 java.net.URLConnection uconn = tClass.getResource(tResource).openConnection();
940 int len = uconn.getContentLength();
941 byte[] bytes = new byte[len];
942 try (java.io.InputStream str = uconn.getInputStream()) {
943 int nr = str.read(bytes);
944 if (nr != len) throw new java.io.IOException(tResource);
947 } catch (java.io.IOException ex) {
948 throw new InternalError(ex);
953 T_BYTES = (byte[]) values[0];
956 // The following class is used as a template for Unsafe.defineAnonymousClass:
957 private static class T {
958 static void init() { } // side effect: initializes this class
959 static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable {
960 return vamh.invokeExact(args);
966 /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
967 static class WrappedMember extends MethodHandle {
968 private final MethodHandle target;
969 private final MemberName member;
970 private final Class<?> callerClass;
972 private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) {
973 super(type, reinvokerForm(target));
974 this.target = target;
975 this.member = member;
976 this.callerClass = callerClass;
980 MethodHandle reinvokerTarget() {
984 public MethodHandle asTypeUncached(MethodType newType) {
985 // This MH is an alias for target, except for the MemberName
986 // Drop the MemberName if there is any conversion.
987 return asTypeCache = target.asType(newType);
990 MemberName internalMemberName() {
994 Class<?> internalCallerClass() {
998 boolean isInvokeSpecial() {
999 return target.isInvokeSpecial();
1002 MethodHandle viewAsType(MethodType newType) {
1003 return new WrappedMember(target, newType, member, callerClass);
1007 static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
1008 if (member.equals(target.internalMemberName()))
1010 return new WrappedMember(target, target.type(), member, null);