提交 50e98779 编写于 作者: V vlivanov

8050166: Get rid of some package-private methods on arguments in j.l.i.MethodHandle

Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
上级 6be16bf0
......@@ -60,13 +60,12 @@ import jdk.internal.org.objectweb.asm.Type;
// BMH API and internals
//
static MethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
// for some type signatures, there exist pre-defined concrete BMH classes
try {
switch (xtype) {
case L_TYPE:
if (true) return bindSingle(type, form, x); // Use known fast path.
return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor().invokeBasic(type, form, x);
return bindSingle(type, form, x); // Use known fast path.
case I_TYPE:
return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor().invokeBasic(type, form, ValueConversions.widenSubword(x));
case J_TYPE:
......@@ -82,49 +81,40 @@ import jdk.internal.org.objectweb.asm.Type;
}
}
static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
return new Species_L(type, form, x);
static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
return Species_L.make(type, form, x);
}
MethodHandle cloneExtend(MethodType type, LambdaForm form, BasicType xtype, Object x) {
try {
switch (xtype) {
case L_TYPE: return copyWithExtendL(type, form, x);
case I_TYPE: return copyWithExtendI(type, form, ValueConversions.widenSubword(x));
case J_TYPE: return copyWithExtendJ(type, form, (long) x);
case F_TYPE: return copyWithExtendF(type, form, (float) x);
case D_TYPE: return copyWithExtendD(type, form, (double) x);
}
} catch (Throwable t) {
throw newInternalError(t);
}
throw newInternalError("unexpected type: " + xtype);
@Override // there is a default binder in the super class, for 'L' types only
/*non-public*/
BoundMethodHandle bindArgumentL(int pos, Object value) {
MethodType type = type().dropParameterTypes(pos, pos+1);
LambdaForm form = internalForm().bind(1+pos, speciesData());
return copyWithExtendL(type, form, value);
}
@Override
MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
/*non-public*/
BoundMethodHandle bindArgumentI(int pos, int value) {
MethodType type = type().dropParameterTypes(pos, pos+1);
LambdaForm form = internalForm().bind(1+pos, speciesData());
return cloneExtend(type, form, basicType, value);
return copyWithExtendI(type, form, value);
}
@Override
MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos + drops));
try {
return copyWith(srcType, form);
} catch (Throwable t) {
throw newInternalError(t);
}
/*non-public*/
BoundMethodHandle bindArgumentJ(int pos, long value) {
MethodType type = type().dropParameterTypes(pos, pos+1);
LambdaForm form = internalForm().bind(1+pos, speciesData());
return copyWithExtendJ(type, form, value);
}
@Override
MethodHandle permuteArguments(MethodType newType, int[] reorder) {
try {
return copyWith(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
} catch (Throwable t) {
throw newInternalError(t);
}
/*non-public*/
BoundMethodHandle bindArgumentF(int pos, float value) {
MethodType type = type().dropParameterTypes(pos, pos+1);
LambdaForm form = internalForm().bind(1+pos, speciesData());
return copyWithExtendF(type, form, value);
}
/*non-public*/
BoundMethodHandle bindArgumentD(int pos, double value) {
MethodType type = type().dropParameterTypes(pos, pos + 1);
LambdaForm form = internalForm().bind(1+pos, speciesData());
return copyWithExtendD(type, form, value);
}
/**
......
......@@ -211,7 +211,7 @@ public class CallSite {
public abstract MethodHandle dynamicInvoker();
/*non-public*/ MethodHandle makeDynamicInvoker() {
MethodHandle getTarget = GET_TARGET.bindReceiver(this);
MethodHandle getTarget = GET_TARGET.bindArgumentL(0, this);
MethodHandle invoker = MethodHandles.exactInvoker(this.type());
return MethodHandles.foldArguments(invoker, getTarget);
}
......
......@@ -142,45 +142,8 @@ class DirectMethodHandle extends MethodHandle {
return member;
}
@Override
MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
// If the member needs dispatching, do so.
if (pos == 0 && basicType == L_TYPE) {
DirectMethodHandle concrete = maybeRebind(value);
if (concrete != null)
return concrete.bindReceiver(value);
}
return super.bindArgument(pos, basicType, value);
}
@Override
MethodHandle bindReceiver(Object receiver) {
// If the member needs dispatching, do so.
DirectMethodHandle concrete = maybeRebind(receiver);
if (concrete != null)
return concrete.bindReceiver(receiver);
return super.bindReceiver(receiver);
}
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
private DirectMethodHandle maybeRebind(Object receiver) {
if (receiver != null) {
switch (member.getReferenceKind()) {
case REF_invokeInterface:
case REF_invokeVirtual:
// Pre-dispatch the member.
Class<?> concreteClass = receiver.getClass();
MemberName concrete = new MemberName(concreteClass, member.getName(), member.getMethodType(), REF_invokeSpecial);
concrete = IMPL_NAMES.resolveOrNull(REF_invokeSpecial, concrete, concreteClass);
if (concrete != null)
return new DirectMethodHandle(type(), preparedLambdaForm(concrete), concrete);
break;
}
}
return null;
}
/**
* Create a LF which can invoke the given method.
* Cache and share this structure among all methods with
......
......@@ -774,7 +774,7 @@ public abstract class MethodHandle {
/*non-public*/ MethodHandle asTypeUncached(MethodType newType) {
if (!type.isConvertibleTo(newType))
throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
return asTypeCache = convertArguments(newType);
return asTypeCache = MethodHandleImpl.makePairwiseConvert(this, newType, 1);
}
/**
......@@ -987,7 +987,7 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123));
int collectArgPos = type().parameterCount()-1;
MethodHandle target = this;
if (arrayType != type().parameterType(collectArgPos))
target = convertArguments(type().changeParameterType(collectArgPos, arrayType));
target = MethodHandleImpl.makePairwiseConvert(this, type().changeParameterType(collectArgPos, arrayType), 1);
MethodHandle collector = MethodHandleImpl.varargsArray(arrayType, arrayLength);
return MethodHandles.collectArguments(target, collectArgPos, collector);
}
......@@ -1260,14 +1260,8 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
* @see MethodHandles#insertArguments
*/
public MethodHandle bindTo(Object x) {
Class<?> ptype;
@SuppressWarnings("LocalVariableHidesMemberVariable")
MethodType type = type();
if (type.parameterCount() == 0 ||
(ptype = type.parameterType(0)).isPrimitive())
throw newIllegalArgumentException("no leading reference parameter", x);
x = ptype.cast(x); // throw CCE if needed
return bindReceiver(x);
x = type.leadingReferenceParameter().cast(x); // throw CCE if needed
return bindArgumentL(0, x);
}
/**
......@@ -1306,6 +1300,10 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
// Other transforms to do: convert, explicitCast, permute, drop, filter, fold, GWT, catch
BoundMethodHandle bindArgumentL(int pos, Object value) {
return rebind().bindArgumentL(pos, value);
}
/*non-public*/
MethodHandle setVarargs(MemberName member) throws IllegalAccessException {
if (!member.isVarargs()) return this;
......@@ -1374,37 +1372,8 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
//// Sub-classes can override these default implementations.
//// All these methods assume arguments are already validated.
/*non-public*/ MethodHandle convertArguments(MethodType newType) {
// Override this if it can be improved.
return MethodHandleImpl.makePairwiseConvert(this, newType, 1);
}
/*non-public*/
MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
// Override this if it can be improved.
return rebind().bindArgument(pos, basicType, value);
}
/*non-public*/
MethodHandle bindReceiver(Object receiver) {
// Override this if it can be improved.
return bindArgument(0, L_TYPE, receiver);
}
/*non-public*/
MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
// Override this if it can be improved.
return rebind().dropArguments(srcType, pos, drops);
}
/*non-public*/
MethodHandle permuteArguments(MethodType newType, int[] reorder) {
// Override this if it can be improved.
return rebind().permuteArguments(newType, reorder);
}
/*non-public*/
MethodHandle rebind() {
BoundMethodHandle rebind() {
// Bind 'this' into a new invoker, of the known class BMH.
MethodType type2 = type();
LambdaForm form2 = reinvokerForm(this);
......
......@@ -434,27 +434,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
boolean isInvokeSpecial() {
return asFixedArity().isInvokeSpecial();
}
@Override
MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
return asFixedArity().bindArgument(pos, basicType, value);
}
@Override
MethodHandle bindReceiver(Object receiver) {
return asFixedArity().bindReceiver(receiver);
}
@Override
MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
return asFixedArity().dropArguments(srcType, pos, drops);
}
@Override
MethodHandle permuteArguments(MethodType newType, int[] reorder) {
return asFixedArity().permuteArguments(newType, reorder);
}
}
/** Factory method: Spread selected argument. */
......@@ -794,7 +773,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
int arity = type.parameterCount();
if (arity > 1) {
return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
MethodHandle mh = throwException(type.dropParameterTypes(1, arity));
mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
return mh;
}
return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2);
}
......
......@@ -26,6 +26,7 @@
package java.lang.invoke;
import java.lang.reflect.*;
import java.util.BitSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -1144,7 +1145,7 @@ return mh1;
Class<? extends Object> refc = receiver.getClass(); // may get NPE
MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
return mh.bindReceiver(receiver).setVarargs(method);
return mh.bindArgumentL(0, receiver).setVarargs(method);
}
/**
......@@ -2087,11 +2088,55 @@ assert((int)twice.invokeExact(21) == 42);
public static
MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
reorder = reorder.clone();
checkReorder(reorder, newType, target.type());
return target.permuteArguments(newType, reorder);
permuteArgumentChecks(reorder, newType, target.type());
// first detect dropped arguments and handle them separately
MethodHandle originalTarget = target;
int newArity = newType.parameterCount();
for (int dropIdx; (dropIdx = findFirstDrop(reorder, newArity)) >= 0; ) {
// dropIdx is missing from reorder; add it in at the end
int oldArity = reorder.length;
target = dropArguments(target, oldArity, newType.parameterType(dropIdx));
reorder = Arrays.copyOf(reorder, oldArity+1);
reorder[oldArity] = dropIdx;
}
assert(target == originalTarget || permuteArgumentChecks(reorder, newType, target.type()));
// Note: This may cache too many distinct LFs. Consider backing off to varargs code.
BoundMethodHandle result = target.rebind();
LambdaForm form = result.form.permuteArguments(1, reorder, basicTypes(newType.parameterList()));
return result.copyWith(newType, form);
}
private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) {
/** Return the first value in [0..newArity-1] that is not present in reorder. */
private static int findFirstDrop(int[] reorder, int newArity) {
final int BIT_LIMIT = 63; // max number of bits in bit mask
if (newArity < BIT_LIMIT) {
long mask = 0;
for (int arg : reorder) {
assert(arg < newArity);
mask |= (1 << arg);
}
if (mask == (1 << newArity) - 1) {
assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity);
return -1;
}
// find first zero
long zeroBit = Long.lowestOneBit(~mask);
int zeroPos = Long.numberOfTrailingZeros(zeroBit);
assert(zeroPos < newArity);
return zeroPos;
}
BitSet mask = new BitSet(newArity);
for (int arg : reorder) {
assert(arg < newArity);
mask.set(arg);
}
int zeroPos = mask.nextClearBit(0);
if (zeroPos == newArity)
return -1;
return zeroPos;
}
private static boolean permuteArgumentChecks(int[] reorder, MethodType newType, MethodType oldType) {
if (newType.returnType() != oldType.returnType())
throw newIllegalArgumentException("return types do not match",
oldType, newType);
......@@ -2109,7 +2154,7 @@ assert((int)twice.invokeExact(21) == 42);
throw newIllegalArgumentException("parameter types do not match after reorder",
oldType, newType);
}
if (!bad) return;
if (!bad) return true;
}
throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder));
}
......@@ -2193,40 +2238,47 @@ assert((int)twice.invokeExact(21) == 42);
public static
MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
int insCount = values.length;
MethodType oldType = target.type();
int outargs = oldType.parameterCount();
int inargs = outargs - insCount;
if (inargs < 0)
throw newIllegalArgumentException("too many values to insert");
if (pos < 0 || pos > inargs)
throw newIllegalArgumentException("no argument type to append");
MethodHandle result = target;
Class<?>[] ptypes = insertArgumentsChecks(target, insCount, pos);
if (insCount == 0) return target;
BoundMethodHandle result = target.rebind();
for (int i = 0; i < insCount; i++) {
Object value = values[i];
Class<?> ptype = oldType.parameterType(pos+i);
Class<?> ptype = ptypes[pos+i];
if (ptype.isPrimitive()) {
BasicType btype = I_TYPE;
Wrapper w = Wrapper.forPrimitiveType(ptype);
switch (w) {
case LONG: btype = J_TYPE; break;
case FLOAT: btype = F_TYPE; break;
case DOUBLE: btype = D_TYPE; break;
}
// perform unboxing and/or primitive conversion
value = w.convert(value, ptype);
result = result.bindArgument(pos, btype, value);
continue;
}
value = ptype.cast(value); // throw CCE if needed
if (pos == 0) {
result = result.bindReceiver(value);
result = insertArgumentPrimitive(result, pos, ptype, value);
} else {
result = result.bindArgument(pos, L_TYPE, value);
value = ptype.cast(value); // throw CCE if needed
result = result.bindArgumentL(pos, value);
}
}
return result;
}
private static BoundMethodHandle insertArgumentPrimitive(BoundMethodHandle result, int pos,
Class<?> ptype, Object value) {
Wrapper w = Wrapper.forPrimitiveType(ptype);
// perform unboxing and/or primitive conversion
value = w.convert(value, ptype);
switch (w) {
case INT: return result.bindArgumentI(pos, (int)value);
case LONG: return result.bindArgumentJ(pos, (long)value);
case FLOAT: return result.bindArgumentF(pos, (float)value);
case DOUBLE: return result.bindArgumentD(pos, (double)value);
default: return result.bindArgumentI(pos, ValueConversions.widenSubword(value));
}
}
private static Class<?>[] insertArgumentsChecks(MethodHandle target, int insCount, int pos) throws RuntimeException {
MethodType oldType = target.type();
int outargs = oldType.parameterCount();
int inargs = outargs - insCount;
if (inargs < 0)
throw newIllegalArgumentException("too many values to insert");
if (pos < 0 || pos > inargs)
throw newIllegalArgumentException("no argument type to append");
return oldType.ptypes();
}
/**
* Produces a method handle which will discard some dummy arguments
* before calling some other specified <i>target</i> method handle.
......@@ -2272,18 +2324,26 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
public static
MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
MethodType oldType = target.type(); // get NPE
int dropped = dropArgumentChecks(oldType, pos, valueTypes);
if (dropped == 0) return target;
BoundMethodHandle result = target.rebind();
LambdaForm lform = result.form;
lform = lform.addArguments(pos, valueTypes);
MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
result = result.copyWith(newType, lform);
return result;
}
private static int dropArgumentChecks(MethodType oldType, int pos, List<Class<?>> valueTypes) {
int dropped = valueTypes.size();
MethodType.checkSlotCount(dropped);
if (dropped == 0) return target;
int outargs = oldType.parameterCount();
int inargs = outargs + dropped;
if (pos < 0 || pos >= inargs)
throw newIllegalArgumentException("no argument type to remove");
ArrayList<Class<?>> ptypes = new ArrayList<>(oldType.parameterList());
ptypes.addAll(pos, valueTypes);
if (ptypes.size() != inargs) throw newIllegalArgumentException("valueTypes");
MethodType newType = MethodType.methodType(oldType.returnType(), ptypes);
return target.dropArguments(newType, pos, dropped);
if (pos < 0 || pos > outargs)
throw newIllegalArgumentException("no argument type to remove"
+ Arrays.asList(oldType, pos, valueTypes, inargs, outargs)
);
return dropped;
}
/**
......
......@@ -498,6 +498,17 @@ class MethodType implements java.io.Serializable {
return this; // arguments check out; no change
}
/** Return the leading parameter type, which must exist and be a reference.
* @return the leading parameter type, after error checks
*/
/*non-public*/ Class<?> leadingReferenceParameter() {
Class<?> ptype;
if (ptypes.length == 0 ||
(ptype = ptypes[0]).isPrimitive())
throw newIllegalArgumentException("no leading reference parameter");
return ptype;
}
/**
* Finds or creates a method type with some parameter types omitted.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
......
......@@ -25,9 +25,6 @@
package java.lang.invoke;
import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.LambdaForm.BasicType.*;
/**
* A method handle whose behavior is determined only by its LambdaForm.
* @author jrose
......@@ -40,23 +37,4 @@ final class SimpleMethodHandle extends MethodHandle {
/*non-public*/ static SimpleMethodHandle make(MethodType type, LambdaForm form) {
return new SimpleMethodHandle(type, form);
}
@Override
MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
MethodType type2 = type().dropParameterTypes(pos, pos+1);
LambdaForm form2 = internalForm().bind(1+pos, BoundMethodHandle.SpeciesData.EMPTY);
return BoundMethodHandle.bindSingle(type2, form2, basicType, value);
}
@Override
MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
LambdaForm newForm = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
return new SimpleMethodHandle(srcType, newForm);
}
@Override
MethodHandle permuteArguments(MethodType newType, int[] reorder) {
LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList()));
return new SimpleMethodHandle(newType, form2);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册