8050200: Make LambdaForm intrinsics detection more robust
Reviewed-by: vlivanov, psandoz
This commit is contained in:
parent
8940954741
commit
d565c3701f
@ -35,7 +35,7 @@ import static java.lang.invoke.LambdaForm.*;
|
|||||||
import static java.lang.invoke.LambdaForm.BasicType.*;
|
import static java.lang.invoke.LambdaForm.BasicType.*;
|
||||||
import static java.lang.invoke.MethodHandleStatics.*;
|
import static java.lang.invoke.MethodHandleStatics.*;
|
||||||
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
||||||
import java.lang.invoke.MethodHandleImpl.ArrayAccessor;
|
|
||||||
import sun.invoke.util.VerifyAccess;
|
import sun.invoke.util.VerifyAccess;
|
||||||
import sun.invoke.util.VerifyType;
|
import sun.invoke.util.VerifyType;
|
||||||
import sun.invoke.util.Wrapper;
|
import sun.invoke.util.Wrapper;
|
||||||
@ -636,26 +636,44 @@ class InvokerBytecodeGenerator {
|
|||||||
Name onStack = null;
|
Name onStack = null;
|
||||||
for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
|
for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
|
||||||
Name name = lambdaForm.names[i];
|
Name name = lambdaForm.names[i];
|
||||||
MemberName member = name.function.member();
|
|
||||||
Class<?> rtype = name.function.methodType().returnType();
|
|
||||||
|
|
||||||
emitStoreResult(onStack);
|
emitStoreResult(onStack);
|
||||||
onStack = name; // unless otherwise modified below
|
onStack = name; // unless otherwise modified below
|
||||||
|
MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
|
||||||
|
switch (intr) {
|
||||||
|
case SELECT_ALTERNATIVE:
|
||||||
|
assert isSelectAlternative(i);
|
||||||
|
onStack = emitSelectAlternative(name, lambdaForm.names[i+1]);
|
||||||
|
i++; // skip MH.invokeBasic of the selectAlternative result
|
||||||
|
continue;
|
||||||
|
case GUARD_WITH_CATCH:
|
||||||
|
assert isGuardWithCatch(i);
|
||||||
|
onStack = emitGuardWithCatch(i);
|
||||||
|
i = i+2; // Jump to the end of GWC idiom
|
||||||
|
continue;
|
||||||
|
case NEW_ARRAY:
|
||||||
|
Class<?> rtype = name.function.methodType().returnType();
|
||||||
|
if (isStaticallyNameable(rtype)) {
|
||||||
|
emitNewArray(name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ARRAY_LOAD:
|
||||||
|
emitArrayLoad(name);
|
||||||
|
continue;
|
||||||
|
case ARRAY_STORE:
|
||||||
|
emitArrayStore(name);
|
||||||
|
continue;
|
||||||
|
case NONE:
|
||||||
|
// no intrinsic associated
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw newInternalError("Unknown intrinsic: "+intr);
|
||||||
|
}
|
||||||
|
|
||||||
if (isSelectAlternative(i)) {
|
MemberName member = name.function.member();
|
||||||
onStack = emitSelectAlternative(name, lambdaForm.names[i + 1]);
|
if (isStaticallyInvocable(member)) {
|
||||||
i++; // skip MH.invokeBasic of the selectAlternative result
|
emitStaticInvoke(member, name);
|
||||||
} else if (isGuardWithCatch(i)) {
|
|
||||||
onStack = emitGuardWithCatch(i);
|
|
||||||
i = i+2; // Jump to the end of GWC idiom
|
|
||||||
} else if (isNewArray(rtype, name)) {
|
|
||||||
emitNewArray(rtype, name);
|
|
||||||
} else if (isArrayLoad(member)) {
|
|
||||||
emitArrayLoad(name);
|
|
||||||
} else if (isArrayStore(member)) {
|
|
||||||
emitArrayStore(name);
|
|
||||||
} else if (isStaticallyInvocable(member)) {
|
|
||||||
emitStaticInvoke(name);
|
|
||||||
} else {
|
} else {
|
||||||
emitInvoke(name);
|
emitInvoke(name);
|
||||||
}
|
}
|
||||||
@ -672,20 +690,6 @@ class InvokerBytecodeGenerator {
|
|||||||
return classFile;
|
return classFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isArrayLoad(MemberName member) {
|
|
||||||
return member != null &&
|
|
||||||
member.getDeclaringClass() == ArrayAccessor.class &&
|
|
||||||
member.getName() != null &&
|
|
||||||
member.getName().startsWith("getElement");
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isArrayStore(MemberName member) {
|
|
||||||
return member != null &&
|
|
||||||
member.getDeclaringClass() == ArrayAccessor.class &&
|
|
||||||
member.getName() != null &&
|
|
||||||
member.getName().startsWith("setElement");
|
|
||||||
}
|
|
||||||
|
|
||||||
void emitArrayLoad(Name name) { emitArrayOp(name, Opcodes.AALOAD); }
|
void emitArrayLoad(Name name) { emitArrayOp(name, Opcodes.AALOAD); }
|
||||||
void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); }
|
void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); }
|
||||||
|
|
||||||
@ -837,33 +841,31 @@ class InvokerBytecodeGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isNewArray(Class<?> rtype, Name name) {
|
void emitNewArray(Name name) throws InternalError {
|
||||||
return rtype.isArray() &&
|
Class<?> rtype = name.function.methodType().returnType();
|
||||||
isStaticallyNameable(rtype) &&
|
if (name.arguments.length == 0) {
|
||||||
isArrayBuilder(name.function.resolvedHandle) &&
|
// The array will be a constant.
|
||||||
name.arguments.length > 0;
|
Object emptyArray;
|
||||||
}
|
try {
|
||||||
|
emptyArray = name.function.resolvedHandle.invoke();
|
||||||
void emitNewArray(Class<?> rtype, Name name) throws InternalError {
|
} catch (Throwable ex) {
|
||||||
|
throw newInternalError(ex);
|
||||||
|
}
|
||||||
|
assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
|
||||||
|
assert(emptyArray.getClass() == rtype); // exact typing
|
||||||
|
mv.visitLdcInsn(constantPlaceholder(emptyArray));
|
||||||
|
emitReferenceCast(rtype, emptyArray);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Class<?> arrayElementType = rtype.getComponentType();
|
Class<?> arrayElementType = rtype.getComponentType();
|
||||||
|
assert(arrayElementType != null);
|
||||||
emitIconstInsn(name.arguments.length);
|
emitIconstInsn(name.arguments.length);
|
||||||
int xas;
|
int xas = Opcodes.AASTORE;
|
||||||
if (!arrayElementType.isPrimitive()) {
|
if (!arrayElementType.isPrimitive()) {
|
||||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
|
mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
|
||||||
xas = Opcodes.AASTORE;
|
|
||||||
} else {
|
} else {
|
||||||
int tc;
|
byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
|
||||||
switch (Wrapper.forPrimitiveType(arrayElementType)) {
|
xas = arrayInsnOpcode(tc, xas);
|
||||||
case BOOLEAN: tc = Opcodes.T_BOOLEAN; xas = Opcodes.BASTORE; break;
|
|
||||||
case BYTE: tc = Opcodes.T_BYTE; xas = Opcodes.BASTORE; break;
|
|
||||||
case CHAR: tc = Opcodes.T_CHAR; xas = Opcodes.CASTORE; break;
|
|
||||||
case SHORT: tc = Opcodes.T_SHORT; xas = Opcodes.SASTORE; break;
|
|
||||||
case INT: tc = Opcodes.T_INT; xas = Opcodes.IASTORE; break;
|
|
||||||
case LONG: tc = Opcodes.T_LONG; xas = Opcodes.LASTORE; break;
|
|
||||||
case FLOAT: tc = Opcodes.T_FLOAT; xas = Opcodes.FASTORE; break;
|
|
||||||
case DOUBLE: tc = Opcodes.T_DOUBLE; xas = Opcodes.DASTORE; break;
|
|
||||||
default: throw new InternalError(rtype.getName());
|
|
||||||
}
|
|
||||||
mv.visitIntInsn(Opcodes.NEWARRAY, tc);
|
mv.visitIntInsn(Opcodes.NEWARRAY, tc);
|
||||||
}
|
}
|
||||||
// store arguments
|
// store arguments
|
||||||
@ -890,24 +892,6 @@ class InvokerBytecodeGenerator {
|
|||||||
throw new InternalError("refKind="+refKind);
|
throw new InternalError("refKind="+refKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isArrayBuilder(MethodHandle fn) {
|
|
||||||
if (fn == null)
|
|
||||||
return false;
|
|
||||||
MethodType mtype = fn.type();
|
|
||||||
Class<?> rtype = mtype.returnType();
|
|
||||||
Class<?> arrayElementType = rtype.getComponentType();
|
|
||||||
if (arrayElementType == null)
|
|
||||||
return false;
|
|
||||||
List<Class<?>> ptypes = mtype.parameterList();
|
|
||||||
int size = ptypes.size();
|
|
||||||
if (!ptypes.equals(Collections.nCopies(size, arrayElementType)))
|
|
||||||
return false;
|
|
||||||
// Assume varargsArray caches pointers.
|
|
||||||
if (fn != MethodHandleImpl.varargsArray(rtype, size))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
|
* Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
|
||||||
*/
|
*/
|
||||||
|
@ -27,11 +27,10 @@ package java.lang.invoke;
|
|||||||
|
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import sun.invoke.util.Wrapper;
|
import sun.invoke.util.Wrapper;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
@ -1371,6 +1370,11 @@ class LambdaForm {
|
|||||||
public boolean isConstantZero() {
|
public boolean isConstantZero() {
|
||||||
return this.equals(constantZero(returnType()));
|
return this.equals(constantZero(returnType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MethodHandleImpl.Intrinsic intrinsicName() {
|
||||||
|
return resolvedHandle == null ? MethodHandleImpl.Intrinsic.NONE
|
||||||
|
: resolvedHandle.intrinsicName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String basicTypeSignature(MethodType type) {
|
public static String basicTypeSignature(MethodType type) {
|
||||||
|
@ -27,11 +27,8 @@ package java.lang.invoke;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.lang.invoke.LambdaForm.BasicType;
|
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
import static java.lang.invoke.MethodHandleStatics.*;
|
import static java.lang.invoke.MethodHandleStatics.*;
|
||||||
import static java.lang.invoke.LambdaForm.BasicType.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A method handle is a typed, directly executable reference to an underlying method,
|
* A method handle is a typed, directly executable reference to an underlying method,
|
||||||
@ -1355,6 +1352,12 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
|
|||||||
return null; // caller-bound MH for @CallerSensitive method returns caller
|
return null; // caller-bound MH for @CallerSensitive method returns caller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*non-public*/
|
||||||
|
MethodHandleImpl.Intrinsic intrinsicName() {
|
||||||
|
// no special intrinsic meaning to most MHs
|
||||||
|
return MethodHandleImpl.Intrinsic.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
/*non-public*/
|
/*non-public*/
|
||||||
MethodHandle withInternalMemberName(MemberName member, boolean isInvokeSpecial) {
|
MethodHandle withInternalMemberName(MemberName member, boolean isInvokeSpecial) {
|
||||||
if (member != null) {
|
if (member != null) {
|
||||||
|
@ -30,7 +30,6 @@ import java.security.PrivilegedAction;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import sun.invoke.empty.Empty;
|
import sun.invoke.empty.Empty;
|
||||||
import sun.invoke.util.ValueConversions;
|
import sun.invoke.util.ValueConversions;
|
||||||
@ -86,6 +85,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
// safe to view non-strictly, because element type follows from array type
|
// safe to view non-strictly, because element type follows from array type
|
||||||
mh = mh.viewAsType(correctType, false);
|
mh = mh.viewAsType(correctType, false);
|
||||||
}
|
}
|
||||||
|
mh = makeIntrinsic(mh, (isSetter ? Intrinsic.ARRAY_STORE : Intrinsic.ARRAY_LOAD));
|
||||||
// Atomically update accessor cache.
|
// Atomically update accessor cache.
|
||||||
synchronized(cache) {
|
synchronized(cache) {
|
||||||
if (cache[cacheIndex] == null) {
|
if (cache[cacheIndex] == null) {
|
||||||
@ -111,8 +111,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER;
|
static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER;
|
||||||
static {
|
static {
|
||||||
MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class);
|
MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class);
|
||||||
cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = getAccessor(Object[].class, false);
|
cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, false), Intrinsic.ARRAY_LOAD);
|
||||||
cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = getAccessor(Object[].class, true);
|
cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = makeIntrinsic(getAccessor(Object[].class, true), Intrinsic.ARRAY_STORE);
|
||||||
|
|
||||||
assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName()));
|
assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName()));
|
||||||
assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName()));
|
assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName()));
|
||||||
@ -502,10 +502,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
|
|
||||||
static final NamedFunction NF_checkSpreadArgument;
|
static final NamedFunction NF_checkSpreadArgument;
|
||||||
static final NamedFunction NF_guardWithCatch;
|
static final NamedFunction NF_guardWithCatch;
|
||||||
static final NamedFunction NF_selectAlternative;
|
|
||||||
static final NamedFunction NF_throwException;
|
static final NamedFunction NF_throwException;
|
||||||
|
|
||||||
static final MethodHandle MH_castReference;
|
static final MethodHandle MH_castReference;
|
||||||
|
static final MethodHandle MH_selectAlternative;
|
||||||
static final MethodHandle MH_copyAsPrimitiveArray;
|
static final MethodHandle MH_copyAsPrimitiveArray;
|
||||||
static final MethodHandle MH_fillNewTypedArray;
|
static final MethodHandle MH_fillNewTypedArray;
|
||||||
static final MethodHandle MH_fillNewArray;
|
static final MethodHandle MH_fillNewArray;
|
||||||
@ -516,13 +516,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
|
NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
|
||||||
NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
|
NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
|
||||||
MethodHandle.class, Object[].class));
|
MethodHandle.class, Object[].class));
|
||||||
NF_selectAlternative = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class,
|
|
||||||
MethodHandle.class));
|
|
||||||
NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
|
NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
|
||||||
|
|
||||||
NF_checkSpreadArgument.resolve();
|
NF_checkSpreadArgument.resolve();
|
||||||
NF_guardWithCatch.resolve();
|
NF_guardWithCatch.resolve();
|
||||||
NF_selectAlternative.resolve();
|
|
||||||
NF_throwException.resolve();
|
NF_throwException.resolve();
|
||||||
|
|
||||||
MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference",
|
MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference",
|
||||||
@ -535,6 +532,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
MethodType.methodType(Object[].class, Integer.class, Object[].class));
|
MethodType.methodType(Object[].class, Integer.class, Object[].class));
|
||||||
MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
|
MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
|
||||||
MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
|
MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
|
||||||
|
|
||||||
|
MH_selectAlternative = makeIntrinsic(
|
||||||
|
IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
|
||||||
|
MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
|
||||||
|
Intrinsic.SELECT_ALTERNATIVE);
|
||||||
} catch (ReflectiveOperationException ex) {
|
} catch (ReflectiveOperationException ex) {
|
||||||
throw newInternalError(ex);
|
throw newInternalError(ex);
|
||||||
}
|
}
|
||||||
@ -620,7 +622,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
|
|
||||||
// call selectAlternative
|
// call selectAlternative
|
||||||
Object[] selectArgs = { names[arity + 1], target, fallback };
|
Object[] selectArgs = { names[arity + 1], target, fallback };
|
||||||
names[arity + 2] = new Name(Lazy.NF_selectAlternative, selectArgs);
|
names[arity + 2] = new Name(Lazy.MH_selectAlternative, selectArgs);
|
||||||
targetArgs[0] = names[arity + 2];
|
targetArgs[0] = names[arity + 2];
|
||||||
|
|
||||||
// call target or fallback
|
// call target or fallback
|
||||||
@ -689,7 +691,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
Object[] args = new Object[invokeBasic.type().parameterCount()];
|
Object[] args = new Object[invokeBasic.type().parameterCount()];
|
||||||
args[0] = names[GET_COLLECT_ARGS];
|
args[0] = names[GET_COLLECT_ARGS];
|
||||||
System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE);
|
System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE);
|
||||||
names[BOXED_ARGS] = new Name(new NamedFunction(invokeBasic), args);
|
names[BOXED_ARGS] = new Name(makeIntrinsic(invokeBasic, Intrinsic.GUARD_WITH_CATCH), args);
|
||||||
|
|
||||||
// t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
|
// t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
|
||||||
Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
|
Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
|
||||||
@ -698,7 +700,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
// t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
|
// t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
|
||||||
MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
|
MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
|
||||||
Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]};
|
Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]};
|
||||||
names[UNBOX_RESULT] = new Name(new NamedFunction(invokeBasicUnbox), unboxArgs);
|
names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs);
|
||||||
|
|
||||||
lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names);
|
lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names);
|
||||||
|
|
||||||
@ -1004,6 +1006,63 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
return new WrappedMember(target, target.type(), member, isInvokeSpecial, null);
|
return new WrappedMember(target, target.type(), member, isInvokeSpecial, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Intrinsic IDs */
|
||||||
|
/*non-public*/
|
||||||
|
enum Intrinsic {
|
||||||
|
SELECT_ALTERNATIVE,
|
||||||
|
GUARD_WITH_CATCH,
|
||||||
|
NEW_ARRAY,
|
||||||
|
ARRAY_LOAD,
|
||||||
|
ARRAY_STORE,
|
||||||
|
NONE // no intrinsic associated
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Mark arbitrary method handle as intrinsic.
|
||||||
|
* InvokerBytecodeGenerator uses this info to produce more efficient bytecode shape. */
|
||||||
|
private static final class IntrinsicMethodHandle extends DelegatingMethodHandle {
|
||||||
|
private final MethodHandle target;
|
||||||
|
private final Intrinsic intrinsicName;
|
||||||
|
|
||||||
|
IntrinsicMethodHandle(MethodHandle target, Intrinsic intrinsicName) {
|
||||||
|
super(target.type(), target);
|
||||||
|
this.target = target;
|
||||||
|
this.intrinsicName = intrinsicName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MethodHandle getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Intrinsic intrinsicName() {
|
||||||
|
return intrinsicName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodHandle asTypeUncached(MethodType newType) {
|
||||||
|
// This MH is an alias for target, except for the intrinsic name
|
||||||
|
// Drop the name if there is any conversion.
|
||||||
|
return asTypeCache = target.asType(newType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String internalProperties() {
|
||||||
|
return super.internalProperties() +
|
||||||
|
"\n& Intrinsic="+intrinsicName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodHandle makeIntrinsic(MethodHandle target, Intrinsic intrinsicName) {
|
||||||
|
if (intrinsicName == target.intrinsicName())
|
||||||
|
return target;
|
||||||
|
return new IntrinsicMethodHandle(target, intrinsicName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodHandle makeIntrinsic(MethodType type, LambdaForm form, Intrinsic intrinsicName) {
|
||||||
|
return new IntrinsicMethodHandle(SimpleMethodHandle.make(type, form), intrinsicName);
|
||||||
|
}
|
||||||
|
|
||||||
/// Collection of multiple arguments.
|
/// Collection of multiple arguments.
|
||||||
|
|
||||||
private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
|
private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
|
||||||
@ -1053,6 +1112,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
|
MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
|
||||||
if (mh == null) break;
|
if (mh == null) break;
|
||||||
|
mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
|
||||||
mhs.add(mh);
|
mhs.add(mh);
|
||||||
}
|
}
|
||||||
assert(mhs.size() == 11); // current number of methods
|
assert(mhs.size() == 11); // current number of methods
|
||||||
@ -1131,9 +1191,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
MethodHandle mh = ARRAYS[nargs];
|
MethodHandle mh = ARRAYS[nargs];
|
||||||
if (mh != null) return mh;
|
if (mh != null) return mh;
|
||||||
mh = findCollector("array", nargs, Object[].class);
|
mh = findCollector("array", nargs, Object[].class);
|
||||||
|
if (mh != null) mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
|
||||||
if (mh != null) return ARRAYS[nargs] = mh;
|
if (mh != null) return ARRAYS[nargs] = mh;
|
||||||
mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs);
|
mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs);
|
||||||
assert(assertCorrectArity(mh, nargs));
|
assert(assertCorrectArity(mh, nargs));
|
||||||
|
mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
|
||||||
return ARRAYS[nargs] = mh;
|
return ARRAYS[nargs] = mh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1263,6 +1325,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
mh = buildVarargsArray(builder, producer, nargs);
|
mh = buildVarargsArray(builder, producer, nargs);
|
||||||
}
|
}
|
||||||
mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
|
mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
|
||||||
|
mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
|
||||||
assert(assertCorrectArity(mh, nargs));
|
assert(assertCorrectArity(mh, nargs));
|
||||||
if (nargs < cache.length)
|
if (nargs < cache.length)
|
||||||
cache[nargs] = mh;
|
cache[nargs] = mh;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user