src/share/classes/java/lang/invoke/MethodHandleImpl.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
jdk Cdiff src/share/classes/java/lang/invoke/MethodHandleImpl.java
src/share/classes/java/lang/invoke/MethodHandleImpl.java
Print this page
rev 10271 : 8037209: Improvements and cleanups to bytecode assembly for lambda forms
Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
rev 10272 : 8038261: JSR292: cache and reuse typed array accessors
Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
rev 10273 : 8049555: Move varargsArray from sun.invoke.util package to java.lang.invoke
Reviewed-by: ?
rev 10274 : 8050052: Small cleanups in java.lang.invoke code
Reviewed-by: ?
rev 10276 : 8050166: Get rid of some package-private methods on arguments in j.l.i.MethodHandle
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10277 : 8050173: Add j.l.i.MethodHandle.copyWith(MethodType, LambdaForm)
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10278 : 8050174: Support overriding of isInvokeSpecial flag in WrappedMember
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10279 : 8050057: Improve caching of MethodHandle reinvokers
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10280 : 8050200: Make LambdaForm intrinsics detection more robust
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10281 : [mq]: 11.8050877.conv
*** 177,225 ****
* For each argument, convert incoming argument to the exact type needed.
* The argument conversions allowed are casting, boxing and unboxing,
* integral widening or narrowing, and floating point widening or narrowing.
* @param srcType required call type
* @param target original method handle
! * @param level which strength of conversion is allowed
* @return an adapter to the original handle with the desired new type,
* or the original target if the types are already identical
* or null if the adaptation cannot be made
*/
! static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
! assert(level >= 0 && level <= 2);
MethodType dstType = target.type();
assert(dstType.parameterCount() == target.type().parameterCount());
if (srcType == dstType)
return target;
! // Calculate extra arguments (temporaries) required in the names array.
! // FIXME: Use an ArrayList<Name>. Some arguments require more than one conversion step.
! final int INARG_COUNT = srcType.parameterCount();
! int conversions = 0;
! boolean[] needConv = new boolean[1+INARG_COUNT];
! for (int i = 0; i <= INARG_COUNT; i++) {
! Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
! Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
! if (!VerifyType.isNullConversion(src, dst, false) ||
! level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
! needConv[i] = true;
! conversions++;
}
}
! boolean retConv = needConv[INARG_COUNT];
! if (retConv && srcType.returnType() == void.class) {
retConv = false;
- conversions--;
}
final int IN_MH = 0;
final int INARG_BASE = 1;
final int INARG_LIMIT = INARG_BASE + INARG_COUNT;
! final int NAME_LIMIT = INARG_LIMIT + conversions + 1;
final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1);
final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
! final int RESULT = (srcType.returnType() == void.class ? -1 : NAME_LIMIT - 1);
// Now build a LambdaForm.
MethodType lambdaType = srcType.basicType().invokerType();
Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
--- 177,229 ----
* For each argument, convert incoming argument to the exact type needed.
* The argument conversions allowed are casting, boxing and unboxing,
* integral widening or narrowing, and floating point widening or narrowing.
* @param srcType required call type
* @param target original method handle
! * @param strict if true, only asType conversions are allowed; if false, explicitCastArguments conversions allowed
! * @param monobox if true, unboxing conversions are assumed to be exactly typed (Integer to int only, not long or double)
* @return an adapter to the original handle with the desired new type,
* or the original target if the types are already identical
* or null if the adaptation cannot be made
*/
! static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType,
! boolean strict, boolean monobox) {
MethodType dstType = target.type();
assert(dstType.parameterCount() == target.type().parameterCount());
if (srcType == dstType)
return target;
+ return makePairwiseConvertIndirect(target, srcType, strict, monobox);
+ }
! private static int countNonNull(Object[] array) {
! int count = 0;
! for (Object x : array) {
! if (x != null) ++count;
}
+ return count;
}
!
! static MethodHandle makePairwiseConvertIndirect(MethodHandle target, MethodType srcType,
! boolean strict, boolean monobox) {
! // Calculate extra arguments (temporaries) required in the names array.
! Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
! final int INARG_COUNT = srcType.parameterCount();
! int convCount = countNonNull(convSpecs);
! boolean retConv = (convSpecs[INARG_COUNT] != null);
! boolean retVoid = srcType.returnType() == void.class;
! if (retConv && retVoid) {
! convCount -= 1;
retConv = false;
}
final int IN_MH = 0;
final int INARG_BASE = 1;
final int INARG_LIMIT = INARG_BASE + INARG_COUNT;
! final int NAME_LIMIT = INARG_LIMIT + convCount + 1;
final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1);
final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
! final int RESULT = (retVoid ? -1 : NAME_LIMIT - 1);
// Now build a LambdaForm.
MethodType lambdaType = srcType.basicType().invokerType();
Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
*** 227,318 ****
final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0]
Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
int nameCursor = INARG_LIMIT;
for (int i = 0; i < INARG_COUNT; i++) {
! Class<?> src = srcType.parameterType(i);
! Class<?> dst = dstType.parameterType(i);
!
! if (!needConv[i]) {
// do nothing: difference is trivial
outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
continue;
}
! // Tricky case analysis follows.
! MethodHandle fn = null;
! if (src.isPrimitive()) {
! if (dst.isPrimitive()) {
! fn = ValueConversions.convertPrimitive(src, dst);
! } else {
! Wrapper w = Wrapper.forPrimitiveType(src);
! MethodHandle boxMethod = ValueConversions.box(w);
! if (dst == w.wrapperType())
! fn = boxMethod;
! else
! fn = boxMethod.asType(MethodType.methodType(dst, src));
! }
! } else {
! if (dst.isPrimitive()) {
! // Caller has boxed a primitive. Unbox it for the target.
! Wrapper w = Wrapper.forPrimitiveType(dst);
! if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType(), false)) {
! fn = ValueConversions.unbox(dst);
! } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
! // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
! // must include additional conversions
! // src must be examined at runtime, to detect Byte, Character, etc.
! MethodHandle unboxMethod = (level == 1
! ? ValueConversions.unbox(dst)
! : ValueConversions.unboxCast(dst));
! fn = unboxMethod;
} else {
! // Example: Byte->int
! // Do this by reformulating the problem to Byte->byte.
! Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
! MethodHandle unbox = ValueConversions.unbox(srcPrim);
! // Compose the two conversions. FIXME: should make two Names for this job
! fn = unbox.asType(MethodType.methodType(dst, src));
}
- } else {
- // Simple reference conversion.
- // Note: Do not check for a class hierarchy relation
- // between src and dst. In all cases a 'null' argument
- // will pass the cast conversion.
- fn = ValueConversions.cast(dst, Lazy.MH_castReference);
- }
- }
- Name conv = new Name(fn, names[INARG_BASE + i]);
assert(names[nameCursor] == null);
names[nameCursor++] = conv;
assert(outArgs[OUTARG_BASE + i] == null);
outArgs[OUTARG_BASE + i] = conv;
}
// Build argument array for the call.
assert(nameCursor == OUT_CALL);
names[OUT_CALL] = new Name(target, outArgs);
! if (RETURN_CONV < 0) {
assert(OUT_CALL == names.length-1);
} else {
! Class<?> needReturn = srcType.returnType();
! Class<?> haveReturn = dstType.returnType();
! MethodHandle fn;
! Object[] arg = { names[OUT_CALL] };
! if (haveReturn == void.class) {
! // synthesize a zero value for the given void
! Object zero = Wrapper.forBasicType(needReturn).zero();
! fn = MethodHandles.constant(needReturn, zero);
! arg = new Object[0]; // don't pass names[OUT_CALL] to conversion
} else {
! MethodHandle identity = MethodHandles.identity(needReturn);
! MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
! fn = makePairwiseConvert(identity, needConversion, level);
}
assert(names[RETURN_CONV] == null);
! names[RETURN_CONV] = new Name(fn, arg);
assert(RETURN_CONV == names.length-1);
}
LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
return SimpleMethodHandle.make(srcType, form);
--- 231,284 ----
final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0]
Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
int nameCursor = INARG_LIMIT;
for (int i = 0; i < INARG_COUNT; i++) {
! Object convSpec = convSpecs[i];
! if (convSpec == null) {
// do nothing: difference is trivial
outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
continue;
}
! Name conv;
! if (convSpec instanceof Class) {
! Class<?> convClass = (Class<?>) convSpec;
! conv = new Name(Lazy.MH_castReference, convClass, names[INARG_BASE + i]);
} else {
! MethodHandle fn = (MethodHandle) convSpec;
! conv = new Name(fn, names[INARG_BASE + i]);
}
assert(names[nameCursor] == null);
names[nameCursor++] = conv;
assert(outArgs[OUTARG_BASE + i] == null);
outArgs[OUTARG_BASE + i] = conv;
}
// Build argument array for the call.
assert(nameCursor == OUT_CALL);
names[OUT_CALL] = new Name(target, outArgs);
! Object convSpec = convSpecs[INARG_COUNT];
! if (!retConv) {
assert(OUT_CALL == names.length-1);
} else {
! Name conv;
! if (convSpec == void.class) {
! conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
! } else if (convSpec instanceof Class) {
! Class<?> convClass = (Class<?>) convSpec;
! conv = new Name(Lazy.MH_castReference, convClass, names[OUT_CALL]);
} else {
! MethodHandle fn = (MethodHandle) convSpec;
! if (fn.type().parameterCount() == 0)
! conv = new Name(fn); // don't pass retval to void conversion
! else
! conv = new Name(fn, names[OUT_CALL]);
}
assert(names[RETURN_CONV] == null);
! names[RETURN_CONV] = conv;
assert(RETURN_CONV == names.length-1);
}
LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
return SimpleMethodHandle.make(srcType, form);
*** 343,352 ****
--- 309,395 ----
names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
}
+ static Object[] computeValueConversions(MethodType srcType, MethodType dstType,
+ boolean strict, boolean monobox) {
+ final int INARG_COUNT = srcType.parameterCount();
+ Object[] convSpecs = new Object[INARG_COUNT+1];
+ for (int i = 0; i <= INARG_COUNT; i++) {
+ boolean isRet = (i == INARG_COUNT);
+ Class<?> src = isRet ? dstType.returnType() : srcType.parameterType(i);
+ Class<?> dst = isRet ? srcType.returnType() : dstType.parameterType(i);
+ if (!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)) {
+ convSpecs[i] = valueConversion(src, dst, strict, monobox);
+ }
+ }
+ return convSpecs;
+ }
+ static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType,
+ boolean strict) {
+ return makePairwiseConvert(target, srcType, strict, /*monobox=*/ false);
+ }
+
+ /**
+ * Find a conversion function from the given source to the given destination.
+ * This conversion function will be used as a LF NamedFunction.
+ * Return a Class object if a simple cast is needed.
+ * Return void.class if void is involved.
+ */
+ static Object valueConversion(Class<?> src, Class<?> dst, boolean strict, boolean monobox) {
+ assert(!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)); // caller responsibility
+ if (dst == void.class)
+ return dst;
+ MethodHandle fn;
+ if (src.isPrimitive()) {
+ if (src == void.class) {
+ return void.class; // caller must recognize this specially
+ } else if (dst.isPrimitive()) {
+ // Examples: int->byte, byte->int, boolean->int (!strict)
+ fn = ValueConversions.convertPrimitive(src, dst);
+ } else {
+ // Examples: int->Integer, boolean->Object, float->Number
+ Wrapper wsrc = Wrapper.forPrimitiveType(src);
+ fn = ValueConversions.boxExact(wsrc);
+ assert(fn.type().parameterType(0) == wsrc.primitiveType());
+ assert(fn.type().returnType() == wsrc.wrapperType());
+ if (!VerifyType.isNullConversion(wsrc.wrapperType(), dst, strict)) {
+ // Corner case, such as int->Long, which will probably fail.
+ MethodType mt = MethodType.methodType(dst, src);
+ if (strict)
+ fn = fn.asType(mt);
+ else
+ fn = MethodHandleImpl.makePairwiseConvert(fn, mt, /*strict=*/ false);
+ }
+ }
+ } else {
+ if (dst.isPrimitive()) {
+ Wrapper wdst = Wrapper.forPrimitiveType(dst);
+ if (monobox || src == wdst.wrapperType()) {
+ // Use a strongly-typed unboxer, if possible.
+ fn = ValueConversions.unboxExact(wdst, strict);
+ } else {
+ // Examples: Object->int, Number->int, Comparable->int, Byte->int
+ // must include additional conversions
+ // src must be examined at runtime, to detect Byte, Character, etc.
+ fn = (strict
+ ? ValueConversions.unboxWiden(wdst)
+ : ValueConversions.unboxCast(wdst));
+ }
+ } else {
+ // Simple reference conversion.
+ // Note: Do not check for a class hierarchy relation
+ // between src and dst. In all cases a 'null' argument
+ // will pass the cast conversion.
+ return dst;
+ }
+ }
+ assert(fn.type().parameterCount() <= 1) : "pc"+Arrays.asList(src.getSimpleName(), dst.getSimpleName(), fn);
+ return fn;
+ }
+
static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
MethodType type = target.type();
int last = type.parameterCount() - 1;
if (type.parameterType(last) != arrayType)
target = target.asType(type.changeParameterType(last, arrayType));
*** 718,731 ****
// Box arguments and wrap them into Object[]: ValueConversions.array().
MethodType varargsType = type.changeReturnType(Object[].class);
MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType);
// Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore().
MethodHandle unboxResult;
! if (type.returnType().isPrimitive()) {
! unboxResult = ValueConversions.unbox(type.returnType());
} else {
! unboxResult = ValueConversions.identity();
}
BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
BoundMethodHandle mh;
try {
--- 761,780 ----
// Box arguments and wrap them into Object[]: ValueConversions.array().
MethodType varargsType = type.changeReturnType(Object[].class);
MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType);
// Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore().
MethodHandle unboxResult;
! Class<?> rtype = type.returnType();
! if (rtype.isPrimitive()) {
! if (rtype == void.class) {
! unboxResult = ValueConversions.ignore();
! } else {
! Wrapper w = Wrapper.forPrimitiveType(type.returnType());
! unboxResult = ValueConversions.unboxExact(w);
! }
} else {
! unboxResult = MethodHandles.identity(Object.class);
}
BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
BoundMethodHandle mh;
try {
*** 771,781 ****
if (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);
}
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
--- 820,830 ----
if (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, false, true);
}
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
src/share/classes/java/lang/invoke/MethodHandleImpl.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File