2
* Copyright (c) 2008, 2011, 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
27
* Extensively modified for IKVM.NET by Jeroen Frijters
28
* Copyright (C) 2011 Jeroen Frijters
31
package java.lang.invoke;
33
import sun.invoke.util.VerifyType;
34
import java.security.AccessController;
35
import java.security.PrivilegedAction;
36
import java.util.ArrayList;
37
import java.util.Arrays;
38
import java.util.Collections;
39
import java.util.HashMap;
40
import java.util.List;
41
import sun.invoke.empty.Empty;
42
import sun.invoke.util.ValueConversions;
43
import sun.invoke.util.Wrapper;
44
import sun.misc.Unsafe;
45
import static java.lang.invoke.MethodHandleStatics.*;
46
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
49
* Trusted implementation code for MethodHandle.
52
/*non-public*/ abstract class MethodHandleImpl {
53
/// Factory methods to create method handles:
55
private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
57
static void initStatics() {
58
// Trigger preceding sequence.
61
/** Look up a given method.
62
* Callable only from sun.invoke and related packages.
64
* The resulting method handle type will be of the given type,
65
* with a receiver type {@code rcvc} prepended if the member is not static.
67
* Access checks are made as of the given lookup class.
68
* In particular, if the method is protected and {@code defc} is in a
69
* different package from the lookup class, then {@code rcvc} must be
70
* the lookup class or a subclass.
71
* @param token Proof that the lookup class has access to this package.
72
* @param member Resolved method or constructor to call.
73
* @param name Name of the desired method.
74
* @param rcvc Receiver type of desired non-static method (else null)
75
* @param doDispatch whether the method handle will test the receiver type
76
* @param lookupClass access-check relative to this class
77
* @return a direct handle to the matching method
78
* @throws IllegalAccessException if the given method cannot be accessed by the lookup class
81
MethodHandle findMethod(MemberName method,
82
boolean doDispatch, Class<?> lookupClass) throws IllegalAccessException {
83
MethodType mtype = method.getMethodType();
84
if (!method.isStatic()) {
85
// adjust the advertised receiver type to be exactly the one requested
86
// (in the case of invokespecial, this will be the calling class)
87
Class<?> recvType = method.getDeclaringClass();
88
mtype = mtype.insertParameterTypes(0, recvType);
90
DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
92
throw method.makeAccessException("no direct method handle", lookupClass);
93
assert(mh.type() == mtype);
94
if (!method.isVarargs())
96
int argc = mtype.parameterCount();
98
Class<?> arrayType = mtype.parameterType(argc-1);
99
if (arrayType.isArray())
100
return AdapterMethodHandle.makeVarargsCollector(mh, arrayType);
102
throw method.makeAccessException("cannot make variable arity", null);
106
MethodHandle makeAllocator(MethodHandle rawConstructor) {
107
MethodType rawConType = rawConstructor.type();
108
Class<?> allocateClass = rawConType.parameterType(0);
109
// Wrap the raw (unsafe) constructor with the allocation of a suitable object.
111
// [fold]=> cookedConstructor(obj=allocate(C), arg...)
112
// [dup,collect]=> identity(obj, void=rawConstructor(obj, arg...))
113
MethodHandle returner = MethodHandles.identity(allocateClass);
114
MethodType ctype = rawConType.insertParameterTypes(0, allocateClass).changeReturnType(allocateClass);
115
MethodHandle cookedConstructor = AdapterMethodHandle.makeCollectArguments(returner, rawConstructor, 1, false);
116
assert(cookedConstructor.type().equals(ctype));
117
ctype = ctype.dropParameterTypes(0, 1);
118
cookedConstructor = AdapterMethodHandle.makeCollectArguments(cookedConstructor, returner, 0, true);
119
MethodHandle allocator = new AllocateObject(allocateClass);
120
// allocate() => new C(void)
121
assert(allocator.type().equals(MethodType.methodType(allocateClass)));
122
ctype = ctype.dropParameterTypes(0, 1);
123
MethodHandle fold = foldArguments(cookedConstructor, ctype, 0, allocator);
127
static final class AllocateObject<C> extends BoundMethodHandle {
128
private static final Unsafe unsafe = Unsafe.getUnsafe();
130
private final Class<C> allocateClass;
132
// for allocation only:
133
private AllocateObject(Class<C> allocateClass) {
134
super(ALLOCATE.asType(MethodType.methodType(allocateClass, AllocateObject.class)));
135
this.allocateClass = allocateClass;
137
@SuppressWarnings("unchecked")
138
private C allocate() throws InstantiationException {
139
return (C) unsafe.allocateInstance(allocateClass);
141
static final MethodHandle ALLOCATE;
144
ALLOCATE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "allocate", MethodType.genericMethodType(0));
145
} catch (ReflectiveOperationException ex) {
146
throw uncaughtException(ex);
152
MethodHandle accessField(MemberName member, boolean isSetter,
153
Class<?> lookupClass) {
154
// Use sun. misc.Unsafe to dig up the dirt on the field.
155
MethodHandle mh = new FieldAccessor(member, isSetter);
160
MethodHandle accessArrayElement(Class<?> arrayClass, boolean isSetter) {
161
if (!arrayClass.isArray())
162
throw newIllegalArgumentException("not an array: "+arrayClass);
163
Class<?> elemClass = arrayClass.getComponentType();
164
MethodHandle[] mhs = FieldAccessor.ARRAY_CACHE.get(elemClass);
166
if (!FieldAccessor.doCache(elemClass))
167
return FieldAccessor.ahandle(arrayClass, isSetter);
168
mhs = new MethodHandle[] {
169
FieldAccessor.ahandle(arrayClass, false),
170
FieldAccessor.ahandle(arrayClass, true)
172
if (mhs[0].type().parameterType(0) == Class.class) {
173
mhs[0] = mhs[0].bindTo(elemClass);
174
mhs[1] = mhs[1].bindTo(elemClass);
176
synchronized (FieldAccessor.ARRAY_CACHE) {} // memory barrier
177
FieldAccessor.ARRAY_CACHE.put(elemClass, mhs);
179
return mhs[isSetter ? 1 : 0];
182
static final class FieldAccessor<C,V> extends BoundMethodHandle {
183
private static final Unsafe unsafe = Unsafe.getUnsafe();
184
final Object base; // for static refs only
188
FieldAccessor(MemberName field, boolean isSetter) {
189
super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
190
this.offset = fieldOffset(field);
191
this.name = field.getName();
195
String debugString() { return addTypeString(name, this); }
197
int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
198
void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
199
long getFieldJ(C obj) { return unsafe.getLong(obj, offset); }
200
void setFieldJ(C obj, long x) { unsafe.putLong(obj, offset, x); }
201
float getFieldF(C obj) { return unsafe.getFloat(obj, offset); }
202
void setFieldF(C obj, float x) { unsafe.putFloat(obj, offset, x); }
203
double getFieldD(C obj) { return unsafe.getDouble(obj, offset); }
204
void setFieldD(C obj, double x) { unsafe.putDouble(obj, offset, x); }
205
boolean getFieldZ(C obj) { return unsafe.getBoolean(obj, offset); }
206
void setFieldZ(C obj, boolean x) { unsafe.putBoolean(obj, offset, x); }
207
byte getFieldB(C obj) { return unsafe.getByte(obj, offset); }
208
void setFieldB(C obj, byte x) { unsafe.putByte(obj, offset, x); }
209
short getFieldS(C obj) { return unsafe.getShort(obj, offset); }
210
void setFieldS(C obj, short x) { unsafe.putShort(obj, offset, x); }
211
char getFieldC(C obj) { return unsafe.getChar(obj, offset); }
212
void setFieldC(C obj, char x) { unsafe.putChar(obj, offset, x); }
213
@SuppressWarnings("unchecked")
214
V getFieldL(C obj) { return (V) unsafe.getObject(obj, offset); }
215
@SuppressWarnings("unchecked")
216
void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); }
217
// cast (V) is OK here, since we wrap convertArguments around the MH.
219
static Integer fieldOffset(final MemberName field) {
220
return AccessController.doPrivileged(new PrivilegedAction<Integer>() {
221
public Integer run() {
223
Class c = field.getDeclaringClass();
224
// FIXME: Should not have to create 'f' to get this value.
225
java.lang.reflect.Field f = c.getDeclaredField(field.getName());
226
return unsafe.fieldOffset(f);
227
} catch (NoSuchFieldException ee) {
228
throw uncaughtException(ee);
234
int getStaticI() { return unsafe.getInt(base, offset); }
235
void setStaticI(int x) { unsafe.putInt(base, offset, x); }
236
long getStaticJ() { return unsafe.getLong(base, offset); }
237
void setStaticJ(long x) { unsafe.putLong(base, offset, x); }
238
float getStaticF() { return unsafe.getFloat(base, offset); }
239
void setStaticF(float x) { unsafe.putFloat(base, offset, x); }
240
double getStaticD() { return unsafe.getDouble(base, offset); }
241
void setStaticD(double x) { unsafe.putDouble(base, offset, x); }
242
boolean getStaticZ() { return unsafe.getBoolean(base, offset); }
243
void setStaticZ(boolean x) { unsafe.putBoolean(base, offset, x); }
244
byte getStaticB() { return unsafe.getByte(base, offset); }
245
void setStaticB(byte x) { unsafe.putByte(base, offset, x); }
246
short getStaticS() { return unsafe.getShort(base, offset); }
247
void setStaticS(short x) { unsafe.putShort(base, offset, x); }
248
char getStaticC() { return unsafe.getChar(base, offset); }
249
void setStaticC(char x) { unsafe.putChar(base, offset, x); }
250
V getStaticL() { return (V) unsafe.getObject(base, offset); }
251
void setStaticL(V x) { unsafe.putObject(base, offset, x); }
253
static String fname(Class<?> vclass, boolean isSetter, boolean isStatic) {
256
stem = (!isSetter ? "getField" : "setField");
258
stem = (!isSetter ? "getStatic" : "setStatic");
259
return stem + Wrapper.basicTypeChar(vclass);
261
static MethodType ftype(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
265
return MethodType.methodType(vclass, cclass);
267
return MethodType.methodType(void.class, cclass, vclass);
270
return MethodType.methodType(vclass);
272
return MethodType.methodType(void.class, vclass);
275
static MethodHandle fhandle(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
276
String name = FieldAccessor.fname(vclass, isSetter, isStatic);
277
if (cclass.isPrimitive()) throw newIllegalArgumentException("primitive "+cclass);
278
Class<?> ecclass = Object.class; //erase this type
279
Class<?> evclass = vclass;
280
if (!evclass.isPrimitive()) evclass = Object.class;
281
MethodType type = FieldAccessor.ftype(ecclass, evclass, isSetter, isStatic);
284
mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type);
285
} catch (ReflectiveOperationException ex) {
286
throw uncaughtException(ex);
288
if (evclass != vclass || (!isStatic && ecclass != cclass)) {
289
MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
290
strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
291
mh = convertArguments(mh, strongType, 0);
296
/// Support for array element access
297
static final HashMap<Class<?>, MethodHandle[]> ARRAY_CACHE =
298
new HashMap<Class<?>, MethodHandle[]>();
299
// FIXME: Cache on the classes themselves, not here.
300
static boolean doCache(Class<?> elemClass) {
301
if (elemClass.isPrimitive()) return true;
302
ClassLoader cl = elemClass.getClassLoader();
303
return cl == null || cl == ClassLoader.getSystemClassLoader();
305
static int getElementI(int[] a, int i) { return a[i]; }
306
static void setElementI(int[] a, int i, int x) { a[i] = x; }
307
static long getElementJ(long[] a, int i) { return a[i]; }
308
static void setElementJ(long[] a, int i, long x) { a[i] = x; }
309
static float getElementF(float[] a, int i) { return a[i]; }
310
static void setElementF(float[] a, int i, float x) { a[i] = x; }
311
static double getElementD(double[] a, int i) { return a[i]; }
312
static void setElementD(double[] a, int i, double x) { a[i] = x; }
313
static boolean getElementZ(boolean[] a, int i) { return a[i]; }
314
static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
315
static byte getElementB(byte[] a, int i) { return a[i]; }
316
static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
317
static short getElementS(short[] a, int i) { return a[i]; }
318
static void setElementS(short[] a, int i, short x) { a[i] = x; }
319
static char getElementC(char[] a, int i) { return a[i]; }
320
static void setElementC(char[] a, int i, char x) { a[i] = x; }
321
static Object getElementL(Object[] a, int i) { return a[i]; }
322
static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
323
static <V> V getElementL(Class<V[]> aclass, V[] a, int i) { return aclass.cast(a)[i]; }
324
static <V> void setElementL(Class<V[]> aclass, V[] a, int i, V x) { aclass.cast(a)[i] = x; }
326
static String aname(Class<?> aclass, boolean isSetter) {
327
Class<?> vclass = aclass.getComponentType();
328
if (vclass == null) throw new IllegalArgumentException();
329
return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(vclass);
331
static MethodType atype(Class<?> aclass, boolean isSetter) {
332
Class<?> vclass = aclass.getComponentType();
334
return MethodType.methodType(vclass, aclass, int.class);
336
return MethodType.methodType(void.class, aclass, int.class, vclass);
338
static MethodHandle ahandle(Class<?> aclass, boolean isSetter) {
339
Class<?> vclass = aclass.getComponentType();
340
String name = FieldAccessor.aname(aclass, isSetter);
341
Class<?> caclass = null;
342
if (!vclass.isPrimitive() && vclass != Object.class) {
344
aclass = Object[].class;
345
vclass = Object.class;
347
MethodType type = FieldAccessor.atype(aclass, isSetter);
349
type = type.insertParameterTypes(0, Class.class);
352
mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type);
353
} catch (ReflectiveOperationException ex) {
354
throw uncaughtException(ex);
356
if (caclass != null) {
357
MethodType strongType = FieldAccessor.atype(caclass, isSetter);
358
mh = mh.bindTo(caclass);
359
mh = convertArguments(mh, strongType, 0);
365
/** Bind a predetermined first argument to the given direct method handle.
366
* Callable only from MethodHandles.
367
* @param token Proof that the caller has access to this package.
368
* @param target Any direct method handle.
369
* @param receiver Receiver (or first static method argument) to pre-bind.
370
* @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
373
MethodHandle bindReceiver(MethodHandle target, Object receiver) {
374
if (receiver == null) return null;
375
return new BoundMethodHandle(target, receiver, 0);
378
/** Bind a predetermined argument to the given arbitrary method handle.
379
* Callable only from MethodHandles.
380
* @param token Proof that the caller has access to this package.
381
* @param target Any method handle.
382
* @param receiver Argument (which can be a boxed primitive) to pre-bind.
383
* @return a suitable BoundMethodHandle
386
MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) {
387
return new BoundMethodHandle(target, receiver, argnum);
390
static native MethodHandle permuteArguments(MethodHandle target,
393
int[] permutationOrNull);
395
/*non-public*/ static
396
MethodHandle convertArguments(MethodHandle target, MethodType newType, int level) {
397
MethodType oldType = target.type();
398
if (oldType.equals(newType))
400
assert(level > 1 || oldType.isConvertibleTo(newType));
401
MethodHandle retFilter = null;
402
Class<?> oldRT = oldType.returnType();
403
Class<?> newRT = newType.returnType();
404
if (!VerifyType.isNullConversion(oldRT, newRT)) {
405
if (oldRT == void.class) {
406
Wrapper wrap = newRT.isPrimitive() ? Wrapper.forPrimitiveType(newRT) : Wrapper.OBJECT;
407
retFilter = ValueConversions.zeroConstantFunction(wrap);
409
retFilter = MethodHandles.identity(newRT);
410
retFilter = convertArguments(retFilter, retFilter.type().changeParameterType(0, oldRT), level);
412
newType = newType.changeReturnType(oldRT);
414
MethodHandle res = null;
417
res = convertArguments(target, newType, oldType, level);
418
} catch (IllegalArgumentException ex1) {
422
WrongMethodTypeException wmt = new WrongMethodTypeException("cannot convert to "+newType+": "+target);
426
if (retFilter != null)
427
res = MethodHandles.filterReturnValue(res, retFilter);
431
static MethodHandle convertArguments(MethodHandle target,
435
assert(oldType.parameterCount() == target.type().parameterCount());
436
if (newType == oldType)
438
if (oldType.parameterCount() != newType.parameterCount())
439
throw newIllegalArgumentException("mismatched parameter count", oldType, newType);
440
return AdapterMethodHandle.makePairwiseConvert(newType, target, level);
443
static MethodHandle spreadArguments(MethodHandle target, Class<?> arrayType, int arrayLength) {
444
MethodType oldType = target.type();
445
int nargs = oldType.parameterCount();
446
int keepPosArgs = nargs - arrayLength;
447
MethodType newType = oldType
448
.dropParameterTypes(keepPosArgs, nargs)
449
.insertParameterTypes(keepPosArgs, arrayType);
450
return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength);
452
// called internally only
453
static MethodHandle spreadArgumentsFromPos(MethodHandle target, MethodType newType, int spreadArgPos) {
454
int arrayLength = target.type().parameterCount() - spreadArgPos;
455
return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength);
457
static MethodHandle spreadArguments(MethodHandle target,
462
// TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
463
MethodType oldType = target.type();
464
// spread the last argument of newType to oldType
465
assert(arrayLength == oldType.parameterCount() - spreadArgPos);
466
assert(newType.parameterType(spreadArgPos) == arrayType);
467
return AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength);
470
static MethodHandle collectArguments(MethodHandle target,
472
MethodHandle collector) {
473
MethodType type = target.type();
474
Class<?> collectType = collector.type().returnType();
475
assert(collectType != void.class); // else use foldArguments
476
if (collectType != type.parameterType(collectArg))
477
target = target.asType(type.changeParameterType(collectArg, collectType));
478
MethodType newType = type
479
.dropParameterTypes(collectArg, collectArg+1)
480
.insertParameterTypes(collectArg, collector.type().parameterArray());
481
return collectArguments(target, newType, collectArg, collector);
483
static MethodHandle collectArguments(MethodHandle target,
486
MethodHandle collector) {
487
MethodType oldType = target.type(); // (a...,c)=>r
488
// newType // (a..., b...)=>r
489
MethodType colType = collector.type(); // (b...)=>c
490
// oldType // (a..., b...)=>r
491
assert(newType.parameterCount() == collectArg + colType.parameterCount());
492
assert(oldType.parameterCount() == collectArg + 1);
493
return AdapterMethodHandle.makeCollectArguments(target, collector, collectArg, false);
496
static MethodHandle filterArgument(MethodHandle target,
498
MethodHandle filter) {
499
MethodType ttype = target.type();
500
MethodType ftype = filter.type();
501
assert(ftype.parameterCount() == 1);
502
return AdapterMethodHandle.makeCollectArguments(target, filter, pos, false);
505
static MethodHandle foldArguments(MethodHandle target,
508
MethodHandle combiner) {
509
MethodType oldType = target.type();
510
MethodType ctype = combiner.type();
511
return AdapterMethodHandle.makeCollectArguments(target, combiner, foldPos, true);
515
MethodHandle dropArguments(MethodHandle target,
516
MethodType newType, int argnum) {
517
int drops = newType.parameterCount() - target.type().parameterCount();
518
return AdapterMethodHandle.makeDropArguments(newType, target, argnum, drops);
522
MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
523
return testResult ? target : fallback;
526
static MethodHandle SELECT_ALTERNATIVE;
527
static MethodHandle selectAlternative() {
528
if (SELECT_ALTERNATIVE != null) return SELECT_ALTERNATIVE;
531
= IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
532
MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
533
} catch (ReflectiveOperationException ex) {
534
throw new RuntimeException(ex);
536
return SELECT_ALTERNATIVE;
540
MethodHandle makeGuardWithTest(MethodHandle test,
542
MethodHandle fallback) {
544
// [fold]=> continueAfterTest(z=test(arg...), arg...)
545
// [filter]=> (tf=select(z))(arg...)
546
// where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
547
// [tailcall]=> tf(arg...)
548
assert(test.type().returnType() == boolean.class);
549
MethodType targetType = target.type();
550
MethodType foldTargetType = targetType.insertParameterTypes(0, boolean.class);
551
// working backwards, as usual:
552
assert(target.type().equals(fallback.type()));
553
MethodHandle tailcall = MethodHandles.exactInvoker(target.type());
554
MethodHandle select = selectAlternative();
555
select = bindArgument(select, 2, fallback);
556
select = bindArgument(select, 1, target);
557
// select(z: boolean) => (z ? target : fallback)
558
MethodHandle filter = filterArgument(tailcall, 0, select);
559
assert(filter.type().parameterType(0) == boolean.class);
560
MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test);
564
private static class GuardWithCatch extends BoundMethodHandle {
565
private final MethodHandle target;
566
private final Class<? extends Throwable> exType;
567
private final MethodHandle catcher;
568
GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
569
this(INVOKES[target.type().parameterCount()], target, exType, catcher);
571
// FIXME: Build the control flow out of foldArguments.
572
GuardWithCatch(MethodHandle invoker,
573
MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
575
this.target = target;
576
this.exType = exType;
577
this.catcher = catcher;
580
String debugString() {
581
return addTypeString(target, this);
583
private Object invoke_V(Object... av) throws Throwable {
585
return target.invokeExact(av);
586
} catch (Throwable t) {
587
if (!exType.isInstance(t)) throw t;
588
return catcher.invokeExact(t, av);
591
private Object invoke_L0() throws Throwable {
593
return target.invokeExact();
594
} catch (Throwable t) {
595
if (!exType.isInstance(t)) throw t;
596
return catcher.invokeExact(t);
599
private Object invoke_L1(Object a0) throws Throwable {
601
return target.invokeExact(a0);
602
} catch (Throwable t) {
603
if (!exType.isInstance(t)) throw t;
604
return catcher.invokeExact(t, a0);
607
private Object invoke_L2(Object a0, Object a1) throws Throwable {
609
return target.invokeExact(a0, a1);
610
} catch (Throwable t) {
611
if (!exType.isInstance(t)) throw t;
612
return catcher.invokeExact(t, a0, a1);
615
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
617
return target.invokeExact(a0, a1, a2);
618
} catch (Throwable t) {
619
if (!exType.isInstance(t)) throw t;
620
return catcher.invokeExact(t, a0, a1, a2);
623
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
625
return target.invokeExact(a0, a1, a2, a3);
626
} catch (Throwable t) {
627
if (!exType.isInstance(t)) throw t;
628
return catcher.invokeExact(t, a0, a1, a2, a3);
631
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
633
return target.invokeExact(a0, a1, a2, a3, a4);
634
} catch (Throwable t) {
635
if (!exType.isInstance(t)) throw t;
636
return catcher.invokeExact(t, a0, a1, a2, a3, a4);
639
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
641
return target.invokeExact(a0, a1, a2, a3, a4, a5);
642
} catch (Throwable t) {
643
if (!exType.isInstance(t)) throw t;
644
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
647
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
649
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
650
} catch (Throwable t) {
651
if (!exType.isInstance(t)) throw t;
652
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
655
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
657
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
658
} catch (Throwable t) {
659
if (!exType.isInstance(t)) throw t;
660
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
663
static MethodHandle[] makeInvokes() {
664
ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
665
MethodHandles.Lookup lookup = IMPL_LOOKUP;
667
int nargs = invokes.size();
668
String name = "invoke_L"+nargs;
669
MethodHandle invoke = null;
671
invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs));
672
} catch (ReflectiveOperationException ex) {
674
if (invoke == null) break;
677
assert(invokes.size() == 9); // current number of methods
678
return invokes.toArray(new MethodHandle[0]);
680
static final MethodHandle[] INVOKES = makeInvokes();
681
// For testing use this:
682
//static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
683
static final MethodHandle VARARGS_INVOKE;
686
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
687
} catch (ReflectiveOperationException ex) {
688
throw uncaughtException(ex);
695
MethodHandle makeGuardWithCatch(MethodHandle target,
696
Class<? extends Throwable> exType,
697
MethodHandle catcher) {
698
MethodType type = target.type();
699
MethodType ctype = catcher.type();
700
int nargs = type.parameterCount();
701
if (nargs < GuardWithCatch.INVOKES.length) {
702
MethodType gtype = type.generic();
703
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
704
// Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
705
MethodHandle gtarget = convertArguments(target, gtype, type, 2);
706
MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, 2);
707
MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
708
if (gtarget == null || gcatcher == null || gguard == null) return null;
709
return convertArguments(gguard, type, gtype, 2);
711
MethodType gtype = MethodType.genericMethodType(0, true);
712
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
713
MethodHandle gtarget = spreadArgumentsFromPos(target, gtype, 0);
714
catcher = catcher.asType(ctype.changeParameterType(0, Throwable.class));
715
MethodHandle gcatcher = spreadArgumentsFromPos(catcher, gcatchType, 1);
716
MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
717
if (gtarget == null || gcatcher == null || gguard == null) return null;
718
return collectArguments(gguard, type, 0, ValueConversions.varargsArray(nargs)).asType(type);
723
MethodHandle throwException(MethodType type) {
724
return AdapterMethodHandle.makeRetypeRaw(type, throwException());
727
static MethodHandle THROW_EXCEPTION;
728
static MethodHandle throwException() {
729
if (THROW_EXCEPTION != null) return THROW_EXCEPTION;
732
= IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
733
MethodType.methodType(Empty.class, Throwable.class));
734
} catch (ReflectiveOperationException ex) {
735
throw new RuntimeException(ex);
737
return THROW_EXCEPTION;
739
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }