2009-05-05 22:40:09 -07:00
|
|
|
/*
|
2011-02-11 01:26:24 -08:00
|
|
|
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
|
2009-05-05 22:40:09 -07:00
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
*
|
|
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 only, as
|
2010-05-25 15:58:33 -07:00
|
|
|
* published by the Free Software Foundation. Oracle designates this
|
2009-05-05 22:40:09 -07:00
|
|
|
* particular file as subject to the "Classpath" exception as provided
|
2010-05-25 15:58:33 -07:00
|
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
2009-05-05 22:40:09 -07:00
|
|
|
*
|
|
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
|
|
* accompanied this code).
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License version
|
|
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*
|
2010-05-25 15:58:33 -07:00
|
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
|
|
* questions.
|
2009-05-05 22:40:09 -07:00
|
|
|
*/
|
|
|
|
|
2011-03-23 23:02:31 -07:00
|
|
|
package java.lang.invoke;
|
2009-05-05 22:40:09 -07:00
|
|
|
|
2011-03-23 23:02:31 -07:00
|
|
|
import sun.invoke.util.VerifyType;
|
2010-01-07 16:16:45 -08:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
2011-03-23 23:02:31 -07:00
|
|
|
import sun.invoke.empty.Empty;
|
|
|
|
import sun.invoke.util.ValueConversions;
|
|
|
|
import sun.invoke.util.Wrapper;
|
2010-01-07 16:16:45 -08:00
|
|
|
import sun.misc.Unsafe;
|
2011-03-23 23:02:31 -07:00
|
|
|
import static java.lang.invoke.MethodHandleStatics.*;
|
|
|
|
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
2009-05-05 22:40:09 -07:00
|
|
|
|
|
|
|
/**
|
2011-03-18 00:03:24 -07:00
|
|
|
* Trusted implementation code for MethodHandle.
|
2009-05-05 22:40:09 -07:00
|
|
|
* @author jrose
|
|
|
|
*/
|
2011-03-18 00:03:24 -07:00
|
|
|
/*non-public*/ abstract class MethodHandleImpl {
|
2009-05-05 22:40:09 -07:00
|
|
|
/// Factory methods to create method handles:
|
|
|
|
|
|
|
|
private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static void initStatics() {
|
2009-05-05 22:40:09 -07:00
|
|
|
// Trigger preceding sequence.
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Look up a given method.
|
2011-03-23 23:02:31 -07:00
|
|
|
* Callable only from sun.invoke and related packages.
|
2009-05-05 22:40:09 -07:00
|
|
|
* <p>
|
|
|
|
* The resulting method handle type will be of the given type,
|
|
|
|
* with a receiver type {@code rcvc} prepended if the member is not static.
|
|
|
|
* <p>
|
|
|
|
* Access checks are made as of the given lookup class.
|
|
|
|
* In particular, if the method is protected and {@code defc} is in a
|
|
|
|
* different package from the lookup class, then {@code rcvc} must be
|
|
|
|
* the lookup class or a subclass.
|
|
|
|
* @param token Proof that the lookup class has access to this package.
|
|
|
|
* @param member Resolved method or constructor to call.
|
|
|
|
* @param name Name of the desired method.
|
|
|
|
* @param rcvc Receiver type of desired non-static method (else null)
|
|
|
|
* @param doDispatch whether the method handle will test the receiver type
|
|
|
|
* @param lookupClass access-check relative to this class
|
|
|
|
* @return a direct handle to the matching method
|
2011-02-11 01:26:32 -08:00
|
|
|
* @throws IllegalAccessException if the given method cannot be accessed by the lookup class
|
2009-05-05 22:40:09 -07:00
|
|
|
*/
|
2011-03-18 00:03:24 -07:00
|
|
|
static
|
|
|
|
MethodHandle findMethod(MemberName method,
|
2011-02-11 01:26:32 -08:00
|
|
|
boolean doDispatch, Class<?> lookupClass) throws IllegalAccessException {
|
2009-05-05 22:40:09 -07:00
|
|
|
MethodType mtype = method.getMethodType();
|
2010-04-30 23:48:23 -07:00
|
|
|
if (!method.isStatic()) {
|
2009-05-05 22:40:09 -07:00
|
|
|
// adjust the advertised receiver type to be exactly the one requested
|
|
|
|
// (in the case of invokespecial, this will be the calling class)
|
2009-05-12 13:54:22 -07:00
|
|
|
Class<?> recvType = method.getDeclaringClass();
|
2010-01-07 16:16:45 -08:00
|
|
|
mtype = mtype.insertParameterTypes(0, recvType);
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
|
|
|
DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
|
|
|
|
if (!mh.isValid())
|
2011-03-18 00:03:24 -07:00
|
|
|
throw method.makeAccessException("no access", lookupClass);
|
2010-05-03 23:32:47 -07:00
|
|
|
assert(mh.type() == mtype);
|
2011-02-11 01:26:24 -08:00
|
|
|
if (!method.isVarargs())
|
|
|
|
return mh;
|
|
|
|
else
|
|
|
|
return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1));
|
2010-04-30 23:48:23 -07:00
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static
|
|
|
|
MethodHandle makeAllocator(MethodHandle rawConstructor) {
|
2010-04-30 23:48:23 -07:00
|
|
|
MethodType rawConType = rawConstructor.type();
|
|
|
|
// Wrap the raw (unsafe) constructor with the allocation of a suitable object.
|
|
|
|
MethodHandle allocator
|
2011-03-18 00:03:24 -07:00
|
|
|
= AllocateObject.make(rawConType.parameterType(0), rawConstructor);
|
2010-04-30 23:48:23 -07:00
|
|
|
assert(allocator.type()
|
|
|
|
.equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0))));
|
|
|
|
return allocator;
|
|
|
|
}
|
|
|
|
|
2010-10-30 21:08:23 -07:00
|
|
|
static final class AllocateObject<C> extends BoundMethodHandle {
|
2010-04-30 23:48:23 -07:00
|
|
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
|
|
|
|
|
|
|
private final Class<C> allocateClass;
|
|
|
|
private final MethodHandle rawConstructor;
|
|
|
|
|
|
|
|
private AllocateObject(MethodHandle invoker,
|
|
|
|
Class<C> allocateClass, MethodHandle rawConstructor) {
|
2011-03-18 00:03:24 -07:00
|
|
|
super(invoker);
|
2010-04-30 23:48:23 -07:00
|
|
|
this.allocateClass = allocateClass;
|
|
|
|
this.rawConstructor = rawConstructor;
|
|
|
|
}
|
2011-03-18 00:03:24 -07:00
|
|
|
static MethodHandle make(Class<?> allocateClass, MethodHandle rawConstructor) {
|
2010-04-30 23:48:23 -07:00
|
|
|
MethodType rawConType = rawConstructor.type();
|
|
|
|
assert(rawConType.parameterType(0) == allocateClass);
|
|
|
|
MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
|
|
|
|
int nargs = rawConType.parameterCount() - 1;
|
|
|
|
if (nargs < INVOKES.length) {
|
|
|
|
MethodHandle invoke = INVOKES[nargs];
|
|
|
|
MethodType conType = CON_TYPES[nargs];
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle gcon = convertArguments(rawConstructor, conType, rawConType, null);
|
2010-04-30 23:48:23 -07:00
|
|
|
if (gcon == null) return null;
|
|
|
|
MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
|
|
|
|
assert(galloc.type() == newType.generic());
|
2011-03-18 00:03:24 -07:00
|
|
|
return convertArguments(galloc, newType, galloc.type(), null);
|
2010-04-30 23:48:23 -07:00
|
|
|
} else {
|
|
|
|
MethodHandle invoke = VARARGS_INVOKE;
|
|
|
|
MethodType conType = CON_TYPES[nargs];
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle gcon = spreadArguments(rawConstructor, conType, 1);
|
2010-04-30 23:48:23 -07:00
|
|
|
if (gcon == null) return null;
|
|
|
|
MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
|
2011-03-18 00:03:24 -07:00
|
|
|
return collectArguments(galloc, newType, 1, null);
|
2010-04-30 23:48:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
2010-10-30 21:08:23 -07:00
|
|
|
return addTypeString(allocateClass.getSimpleName(), this);
|
2010-04-30 23:48:23 -07:00
|
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
private C allocate() throws InstantiationException {
|
|
|
|
return (C) unsafe.allocateInstance(allocateClass);
|
|
|
|
}
|
|
|
|
private C invoke_V(Object... av) throws Throwable {
|
|
|
|
C obj = allocate();
|
2010-11-22 22:41:31 -08:00
|
|
|
rawConstructor.invokeExact((Object)obj, av);
|
2010-04-30 23:48:23 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
private C invoke_L0() throws Throwable {
|
|
|
|
C obj = allocate();
|
2010-11-22 22:41:31 -08:00
|
|
|
rawConstructor.invokeExact((Object)obj);
|
2010-04-30 23:48:23 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
private C invoke_L1(Object a0) throws Throwable {
|
|
|
|
C obj = allocate();
|
2010-11-22 22:41:31 -08:00
|
|
|
rawConstructor.invokeExact((Object)obj, a0);
|
2010-04-30 23:48:23 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
private C invoke_L2(Object a0, Object a1) throws Throwable {
|
|
|
|
C obj = allocate();
|
2010-11-22 22:41:31 -08:00
|
|
|
rawConstructor.invokeExact((Object)obj, a0, a1);
|
2010-04-30 23:48:23 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
private C invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
|
|
|
C obj = allocate();
|
2010-11-22 22:41:31 -08:00
|
|
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2);
|
2010-04-30 23:48:23 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
private C invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
|
|
|
C obj = allocate();
|
2010-11-22 22:41:31 -08:00
|
|
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3);
|
2010-04-30 23:48:23 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
private C invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
|
|
|
C obj = allocate();
|
2010-11-22 22:41:31 -08:00
|
|
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4);
|
2010-04-30 23:48:23 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
private C invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
|
|
|
C obj = allocate();
|
2010-11-22 22:41:31 -08:00
|
|
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5);
|
2010-04-30 23:48:23 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
private C invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
|
|
|
C obj = allocate();
|
2010-11-22 22:41:31 -08:00
|
|
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6);
|
2010-04-30 23:48:23 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
private C invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
|
|
|
C obj = allocate();
|
2010-11-22 22:41:31 -08:00
|
|
|
rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6, a7);
|
2010-04-30 23:48:23 -07:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
static MethodHandle[] makeInvokes() {
|
|
|
|
ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
|
|
|
|
MethodHandles.Lookup lookup = IMPL_LOOKUP;
|
|
|
|
for (;;) {
|
|
|
|
int nargs = invokes.size();
|
|
|
|
String name = "invoke_L"+nargs;
|
|
|
|
MethodHandle invoke = null;
|
|
|
|
try {
|
|
|
|
invoke = lookup.findVirtual(AllocateObject.class, name, MethodType.genericMethodType(nargs));
|
2011-02-11 01:26:32 -08:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2010-04-30 23:48:23 -07:00
|
|
|
}
|
|
|
|
if (invoke == null) break;
|
|
|
|
invokes.add(invoke);
|
|
|
|
}
|
|
|
|
assert(invokes.size() == 9); // current number of methods
|
|
|
|
return invokes.toArray(new MethodHandle[0]);
|
|
|
|
};
|
|
|
|
static final MethodHandle[] INVOKES = makeInvokes();
|
|
|
|
// For testing use this:
|
|
|
|
//static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
|
|
|
|
static final MethodHandle VARARGS_INVOKE;
|
|
|
|
static {
|
|
|
|
try {
|
|
|
|
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true));
|
2011-02-11 01:26:32 -08:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2010-09-08 18:40:23 -07:00
|
|
|
throw uncaughtException(ex);
|
2010-04-30 23:48:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Corresponding generic constructor types:
|
|
|
|
static final MethodType[] CON_TYPES = new MethodType[INVOKES.length];
|
|
|
|
static {
|
|
|
|
for (int i = 0; i < INVOKES.length; i++)
|
|
|
|
CON_TYPES[i] = makeConType(INVOKES[i]);
|
|
|
|
}
|
|
|
|
static final MethodType VARARGS_CON_TYPE = makeConType(VARARGS_INVOKE);
|
|
|
|
static MethodType makeConType(MethodHandle invoke) {
|
|
|
|
MethodType invType = invoke.type();
|
|
|
|
return invType.changeParameterType(0, Object.class).changeReturnType(void.class);
|
|
|
|
}
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static
|
|
|
|
MethodHandle accessField(MemberName member, boolean isSetter,
|
2010-01-07 16:16:45 -08:00
|
|
|
Class<?> lookupClass) {
|
|
|
|
// Use sun. misc.Unsafe to dig up the dirt on the field.
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle mh = new FieldAccessor(member, isSetter);
|
2010-01-07 16:16:45 -08:00
|
|
|
return mh;
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static
|
|
|
|
MethodHandle accessArrayElement(Class<?> arrayClass, boolean isSetter) {
|
2009-05-05 22:40:09 -07:00
|
|
|
if (!arrayClass.isArray())
|
|
|
|
throw newIllegalArgumentException("not an array: "+arrayClass);
|
2010-01-07 16:16:45 -08:00
|
|
|
Class<?> elemClass = arrayClass.getComponentType();
|
|
|
|
MethodHandle[] mhs = FieldAccessor.ARRAY_CACHE.get(elemClass);
|
|
|
|
if (mhs == null) {
|
|
|
|
if (!FieldAccessor.doCache(elemClass))
|
|
|
|
return FieldAccessor.ahandle(arrayClass, isSetter);
|
|
|
|
mhs = new MethodHandle[] {
|
|
|
|
FieldAccessor.ahandle(arrayClass, false),
|
|
|
|
FieldAccessor.ahandle(arrayClass, true)
|
|
|
|
};
|
|
|
|
if (mhs[0].type().parameterType(0) == Class.class) {
|
|
|
|
mhs[0] = MethodHandles.insertArguments(mhs[0], 0, elemClass);
|
|
|
|
mhs[1] = MethodHandles.insertArguments(mhs[1], 0, elemClass);
|
|
|
|
}
|
|
|
|
synchronized (FieldAccessor.ARRAY_CACHE) {} // memory barrier
|
|
|
|
FieldAccessor.ARRAY_CACHE.put(elemClass, mhs);
|
|
|
|
}
|
|
|
|
return mhs[isSetter ? 1 : 0];
|
|
|
|
}
|
|
|
|
|
2010-10-30 21:08:23 -07:00
|
|
|
static final class FieldAccessor<C,V> extends BoundMethodHandle {
|
2010-01-07 16:16:45 -08:00
|
|
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
|
|
|
final Object base; // for static refs only
|
|
|
|
final long offset;
|
|
|
|
final String name;
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
FieldAccessor(MemberName field, boolean isSetter) {
|
|
|
|
super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
|
|
|
|
this.offset = (long) field.getVMIndex();
|
2010-01-07 16:16:45 -08:00
|
|
|
this.name = field.getName();
|
|
|
|
this.base = staticBase(field);
|
|
|
|
}
|
2011-03-18 00:03:24 -07:00
|
|
|
@Override
|
2010-10-30 21:08:23 -07:00
|
|
|
public String toString() { return addTypeString(name, this); }
|
2010-01-07 16:16:45 -08:00
|
|
|
|
|
|
|
int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
|
|
|
|
void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
|
|
|
|
long getFieldJ(C obj) { return unsafe.getLong(obj, offset); }
|
|
|
|
void setFieldJ(C obj, long x) { unsafe.putLong(obj, offset, x); }
|
|
|
|
float getFieldF(C obj) { return unsafe.getFloat(obj, offset); }
|
|
|
|
void setFieldF(C obj, float x) { unsafe.putFloat(obj, offset, x); }
|
|
|
|
double getFieldD(C obj) { return unsafe.getDouble(obj, offset); }
|
|
|
|
void setFieldD(C obj, double x) { unsafe.putDouble(obj, offset, x); }
|
|
|
|
boolean getFieldZ(C obj) { return unsafe.getBoolean(obj, offset); }
|
|
|
|
void setFieldZ(C obj, boolean x) { unsafe.putBoolean(obj, offset, x); }
|
|
|
|
byte getFieldB(C obj) { return unsafe.getByte(obj, offset); }
|
|
|
|
void setFieldB(C obj, byte x) { unsafe.putByte(obj, offset, x); }
|
|
|
|
short getFieldS(C obj) { return unsafe.getShort(obj, offset); }
|
|
|
|
void setFieldS(C obj, short x) { unsafe.putShort(obj, offset, x); }
|
|
|
|
char getFieldC(C obj) { return unsafe.getChar(obj, offset); }
|
|
|
|
void setFieldC(C obj, char x) { unsafe.putChar(obj, offset, x); }
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
V getFieldL(C obj) { return (V) unsafe.getObject(obj, offset); }
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); }
|
|
|
|
// cast (V) is OK here, since we wrap convertArguments around the MH.
|
|
|
|
|
|
|
|
static Object staticBase(MemberName field) {
|
|
|
|
if (!field.isStatic()) return null;
|
|
|
|
Class c = field.getDeclaringClass();
|
|
|
|
java.lang.reflect.Field f;
|
|
|
|
try {
|
|
|
|
// FIXME: Should not have to create 'f' to get this value.
|
|
|
|
f = c.getDeclaredField(field.getName());
|
|
|
|
return unsafe.staticFieldBase(f);
|
|
|
|
} catch (Exception ee) {
|
2010-09-08 18:40:23 -07:00
|
|
|
throw uncaughtException(ee);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int getStaticI() { return unsafe.getInt(base, offset); }
|
|
|
|
void setStaticI(int x) { unsafe.putInt(base, offset, x); }
|
|
|
|
long getStaticJ() { return unsafe.getLong(base, offset); }
|
|
|
|
void setStaticJ(long x) { unsafe.putLong(base, offset, x); }
|
|
|
|
float getStaticF() { return unsafe.getFloat(base, offset); }
|
|
|
|
void setStaticF(float x) { unsafe.putFloat(base, offset, x); }
|
|
|
|
double getStaticD() { return unsafe.getDouble(base, offset); }
|
|
|
|
void setStaticD(double x) { unsafe.putDouble(base, offset, x); }
|
|
|
|
boolean getStaticZ() { return unsafe.getBoolean(base, offset); }
|
|
|
|
void setStaticZ(boolean x) { unsafe.putBoolean(base, offset, x); }
|
|
|
|
byte getStaticB() { return unsafe.getByte(base, offset); }
|
|
|
|
void setStaticB(byte x) { unsafe.putByte(base, offset, x); }
|
|
|
|
short getStaticS() { return unsafe.getShort(base, offset); }
|
|
|
|
void setStaticS(short x) { unsafe.putShort(base, offset, x); }
|
|
|
|
char getStaticC() { return unsafe.getChar(base, offset); }
|
|
|
|
void setStaticC(char x) { unsafe.putChar(base, offset, x); }
|
|
|
|
V getStaticL() { return (V) unsafe.getObject(base, offset); }
|
|
|
|
void setStaticL(V x) { unsafe.putObject(base, offset, x); }
|
|
|
|
|
|
|
|
static String fname(Class<?> vclass, boolean isSetter, boolean isStatic) {
|
|
|
|
String stem;
|
|
|
|
if (!isStatic)
|
|
|
|
stem = (!isSetter ? "getField" : "setField");
|
|
|
|
else
|
|
|
|
stem = (!isSetter ? "getStatic" : "setStatic");
|
|
|
|
return stem + Wrapper.basicTypeChar(vclass);
|
|
|
|
}
|
|
|
|
static MethodType ftype(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
|
|
|
|
MethodType type;
|
|
|
|
if (!isStatic) {
|
|
|
|
if (!isSetter)
|
|
|
|
return MethodType.methodType(vclass, cclass);
|
|
|
|
else
|
|
|
|
return MethodType.methodType(void.class, cclass, vclass);
|
|
|
|
} else {
|
|
|
|
if (!isSetter)
|
|
|
|
return MethodType.methodType(vclass);
|
|
|
|
else
|
|
|
|
return MethodType.methodType(void.class, vclass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static MethodHandle fhandle(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
|
|
|
|
String name = FieldAccessor.fname(vclass, isSetter, isStatic);
|
|
|
|
if (cclass.isPrimitive()) throw newIllegalArgumentException("primitive "+cclass);
|
|
|
|
Class<?> ecclass = Object.class; //erase this type
|
|
|
|
Class<?> evclass = vclass;
|
|
|
|
if (!evclass.isPrimitive()) evclass = Object.class;
|
|
|
|
MethodType type = FieldAccessor.ftype(ecclass, evclass, isSetter, isStatic);
|
|
|
|
MethodHandle mh;
|
|
|
|
try {
|
|
|
|
mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type);
|
2011-02-11 01:26:32 -08:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2010-09-08 18:40:23 -07:00
|
|
|
throw uncaughtException(ex);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
if (evclass != vclass || (!isStatic && ecclass != cclass)) {
|
|
|
|
MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
|
|
|
|
strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
|
|
|
|
mh = MethodHandles.convertArguments(mh, strongType);
|
|
|
|
}
|
|
|
|
return mh;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Support for array element access
|
|
|
|
static final HashMap<Class<?>, MethodHandle[]> ARRAY_CACHE =
|
|
|
|
new HashMap<Class<?>, MethodHandle[]>();
|
|
|
|
// FIXME: Cache on the classes themselves, not here.
|
|
|
|
static boolean doCache(Class<?> elemClass) {
|
|
|
|
if (elemClass.isPrimitive()) return true;
|
|
|
|
ClassLoader cl = elemClass.getClassLoader();
|
|
|
|
return cl == null || cl == ClassLoader.getSystemClassLoader();
|
|
|
|
}
|
|
|
|
static int getElementI(int[] a, int i) { return a[i]; }
|
|
|
|
static void setElementI(int[] a, int i, int x) { a[i] = x; }
|
|
|
|
static long getElementJ(long[] a, int i) { return a[i]; }
|
|
|
|
static void setElementJ(long[] a, int i, long x) { a[i] = x; }
|
|
|
|
static float getElementF(float[] a, int i) { return a[i]; }
|
|
|
|
static void setElementF(float[] a, int i, float x) { a[i] = x; }
|
|
|
|
static double getElementD(double[] a, int i) { return a[i]; }
|
|
|
|
static void setElementD(double[] a, int i, double x) { a[i] = x; }
|
|
|
|
static boolean getElementZ(boolean[] a, int i) { return a[i]; }
|
|
|
|
static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
|
|
|
|
static byte getElementB(byte[] a, int i) { return a[i]; }
|
|
|
|
static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
|
|
|
|
static short getElementS(short[] a, int i) { return a[i]; }
|
|
|
|
static void setElementS(short[] a, int i, short x) { a[i] = x; }
|
|
|
|
static char getElementC(char[] a, int i) { return a[i]; }
|
|
|
|
static void setElementC(char[] a, int i, char x) { a[i] = x; }
|
|
|
|
static Object getElementL(Object[] a, int i) { return a[i]; }
|
|
|
|
static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
|
|
|
|
static <V> V getElementL(Class<V[]> aclass, V[] a, int i) { return aclass.cast(a)[i]; }
|
|
|
|
static <V> void setElementL(Class<V[]> aclass, V[] a, int i, V x) { aclass.cast(a)[i] = x; }
|
|
|
|
|
|
|
|
static String aname(Class<?> aclass, boolean isSetter) {
|
|
|
|
Class<?> vclass = aclass.getComponentType();
|
|
|
|
if (vclass == null) throw new IllegalArgumentException();
|
|
|
|
return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(vclass);
|
|
|
|
}
|
|
|
|
static MethodType atype(Class<?> aclass, boolean isSetter) {
|
|
|
|
Class<?> vclass = aclass.getComponentType();
|
|
|
|
if (!isSetter)
|
|
|
|
return MethodType.methodType(vclass, aclass, int.class);
|
|
|
|
else
|
|
|
|
return MethodType.methodType(void.class, aclass, int.class, vclass);
|
|
|
|
}
|
|
|
|
static MethodHandle ahandle(Class<?> aclass, boolean isSetter) {
|
|
|
|
Class<?> vclass = aclass.getComponentType();
|
|
|
|
String name = FieldAccessor.aname(aclass, isSetter);
|
|
|
|
Class<?> caclass = null;
|
|
|
|
if (!vclass.isPrimitive() && vclass != Object.class) {
|
|
|
|
caclass = aclass;
|
|
|
|
aclass = Object[].class;
|
|
|
|
vclass = Object.class;
|
|
|
|
}
|
|
|
|
MethodType type = FieldAccessor.atype(aclass, isSetter);
|
|
|
|
if (caclass != null)
|
|
|
|
type = type.insertParameterTypes(0, Class.class);
|
|
|
|
MethodHandle mh;
|
|
|
|
try {
|
|
|
|
mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type);
|
2011-02-11 01:26:32 -08:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2010-09-08 18:40:23 -07:00
|
|
|
throw uncaughtException(ex);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
if (caclass != null) {
|
|
|
|
MethodType strongType = FieldAccessor.atype(caclass, isSetter);
|
|
|
|
mh = MethodHandles.insertArguments(mh, 0, caclass);
|
|
|
|
mh = MethodHandles.convertArguments(mh, strongType);
|
|
|
|
}
|
|
|
|
return mh;
|
|
|
|
}
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Bind a predetermined first argument to the given direct method handle.
|
|
|
|
* Callable only from MethodHandles.
|
|
|
|
* @param token Proof that the caller has access to this package.
|
|
|
|
* @param target Any direct method handle.
|
|
|
|
* @param receiver Receiver (or first static method argument) to pre-bind.
|
|
|
|
* @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
|
|
|
|
*/
|
2011-03-18 00:03:24 -07:00
|
|
|
static
|
|
|
|
MethodHandle bindReceiver(MethodHandle target, Object receiver) {
|
2010-10-30 21:02:30 -07:00
|
|
|
if (target instanceof AdapterMethodHandle &&
|
|
|
|
((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
|
|
|
|
) {
|
2009-05-12 13:54:22 -07:00
|
|
|
Object info = MethodHandleNatives.getTargetInfo(target);
|
|
|
|
if (info instanceof DirectMethodHandle) {
|
|
|
|
DirectMethodHandle dmh = (DirectMethodHandle) info;
|
|
|
|
if (receiver == null ||
|
2010-01-07 16:16:45 -08:00
|
|
|
dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
|
|
|
|
MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
|
|
|
|
MethodType newType = target.type().dropParameterTypes(0, 1);
|
2011-03-18 00:03:24 -07:00
|
|
|
return convertArguments(bmh, newType, bmh.type(), null);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
2009-05-12 13:54:22 -07:00
|
|
|
}
|
|
|
|
}
|
2009-05-05 22:40:09 -07:00
|
|
|
if (target instanceof DirectMethodHandle)
|
|
|
|
return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
|
|
|
|
return null; // let caller try something else
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Bind a predetermined argument to the given arbitrary method handle.
|
|
|
|
* Callable only from MethodHandles.
|
|
|
|
* @param token Proof that the caller has access to this package.
|
|
|
|
* @param target Any method handle.
|
|
|
|
* @param receiver Argument (which can be a boxed primitive) to pre-bind.
|
|
|
|
* @return a suitable BoundMethodHandle
|
|
|
|
*/
|
2011-03-18 00:03:24 -07:00
|
|
|
static
|
|
|
|
MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) {
|
2010-01-07 16:16:45 -08:00
|
|
|
return new BoundMethodHandle(target, receiver, argnum);
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static MethodHandle convertArguments(MethodHandle target,
|
2009-05-05 22:40:09 -07:00
|
|
|
MethodType newType,
|
|
|
|
MethodType oldType,
|
|
|
|
int[] permutationOrNull) {
|
2010-04-30 23:48:23 -07:00
|
|
|
assert(oldType.parameterCount() == target.type().parameterCount());
|
2010-01-07 16:16:45 -08:00
|
|
|
if (permutationOrNull != null) {
|
|
|
|
int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
|
|
|
|
if (permutationOrNull.length != outargs)
|
|
|
|
throw newIllegalArgumentException("wrong number of arguments in permutation");
|
|
|
|
// Make the individual outgoing argument types match up first.
|
|
|
|
Class<?>[] callTypeArgs = new Class<?>[outargs];
|
|
|
|
for (int i = 0; i < outargs; i++)
|
|
|
|
callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
|
|
|
|
MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
|
2011-03-18 00:03:24 -07:00
|
|
|
target = convertArguments(target, callType, oldType, null);
|
2010-01-07 16:16:45 -08:00
|
|
|
assert(target != null);
|
|
|
|
oldType = target.type();
|
|
|
|
List<Integer> goal = new ArrayList<Integer>(); // i*TOKEN
|
|
|
|
List<Integer> state = new ArrayList<Integer>(); // i*TOKEN
|
|
|
|
List<Integer> drops = new ArrayList<Integer>(); // not tokens
|
|
|
|
List<Integer> dups = new ArrayList<Integer>(); // not tokens
|
|
|
|
final int TOKEN = 10; // to mark items which are symbolic only
|
|
|
|
// state represents the argument values coming into target
|
|
|
|
for (int i = 0; i < outargs; i++) {
|
|
|
|
state.add(permutationOrNull[i] * TOKEN);
|
|
|
|
}
|
|
|
|
// goal represents the desired state
|
|
|
|
for (int i = 0; i < inargs; i++) {
|
|
|
|
if (state.contains(i * TOKEN)) {
|
|
|
|
goal.add(i * TOKEN);
|
|
|
|
} else {
|
|
|
|
// adapter must initially drop all unused arguments
|
|
|
|
drops.add(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// detect duplications
|
|
|
|
while (state.size() > goal.size()) {
|
|
|
|
for (int i2 = 0; i2 < state.size(); i2++) {
|
|
|
|
int arg1 = state.get(i2);
|
|
|
|
int i1 = state.indexOf(arg1);
|
|
|
|
if (i1 != i2) {
|
|
|
|
// found duplicate occurrence at i2
|
|
|
|
int arg2 = (inargs++) * TOKEN;
|
|
|
|
state.set(i2, arg2);
|
|
|
|
dups.add(goal.indexOf(arg1));
|
|
|
|
goal.add(arg2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(state.size() == goal.size());
|
|
|
|
int size = goal.size();
|
|
|
|
while (!state.equals(goal)) {
|
|
|
|
// Look for a maximal sequence of adjacent misplaced arguments,
|
|
|
|
// and try to rotate them into place.
|
|
|
|
int bestRotArg = -10 * TOKEN, bestRotLen = 0;
|
|
|
|
int thisRotArg = -10 * TOKEN, thisRotLen = 0;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
int arg = state.get(i);
|
|
|
|
// Does this argument match the current run?
|
|
|
|
if (arg == thisRotArg + TOKEN) {
|
|
|
|
thisRotArg = arg;
|
|
|
|
thisRotLen += 1;
|
|
|
|
if (bestRotLen < thisRotLen) {
|
|
|
|
bestRotLen = thisRotLen;
|
|
|
|
bestRotArg = thisRotArg;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// The old sequence (if any) stops here.
|
|
|
|
thisRotLen = 0;
|
|
|
|
thisRotArg = -10 * TOKEN;
|
|
|
|
// But maybe a new one starts here also.
|
|
|
|
int wantArg = goal.get(i);
|
|
|
|
final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION;
|
|
|
|
if (arg != wantArg &&
|
|
|
|
arg >= wantArg - TOKEN * MAX_ARG_ROTATION &&
|
|
|
|
arg <= wantArg + TOKEN * MAX_ARG_ROTATION) {
|
|
|
|
thisRotArg = arg;
|
|
|
|
thisRotLen = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bestRotLen >= 2) {
|
|
|
|
// Do a rotation if it can improve argument positioning
|
|
|
|
// by at least 2 arguments. This is not always optimal,
|
|
|
|
// but it seems to catch common cases.
|
|
|
|
int dstEnd = state.indexOf(bestRotArg);
|
|
|
|
int srcEnd = goal.indexOf(bestRotArg);
|
|
|
|
int rotBy = dstEnd - srcEnd;
|
|
|
|
int dstBeg = dstEnd - (bestRotLen - 1);
|
|
|
|
int srcBeg = srcEnd - (bestRotLen - 1);
|
|
|
|
assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs
|
|
|
|
// Make a span which covers both source and destination.
|
|
|
|
int rotBeg = Math.min(dstBeg, srcBeg);
|
|
|
|
int rotEnd = Math.max(dstEnd, srcEnd);
|
|
|
|
int score = 0;
|
|
|
|
for (int i = rotBeg; i <= rotEnd; i++) {
|
|
|
|
if ((int)state.get(i) != (int)goal.get(i))
|
|
|
|
score += 1;
|
|
|
|
}
|
|
|
|
List<Integer> rotSpan = state.subList(rotBeg, rotEnd+1);
|
|
|
|
Collections.rotate(rotSpan, -rotBy); // reverse direction
|
|
|
|
for (int i = rotBeg; i <= rotEnd; i++) {
|
|
|
|
if ((int)state.get(i) != (int)goal.get(i))
|
|
|
|
score -= 1;
|
|
|
|
}
|
|
|
|
if (score >= 2) {
|
|
|
|
// Improved at least two argument positions. Do it.
|
|
|
|
List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
|
|
|
|
Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
|
|
|
|
MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
|
|
|
|
MethodHandle nextTarget
|
2011-03-18 00:03:24 -07:00
|
|
|
= AdapterMethodHandle.makeRotateArguments(rotType, target,
|
2010-01-07 16:16:45 -08:00
|
|
|
rotBeg, rotSpan.size(), rotBy);
|
|
|
|
if (nextTarget != null) {
|
|
|
|
//System.out.println("Rot: "+rotSpan+" by "+rotBy);
|
|
|
|
target = nextTarget;
|
|
|
|
oldType = rotType;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Else de-rotate, and drop through to the swap-fest.
|
|
|
|
Collections.rotate(rotSpan, rotBy);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now swap like the wind!
|
|
|
|
List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
// What argument do I want here?
|
|
|
|
int arg = goal.get(i);
|
|
|
|
if (arg != state.get(i)) {
|
|
|
|
// Where is it now?
|
|
|
|
int j = state.indexOf(arg);
|
|
|
|
Collections.swap(ptypes, i, j);
|
|
|
|
MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
|
2011-03-18 00:03:24 -07:00
|
|
|
target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
|
2010-01-07 16:16:45 -08:00
|
|
|
if (target == null) throw newIllegalArgumentException("cannot swap");
|
|
|
|
assert(target.type() == swapType);
|
|
|
|
oldType = swapType;
|
|
|
|
Collections.swap(state, i, j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// One pass of swapping must finish the job.
|
|
|
|
assert(state.equals(goal));
|
|
|
|
}
|
|
|
|
while (!dups.isEmpty()) {
|
|
|
|
// Grab a contiguous trailing sequence of dups.
|
|
|
|
int grab = dups.size() - 1;
|
|
|
|
int dupArgPos = dups.get(grab), dupArgCount = 1;
|
|
|
|
while (grab - 1 >= 0) {
|
|
|
|
int dup0 = dups.get(grab - 1);
|
|
|
|
if (dup0 != dupArgPos - 1) break;
|
|
|
|
dupArgPos -= 1;
|
|
|
|
dupArgCount += 1;
|
|
|
|
grab -= 1;
|
|
|
|
}
|
|
|
|
//if (dupArgCount > 1) System.out.println("Dup: "+dups.subList(grab, dups.size()));
|
|
|
|
dups.subList(grab, dups.size()).clear();
|
|
|
|
// In the new target type drop that many args from the tail:
|
|
|
|
List<Class<?>> ptypes = oldType.parameterList();
|
|
|
|
ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
|
|
|
|
MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
|
2011-03-18 00:03:24 -07:00
|
|
|
target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
|
2010-01-07 16:16:45 -08:00
|
|
|
if (target == null)
|
|
|
|
throw newIllegalArgumentException("cannot dup");
|
|
|
|
oldType = target.type();
|
|
|
|
}
|
|
|
|
while (!drops.isEmpty()) {
|
|
|
|
// Grab a contiguous initial sequence of drops.
|
|
|
|
int dropArgPos = drops.get(0), dropArgCount = 1;
|
|
|
|
while (dropArgCount < drops.size()) {
|
|
|
|
int drop1 = drops.get(dropArgCount);
|
|
|
|
if (drop1 != dropArgPos + dropArgCount) break;
|
|
|
|
dropArgCount += 1;
|
|
|
|
}
|
|
|
|
//if (dropArgCount > 1) System.out.println("Drop: "+drops.subList(0, dropArgCount));
|
|
|
|
drops.subList(0, dropArgCount).clear();
|
|
|
|
List<Class<?>> dropTypes = newType.parameterList()
|
|
|
|
.subList(dropArgPos, dropArgPos + dropArgCount);
|
|
|
|
MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
|
2011-03-18 00:03:24 -07:00
|
|
|
target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
|
2010-01-07 16:16:45 -08:00
|
|
|
if (target == null) throw newIllegalArgumentException("cannot drop");
|
|
|
|
oldType = target.type();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (newType == oldType)
|
|
|
|
return target;
|
|
|
|
if (oldType.parameterCount() != newType.parameterCount())
|
|
|
|
throw newIllegalArgumentException("mismatched parameter count");
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle res = AdapterMethodHandle.makePairwiseConvert(newType, target);
|
2009-05-05 22:40:09 -07:00
|
|
|
if (res != null)
|
|
|
|
return res;
|
|
|
|
int argc = oldType.parameterCount();
|
|
|
|
// The JVM can't do it directly, so fill in the gap with a Java adapter.
|
|
|
|
// TO DO: figure out what to put here from case-by-case experience
|
|
|
|
// Use a heavier method: Convert all the arguments to Object,
|
|
|
|
// then back to the desired types. We might have to use Java-based
|
|
|
|
// method handles to do this.
|
2010-01-07 16:16:45 -08:00
|
|
|
MethodType objType = MethodType.genericMethodType(argc);
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(objType, target);
|
2009-05-05 22:40:09 -07:00
|
|
|
if (objTarget == null)
|
|
|
|
objTarget = FromGeneric.make(target);
|
2011-03-18 00:03:24 -07:00
|
|
|
res = AdapterMethodHandle.makePairwiseConvert(newType, objTarget);
|
2009-05-05 22:40:09 -07:00
|
|
|
if (res != null)
|
|
|
|
return res;
|
|
|
|
return ToGeneric.make(newType, objTarget);
|
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static MethodHandle spreadArguments(MethodHandle target,
|
2009-05-05 22:40:09 -07:00
|
|
|
MethodType newType,
|
|
|
|
int spreadArg) {
|
|
|
|
// TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
|
|
|
|
MethodType oldType = target.type();
|
|
|
|
// spread the last argument of newType to oldType
|
|
|
|
int spreadCount = oldType.parameterCount() - spreadArg;
|
|
|
|
Class<Object[]> spreadArgType = Object[].class;
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, spreadArgType, spreadArg, spreadCount);
|
2009-05-05 22:40:09 -07:00
|
|
|
if (res != null)
|
|
|
|
return res;
|
|
|
|
// try an intermediate adapter
|
|
|
|
Class<?> spreadType = null;
|
|
|
|
if (spreadArg < 0 || spreadArg >= newType.parameterCount()
|
|
|
|
|| !VerifyType.isSpreadArgType(spreadType = newType.parameterType(spreadArg)))
|
|
|
|
throw newIllegalArgumentException("no restarg in "+newType);
|
|
|
|
Class<?>[] ptypes = oldType.parameterArray();
|
|
|
|
for (int i = 0; i < spreadCount; i++)
|
|
|
|
ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
|
2010-01-07 16:16:45 -08:00
|
|
|
MethodType midType = MethodType.methodType(newType.returnType(), ptypes);
|
2009-05-05 22:40:09 -07:00
|
|
|
// after spreading, some arguments may need further conversion
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle target2 = convertArguments(target, midType, oldType, null);
|
2010-01-07 16:16:45 -08:00
|
|
|
if (target2 == null)
|
2009-05-05 22:40:09 -07:00
|
|
|
throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType);
|
2011-03-18 00:03:24 -07:00
|
|
|
res = AdapterMethodHandle.makeSpreadArguments(newType, target2, spreadArgType, spreadArg, spreadCount);
|
2010-01-07 16:16:45 -08:00
|
|
|
if (res != null)
|
|
|
|
return res;
|
|
|
|
res = SpreadGeneric.make(target2, spreadCount);
|
|
|
|
if (res != null)
|
2011-03-18 00:03:24 -07:00
|
|
|
res = convertArguments(res, newType, res.type(), null);
|
2009-05-05 22:40:09 -07:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static MethodHandle collectArguments(MethodHandle target,
|
2009-05-05 22:40:09 -07:00
|
|
|
MethodType newType,
|
2010-01-07 16:16:45 -08:00
|
|
|
int collectArg,
|
|
|
|
MethodHandle collector) {
|
|
|
|
MethodType oldType = target.type(); // (a...,c)=>r
|
|
|
|
if (collector == null) {
|
|
|
|
int numCollect = newType.parameterCount() - oldType.parameterCount() + 1;
|
|
|
|
collector = ValueConversions.varargsArray(numCollect);
|
|
|
|
}
|
|
|
|
// newType // (a..., b...)=>r
|
|
|
|
MethodType colType = collector.type(); // (b...)=>c
|
|
|
|
// oldType // (a..., b...)=>r
|
|
|
|
assert(newType.parameterCount() == collectArg + colType.parameterCount());
|
|
|
|
assert(oldType.parameterCount() == collectArg + 1);
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
|
|
|
|
MethodHandle gcollector = convertArguments(collector, colType.generic(), colType, null);
|
2010-01-07 16:16:45 -08:00
|
|
|
if (gtarget == null || gcollector == null) return null;
|
|
|
|
MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget);
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
|
2010-01-07 16:16:45 -08:00
|
|
|
return result;
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
2010-01-07 16:16:45 -08:00
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static MethodHandle filterArgument(MethodHandle target,
|
2010-01-07 16:16:45 -08:00
|
|
|
int pos,
|
|
|
|
MethodHandle filter) {
|
|
|
|
MethodType ttype = target.type(), gttype = ttype.generic();
|
|
|
|
if (ttype != gttype) {
|
2011-03-18 00:03:24 -07:00
|
|
|
target = convertArguments(target, gttype, ttype, null);
|
2010-01-07 16:16:45 -08:00
|
|
|
ttype = gttype;
|
|
|
|
}
|
|
|
|
MethodType ftype = filter.type(), gftype = ftype.generic();
|
|
|
|
if (ftype.parameterCount() != 1)
|
|
|
|
throw new InternalError();
|
|
|
|
if (ftype != gftype) {
|
2011-03-18 00:03:24 -07:00
|
|
|
filter = convertArguments(filter, gftype, ftype, null);
|
2010-01-07 16:16:45 -08:00
|
|
|
ftype = gftype;
|
|
|
|
}
|
|
|
|
if (ftype == ttype) {
|
|
|
|
// simple unary case
|
|
|
|
return FilterOneArgument.make(filter, target);
|
|
|
|
}
|
|
|
|
return FilterGeneric.makeArgumentFilter(pos, filter, target);
|
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static MethodHandle foldArguments(MethodHandle target,
|
2010-01-07 16:16:45 -08:00
|
|
|
MethodType newType,
|
|
|
|
MethodHandle combiner) {
|
|
|
|
MethodType oldType = target.type();
|
|
|
|
MethodType ctype = combiner.type();
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
|
|
|
|
MethodHandle gcombiner = convertArguments(combiner, ctype.generic(), ctype, null);
|
2010-01-07 16:16:45 -08:00
|
|
|
if (gtarget == null || gcombiner == null) return null;
|
|
|
|
MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget);
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
|
2010-01-07 16:16:45 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static
|
|
|
|
MethodHandle dropArguments(MethodHandle target,
|
2009-05-05 22:40:09 -07:00
|
|
|
MethodType newType, int argnum) {
|
2010-01-07 16:16:45 -08:00
|
|
|
int drops = newType.parameterCount() - target.type().parameterCount();
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle res = AdapterMethodHandle.makeDropArguments(newType, target, argnum, drops);
|
2010-01-07 16:16:45 -08:00
|
|
|
if (res != null)
|
|
|
|
return res;
|
2009-05-05 22:40:09 -07:00
|
|
|
throw new UnsupportedOperationException("NYI");
|
|
|
|
}
|
|
|
|
|
2010-10-30 21:08:23 -07:00
|
|
|
private static class GuardWithTest extends BoundMethodHandle {
|
2010-01-07 16:16:45 -08:00
|
|
|
private final MethodHandle test, target, fallback;
|
2010-04-30 23:48:23 -07:00
|
|
|
private GuardWithTest(MethodHandle invoker,
|
|
|
|
MethodHandle test, MethodHandle target, MethodHandle fallback) {
|
2011-03-18 00:03:24 -07:00
|
|
|
super(invoker);
|
2010-01-07 16:16:45 -08:00
|
|
|
this.test = test;
|
|
|
|
this.target = target;
|
|
|
|
this.fallback = fallback;
|
|
|
|
}
|
2011-03-18 00:03:24 -07:00
|
|
|
static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
|
2010-04-30 23:48:23 -07:00
|
|
|
MethodType type = target.type();
|
|
|
|
int nargs = type.parameterCount();
|
|
|
|
if (nargs < INVOKES.length) {
|
|
|
|
MethodHandle invoke = INVOKES[nargs];
|
|
|
|
MethodType gtype = type.generic();
|
|
|
|
assert(invoke.type().dropParameterTypes(0,1) == gtype);
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), null);
|
|
|
|
MethodHandle gtarget = convertArguments(target, gtype, type, null);
|
|
|
|
MethodHandle gfallback = convertArguments(fallback, gtype, type, null);
|
2010-04-30 23:48:23 -07:00
|
|
|
if (gtest == null || gtarget == null || gfallback == null) return null;
|
|
|
|
MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
|
2011-03-18 00:03:24 -07:00
|
|
|
return convertArguments(gguard, type, gtype, null);
|
2010-04-30 23:48:23 -07:00
|
|
|
} else {
|
|
|
|
MethodHandle invoke = VARARGS_INVOKE;
|
|
|
|
MethodType gtype = MethodType.genericMethodType(1);
|
|
|
|
assert(invoke.type().dropParameterTypes(0,1) == gtype);
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle gtest = spreadArguments(test, gtype.changeReturnType(boolean.class), 0);
|
|
|
|
MethodHandle gtarget = spreadArguments(target, gtype, 0);
|
|
|
|
MethodHandle gfallback = spreadArguments(fallback, gtype, 0);
|
2010-04-30 23:48:23 -07:00
|
|
|
MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
|
|
|
|
if (gtest == null || gtarget == null || gfallback == null) return null;
|
2011-03-18 00:03:24 -07:00
|
|
|
return collectArguments(gguard, type, 0, null);
|
2010-04-30 23:48:23 -07:00
|
|
|
}
|
|
|
|
}
|
2010-01-07 16:16:45 -08:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
2010-10-30 21:08:23 -07:00
|
|
|
return addTypeString(target, this);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_V(Object... av) throws Throwable {
|
2010-11-22 22:41:31 -08:00
|
|
|
if ((boolean) test.invokeExact(av))
|
|
|
|
return target.invokeExact(av);
|
|
|
|
return fallback.invokeExact(av);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_L0() throws Throwable {
|
2010-11-22 22:41:31 -08:00
|
|
|
if ((boolean) test.invokeExact())
|
|
|
|
return target.invokeExact();
|
|
|
|
return fallback.invokeExact();
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_L1(Object a0) throws Throwable {
|
2010-11-22 22:41:31 -08:00
|
|
|
if ((boolean) test.invokeExact(a0))
|
|
|
|
return target.invokeExact(a0);
|
|
|
|
return fallback.invokeExact(a0);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_L2(Object a0, Object a1) throws Throwable {
|
2010-11-22 22:41:31 -08:00
|
|
|
if ((boolean) test.invokeExact(a0, a1))
|
|
|
|
return target.invokeExact(a0, a1);
|
|
|
|
return fallback.invokeExact(a0, a1);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
2010-11-22 22:41:31 -08:00
|
|
|
if ((boolean) test.invokeExact(a0, a1, a2))
|
|
|
|
return target.invokeExact(a0, a1, a2);
|
|
|
|
return fallback.invokeExact(a0, a1, a2);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
2010-11-22 22:41:31 -08:00
|
|
|
if ((boolean) test.invokeExact(a0, a1, a2, a3))
|
|
|
|
return target.invokeExact(a0, a1, a2, a3);
|
|
|
|
return fallback.invokeExact(a0, a1, a2, a3);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
2010-11-22 22:41:31 -08:00
|
|
|
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4))
|
|
|
|
return target.invokeExact(a0, a1, a2, a3, a4);
|
|
|
|
return fallback.invokeExact(a0, a1, a2, a3, a4);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
2010-11-22 22:41:31 -08:00
|
|
|
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5))
|
|
|
|
return target.invokeExact(a0, a1, a2, a3, a4, a5);
|
|
|
|
return fallback.invokeExact(a0, a1, a2, a3, a4, a5);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
2010-11-22 22:41:31 -08:00
|
|
|
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5, a6))
|
|
|
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
|
|
|
|
return fallback.invokeExact(a0, a1, a2, a3, a4, a5, a6);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
2010-11-22 22:41:31 -08:00
|
|
|
if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7))
|
|
|
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
|
|
|
|
return fallback.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
static MethodHandle[] makeInvokes() {
|
|
|
|
ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
|
|
|
|
MethodHandles.Lookup lookup = IMPL_LOOKUP;
|
|
|
|
for (;;) {
|
|
|
|
int nargs = invokes.size();
|
|
|
|
String name = "invoke_L"+nargs;
|
|
|
|
MethodHandle invoke = null;
|
|
|
|
try {
|
|
|
|
invoke = lookup.findVirtual(GuardWithTest.class, name, MethodType.genericMethodType(nargs));
|
2011-02-11 01:26:32 -08:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
if (invoke == null) break;
|
|
|
|
invokes.add(invoke);
|
|
|
|
}
|
|
|
|
assert(invokes.size() == 9); // current number of methods
|
|
|
|
return invokes.toArray(new MethodHandle[0]);
|
|
|
|
};
|
|
|
|
static final MethodHandle[] INVOKES = makeInvokes();
|
|
|
|
// For testing use this:
|
|
|
|
//static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
|
|
|
|
static final MethodHandle VARARGS_INVOKE;
|
|
|
|
static {
|
|
|
|
try {
|
|
|
|
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithTest.class, "invoke_V", MethodType.genericMethodType(0, true));
|
2011-02-11 01:26:32 -08:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2010-09-08 18:40:23 -07:00
|
|
|
throw uncaughtException(ex);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static
|
|
|
|
MethodHandle makeGuardWithTest(MethodHandle test,
|
2010-01-07 16:16:45 -08:00
|
|
|
MethodHandle target,
|
|
|
|
MethodHandle fallback) {
|
2011-03-18 00:03:24 -07:00
|
|
|
return GuardWithTest.make(test, target, fallback);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
|
2010-10-30 21:08:23 -07:00
|
|
|
private static class GuardWithCatch extends BoundMethodHandle {
|
2010-01-07 16:16:45 -08:00
|
|
|
private final MethodHandle target;
|
|
|
|
private final Class<? extends Throwable> exType;
|
|
|
|
private final MethodHandle catcher;
|
2011-03-18 00:03:24 -07:00
|
|
|
GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
|
2010-01-07 16:16:45 -08:00
|
|
|
this(INVOKES[target.type().parameterCount()], target, exType, catcher);
|
|
|
|
}
|
2011-03-18 00:03:24 -07:00
|
|
|
GuardWithCatch(MethodHandle invoker,
|
|
|
|
MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
|
|
|
|
super(invoker);
|
2010-01-07 16:16:45 -08:00
|
|
|
this.target = target;
|
|
|
|
this.exType = exType;
|
|
|
|
this.catcher = catcher;
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
2010-10-30 21:08:23 -07:00
|
|
|
return addTypeString(target, this);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_V(Object... av) throws Throwable {
|
|
|
|
try {
|
2010-11-22 22:41:31 -08:00
|
|
|
return target.invokeExact(av);
|
2010-01-07 16:16:45 -08:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (!exType.isInstance(t)) throw t;
|
2010-11-22 22:41:31 -08:00
|
|
|
return catcher.invokeExact(t, av);
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
private Object invoke_L0() throws Throwable {
|
|
|
|
try {
|
2010-11-22 22:41:31 -08:00
|
|
|
return target.invokeExact();
|
2010-01-07 16:16:45 -08:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (!exType.isInstance(t)) throw t;
|
2010-11-22 22:41:31 -08:00
|
|
|
return catcher.invokeExact(t);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private Object invoke_L1(Object a0) throws Throwable {
|
|
|
|
try {
|
2010-11-22 22:41:31 -08:00
|
|
|
return target.invokeExact(a0);
|
2010-01-07 16:16:45 -08:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (!exType.isInstance(t)) throw t;
|
2010-11-22 22:41:31 -08:00
|
|
|
return catcher.invokeExact(t, a0);
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
|
|
|
}
|
2010-01-07 16:16:45 -08:00
|
|
|
private Object invoke_L2(Object a0, Object a1) throws Throwable {
|
|
|
|
try {
|
2010-11-22 22:41:31 -08:00
|
|
|
return target.invokeExact(a0, a1);
|
2010-01-07 16:16:45 -08:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (!exType.isInstance(t)) throw t;
|
2010-11-22 22:41:31 -08:00
|
|
|
return catcher.invokeExact(t, a0, a1);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
|
|
|
|
try {
|
2010-11-22 22:41:31 -08:00
|
|
|
return target.invokeExact(a0, a1, a2);
|
2010-01-07 16:16:45 -08:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (!exType.isInstance(t)) throw t;
|
2010-11-22 22:41:31 -08:00
|
|
|
return catcher.invokeExact(t, a0, a1, a2);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
|
|
|
|
try {
|
2010-11-22 22:41:31 -08:00
|
|
|
return target.invokeExact(a0, a1, a2, a3);
|
2010-01-07 16:16:45 -08:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (!exType.isInstance(t)) throw t;
|
2010-11-22 22:41:31 -08:00
|
|
|
return catcher.invokeExact(t, a0, a1, a2, a3);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
|
|
|
|
try {
|
2010-11-22 22:41:31 -08:00
|
|
|
return target.invokeExact(a0, a1, a2, a3, a4);
|
2010-01-07 16:16:45 -08:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (!exType.isInstance(t)) throw t;
|
2010-11-22 22:41:31 -08:00
|
|
|
return catcher.invokeExact(t, a0, a1, a2, a3, a4);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
|
|
|
|
try {
|
2010-11-22 22:41:31 -08:00
|
|
|
return target.invokeExact(a0, a1, a2, a3, a4, a5);
|
2010-01-07 16:16:45 -08:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (!exType.isInstance(t)) throw t;
|
2010-11-22 22:41:31 -08:00
|
|
|
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
|
|
|
|
try {
|
2010-11-22 22:41:31 -08:00
|
|
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
|
2010-01-07 16:16:45 -08:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (!exType.isInstance(t)) throw t;
|
2010-11-22 22:41:31 -08:00
|
|
|
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
|
|
|
|
try {
|
2010-11-22 22:41:31 -08:00
|
|
|
return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
|
2010-01-07 16:16:45 -08:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (!exType.isInstance(t)) throw t;
|
2010-11-22 22:41:31 -08:00
|
|
|
return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
static MethodHandle[] makeInvokes() {
|
|
|
|
ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
|
|
|
|
MethodHandles.Lookup lookup = IMPL_LOOKUP;
|
|
|
|
for (;;) {
|
|
|
|
int nargs = invokes.size();
|
|
|
|
String name = "invoke_L"+nargs;
|
|
|
|
MethodHandle invoke = null;
|
|
|
|
try {
|
|
|
|
invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs));
|
2011-02-11 01:26:32 -08:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
if (invoke == null) break;
|
|
|
|
invokes.add(invoke);
|
|
|
|
}
|
|
|
|
assert(invokes.size() == 9); // current number of methods
|
|
|
|
return invokes.toArray(new MethodHandle[0]);
|
|
|
|
};
|
|
|
|
static final MethodHandle[] INVOKES = makeInvokes();
|
|
|
|
// For testing use this:
|
|
|
|
//static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
|
|
|
|
static final MethodHandle VARARGS_INVOKE;
|
|
|
|
static {
|
|
|
|
try {
|
|
|
|
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
|
2011-02-11 01:26:32 -08:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2010-09-08 18:40:23 -07:00
|
|
|
throw uncaughtException(ex);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static
|
|
|
|
MethodHandle makeGuardWithCatch(MethodHandle target,
|
2010-01-07 16:16:45 -08:00
|
|
|
Class<? extends Throwable> exType,
|
|
|
|
MethodHandle catcher) {
|
|
|
|
MethodType type = target.type();
|
|
|
|
MethodType ctype = catcher.type();
|
|
|
|
int nargs = type.parameterCount();
|
|
|
|
if (nargs < GuardWithCatch.INVOKES.length) {
|
|
|
|
MethodType gtype = type.generic();
|
|
|
|
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle gtarget = convertArguments(target, gtype, type, null);
|
|
|
|
MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, null);
|
2010-01-07 16:16:45 -08:00
|
|
|
MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
|
|
|
|
if (gtarget == null || gcatcher == null || gguard == null) return null;
|
2011-03-18 00:03:24 -07:00
|
|
|
return convertArguments(gguard, type, gtype, null);
|
2010-01-07 16:16:45 -08:00
|
|
|
} else {
|
|
|
|
MethodType gtype = MethodType.genericMethodType(0, true);
|
|
|
|
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
|
2011-03-18 00:03:24 -07:00
|
|
|
MethodHandle gtarget = spreadArguments(target, gtype, 0);
|
|
|
|
MethodHandle gcatcher = spreadArguments(catcher, gcatchType, 1);
|
2010-01-07 16:16:45 -08:00
|
|
|
MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
|
|
|
|
if (gtarget == null || gcatcher == null || gguard == null) return null;
|
2011-03-18 00:03:24 -07:00
|
|
|
return collectArguments(gguard, type, 0, null);
|
2010-01-07 16:16:45 -08:00
|
|
|
}
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static
|
|
|
|
MethodHandle throwException(MethodType type) {
|
|
|
|
return AdapterMethodHandle.makeRetypeRaw(type, throwException());
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static MethodHandle THROW_EXCEPTION;
|
|
|
|
static MethodHandle throwException() {
|
|
|
|
if (THROW_EXCEPTION != null) return THROW_EXCEPTION;
|
2010-09-08 18:40:23 -07:00
|
|
|
try {
|
|
|
|
THROW_EXCEPTION
|
2010-01-07 16:16:45 -08:00
|
|
|
= IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
|
|
|
|
MethodType.methodType(Empty.class, Throwable.class));
|
2011-02-11 01:26:32 -08:00
|
|
|
} catch (ReflectiveOperationException ex) {
|
2010-09-08 18:40:23 -07:00
|
|
|
throw new RuntimeException(ex);
|
|
|
|
}
|
2011-03-18 00:03:24 -07:00
|
|
|
return THROW_EXCEPTION;
|
2010-09-08 18:40:23 -07:00
|
|
|
}
|
2010-01-07 16:16:45 -08:00
|
|
|
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
|
|
|
|
|
2010-04-30 23:48:23 -07:00
|
|
|
// Linkage support:
|
2011-03-18 00:03:24 -07:00
|
|
|
static void registerBootstrap(Class<?> callerClass, MethodHandle bootstrapMethod) {
|
2010-04-30 23:48:23 -07:00
|
|
|
MethodHandleNatives.registerBootstrap(callerClass, bootstrapMethod);
|
|
|
|
}
|
2011-03-18 00:03:24 -07:00
|
|
|
static MethodHandle getBootstrap(Class<?> callerClass) {
|
2010-04-30 23:48:23 -07:00
|
|
|
return MethodHandleNatives.getBootstrap(callerClass);
|
|
|
|
}
|
2010-10-30 21:02:30 -07:00
|
|
|
|
2011-03-18 00:03:24 -07:00
|
|
|
static MethodHandle asVarargsCollector(MethodHandle target, Class<?> arrayType) {
|
|
|
|
return AdapterMethodHandle.makeVarargsCollector(target, arrayType);
|
2010-10-30 21:02:30 -07:00
|
|
|
}
|
2009-05-05 22:40:09 -07:00
|
|
|
}
|