mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8260605: Various java.lang.invoke cleanups
Reviewed-by: mchung
This commit is contained in:
parent
9cd21b687e
commit
63eae8fac2
4 changed files with 118 additions and 246 deletions
|
@ -84,10 +84,13 @@ final class BootstrapMethodInvoker {
|
|||
// By providing static type information or even invoking
|
||||
// exactly, we avoid emitting code to perform runtime
|
||||
// checking.
|
||||
info = maybeReBox(info);
|
||||
if (info == null) {
|
||||
// VM is allowed to pass up a null meaning no BSM args
|
||||
result = invoke(bootstrapMethod, caller, name, type);
|
||||
if (type instanceof Class<?> c) {
|
||||
result = bootstrapMethod.invoke(caller, name, c);
|
||||
} else {
|
||||
result = bootstrapMethod.invoke(caller, name, (MethodType)type);
|
||||
}
|
||||
}
|
||||
else if (!info.getClass().isArray()) {
|
||||
// VM is allowed to pass up a single BSM arg directly
|
||||
|
@ -99,7 +102,12 @@ final class BootstrapMethodInvoker {
|
|||
.invokeExact(caller, name, (MethodType)type,
|
||||
(String)info, new Object[0]);
|
||||
} else {
|
||||
result = invoke(bootstrapMethod, caller, name, type, info);
|
||||
info = maybeReBox(info);
|
||||
if (type instanceof Class<?> c) {
|
||||
result = bootstrapMethod.invoke(caller, name, c, info);
|
||||
} else {
|
||||
result = bootstrapMethod.invoke(caller, name, (MethodType)type, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (info.getClass() == int[].class) {
|
||||
|
@ -119,7 +127,6 @@ final class BootstrapMethodInvoker {
|
|||
else {
|
||||
// VM is allowed to pass up a full array of resolved BSM args
|
||||
Object[] argv = (Object[]) info;
|
||||
maybeReBoxElements(argv);
|
||||
|
||||
MethodType bsmType = bootstrapMethod.type();
|
||||
if (isLambdaMetafactoryIndyBSM(bsmType) && argv.length == 3) {
|
||||
|
@ -133,40 +140,36 @@ final class BootstrapMethodInvoker {
|
|||
} else if (isStringConcatFactoryBSM(bsmType) && argv.length >= 1) {
|
||||
String recipe = (String)argv[0];
|
||||
Object[] shiftedArgs = Arrays.copyOfRange(argv, 1, argv.length);
|
||||
maybeReBoxElements(shiftedArgs);
|
||||
result = (CallSite)bootstrapMethod.invokeExact(caller, name, (MethodType)type, recipe, shiftedArgs);
|
||||
} else if (isLambdaMetafactoryAltMetafactoryBSM(bsmType)) {
|
||||
maybeReBoxElements(argv);
|
||||
result = (CallSite)bootstrapMethod.invokeExact(caller, name, (MethodType)type, argv);
|
||||
} else {
|
||||
switch (argv.length) {
|
||||
case 0:
|
||||
result = invoke(bootstrapMethod, caller, name, type);
|
||||
break;
|
||||
case 1:
|
||||
result = invoke(bootstrapMethod, caller, name, type,
|
||||
argv[0]);
|
||||
break;
|
||||
case 2:
|
||||
result = invoke(bootstrapMethod, caller, name, type,
|
||||
argv[0], argv[1]);
|
||||
break;
|
||||
case 3:
|
||||
result = invoke(bootstrapMethod, caller, name, type,
|
||||
argv[0], argv[1], argv[2]);
|
||||
break;
|
||||
case 4:
|
||||
result = invoke(bootstrapMethod, caller, name, type,
|
||||
argv[0], argv[1], argv[2], argv[3]);
|
||||
break;
|
||||
case 5:
|
||||
result = invoke(bootstrapMethod, caller, name, type,
|
||||
argv[0], argv[1], argv[2], argv[3], argv[4]);
|
||||
break;
|
||||
case 6:
|
||||
result = invoke(bootstrapMethod, caller, name, type,
|
||||
argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
|
||||
break;
|
||||
default:
|
||||
result = invokeWithManyArguments(bootstrapMethod, caller, name, type, argv);
|
||||
maybeReBoxElements(argv);
|
||||
if (type instanceof Class<?> c) {
|
||||
result = switch (argv.length) {
|
||||
case 0 -> bootstrapMethod.invoke(caller, name, c);
|
||||
case 1 -> bootstrapMethod.invoke(caller, name, c, argv[0]);
|
||||
case 2 -> bootstrapMethod.invoke(caller, name, c, argv[0], argv[1]);
|
||||
case 3 -> bootstrapMethod.invoke(caller, name, c, argv[0], argv[1], argv[2]);
|
||||
case 4 -> bootstrapMethod.invoke(caller, name, c, argv[0], argv[1], argv[2], argv[3]);
|
||||
case 5 -> bootstrapMethod.invoke(caller, name, c, argv[0], argv[1], argv[2], argv[3], argv[4]);
|
||||
case 6 -> bootstrapMethod.invoke(caller, name, c, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
|
||||
default -> invokeWithManyArguments(bootstrapMethod, caller, name, type, argv);
|
||||
};
|
||||
} else {
|
||||
MethodType mt = (MethodType) type;
|
||||
result = switch (argv.length) {
|
||||
case 0 -> bootstrapMethod.invoke(caller, name, mt);
|
||||
case 1 -> bootstrapMethod.invoke(caller, name, mt, argv[0]);
|
||||
case 2 -> bootstrapMethod.invoke(caller, name, mt, argv[0], argv[1]);
|
||||
case 3 -> bootstrapMethod.invoke(caller, name, mt, argv[0], argv[1], argv[2]);
|
||||
case 4 -> bootstrapMethod.invoke(caller, name, mt, argv[0], argv[1], argv[2], argv[3]);
|
||||
case 5 -> bootstrapMethod.invoke(caller, name, mt, argv[0], argv[1], argv[2], argv[3], argv[4]);
|
||||
case 6 -> bootstrapMethod.invoke(caller, name, mt, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
|
||||
default -> invokeWithManyArguments(bootstrapMethod, caller, name, type, argv);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -218,76 +221,6 @@ final class BootstrapMethodInvoker {
|
|||
return wrapperType.cast(result);
|
||||
}
|
||||
|
||||
// If we don't provide static type information for type, we'll generate runtime
|
||||
// checks. Let's try not to...
|
||||
|
||||
private static Object invoke(MethodHandle bootstrapMethod, Lookup caller,
|
||||
String name, Object type) throws Throwable {
|
||||
if (type instanceof Class) {
|
||||
return bootstrapMethod.invoke(caller, name, (Class<?>)type);
|
||||
} else {
|
||||
return bootstrapMethod.invoke(caller, name, (MethodType)type);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object invoke(MethodHandle bootstrapMethod, Lookup caller,
|
||||
String name, Object type, Object arg0) throws Throwable {
|
||||
if (type instanceof Class) {
|
||||
return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0);
|
||||
} else {
|
||||
return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object invoke(MethodHandle bootstrapMethod, Lookup caller, String name,
|
||||
Object type, Object arg0, Object arg1) throws Throwable {
|
||||
if (type instanceof Class) {
|
||||
return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0, arg1);
|
||||
} else {
|
||||
return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object invoke(MethodHandle bootstrapMethod, Lookup caller, String name,
|
||||
Object type, Object arg0, Object arg1,
|
||||
Object arg2) throws Throwable {
|
||||
if (type instanceof Class) {
|
||||
return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0, arg1, arg2);
|
||||
} else {
|
||||
return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object invoke(MethodHandle bootstrapMethod, Lookup caller, String name,
|
||||
Object type, Object arg0, Object arg1,
|
||||
Object arg2, Object arg3) throws Throwable {
|
||||
if (type instanceof Class) {
|
||||
return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0, arg1, arg2, arg3);
|
||||
} else {
|
||||
return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2, arg3);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object invoke(MethodHandle bootstrapMethod, Lookup caller,
|
||||
String name, Object type, Object arg0, Object arg1,
|
||||
Object arg2, Object arg3, Object arg4) throws Throwable {
|
||||
if (type instanceof Class) {
|
||||
return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0, arg1, arg2, arg3, arg4);
|
||||
} else {
|
||||
return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2, arg3, arg4);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object invoke(MethodHandle bootstrapMethod, Lookup caller,
|
||||
String name, Object type, Object arg0, Object arg1,
|
||||
Object arg2, Object arg3, Object arg4, Object arg5) throws Throwable {
|
||||
if (type instanceof Class) {
|
||||
return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0, arg1, arg2, arg3, arg4, arg5);
|
||||
} else {
|
||||
return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object invokeWithManyArguments(MethodHandle bootstrapMethod, Lookup caller,
|
||||
String name, Object type, Object[] argv) throws Throwable {
|
||||
final int NON_SPREAD_ARG_COUNT = 3; // (caller, name, type)
|
||||
|
|
|
@ -84,6 +84,7 @@ class InvokerBytecodeGenerator {
|
|||
static final String INVOKER_SUPER_NAME = OBJ;
|
||||
|
||||
/** Name of new class */
|
||||
private final String name;
|
||||
private final String className;
|
||||
|
||||
private final LambdaForm lambdaForm;
|
||||
|
@ -117,16 +118,17 @@ class InvokerBytecodeGenerator {
|
|||
|
||||
/** Main constructor; other constructors delegate to this one. */
|
||||
private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
|
||||
String className, String invokerName, MethodType invokerType) {
|
||||
String name, String invokerName, MethodType invokerType) {
|
||||
int p = invokerName.indexOf('.');
|
||||
if (p > -1) {
|
||||
className = invokerName.substring(0, p);
|
||||
name = invokerName.substring(0, p);
|
||||
invokerName = invokerName.substring(p + 1);
|
||||
}
|
||||
if (DUMP_CLASS_FILES) {
|
||||
className = makeDumpableClassName(className);
|
||||
name = makeDumpableClassName(name);
|
||||
}
|
||||
this.className = className;
|
||||
this.name = name;
|
||||
this.className = CLASS_PREFIX + name;
|
||||
this.lambdaForm = lambdaForm;
|
||||
this.invokerName = invokerName;
|
||||
this.invokerType = invokerType;
|
||||
|
@ -135,9 +137,9 @@ class InvokerBytecodeGenerator {
|
|||
}
|
||||
|
||||
/** For generating LambdaForm interpreter entry points. */
|
||||
private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
|
||||
private InvokerBytecodeGenerator(String name, String invokerName, MethodType invokerType) {
|
||||
this(null, invokerType.parameterCount(),
|
||||
className, invokerName, invokerType);
|
||||
name, invokerName, invokerType);
|
||||
MethodType mt = invokerType.erase();
|
||||
// Create an array to map name indexes to locals indexes.
|
||||
localsMap[0] = 0; // localsMap has at least one element
|
||||
|
@ -149,15 +151,15 @@ class InvokerBytecodeGenerator {
|
|||
}
|
||||
|
||||
/** For generating customized code for a single LambdaForm. */
|
||||
private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
|
||||
this(className, form.lambdaName(), form, invokerType);
|
||||
private InvokerBytecodeGenerator(String name, LambdaForm form, MethodType invokerType) {
|
||||
this(name, form.lambdaName(), form, invokerType);
|
||||
}
|
||||
|
||||
/** For generating customized code for a single LambdaForm. */
|
||||
InvokerBytecodeGenerator(String className, String invokerName,
|
||||
InvokerBytecodeGenerator(String name, String invokerName,
|
||||
LambdaForm form, MethodType invokerType) {
|
||||
this(form, form.names.length,
|
||||
className, invokerName, invokerType);
|
||||
name, invokerName, invokerType);
|
||||
// Create an array to map name indexes to locals indexes.
|
||||
Name[] names = form.names;
|
||||
for (int i = 0, index = 0; i < localsMap.length; i++) {
|
||||
|
@ -195,7 +197,7 @@ class InvokerBytecodeGenerator {
|
|||
|
||||
private void maybeDump(final byte[] classFile) {
|
||||
if (DUMP_CLASS_FILES) {
|
||||
maybeDump(CLASS_PREFIX + className, classFile);
|
||||
maybeDump(className, classFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,7 +233,7 @@ class InvokerBytecodeGenerator {
|
|||
}
|
||||
String sfx = ctr.toString();
|
||||
while (sfx.length() < 3)
|
||||
sfx = "0"+sfx;
|
||||
sfx = "0" + sfx;
|
||||
className += sfx;
|
||||
return className;
|
||||
}
|
||||
|
@ -265,23 +267,38 @@ class InvokerBytecodeGenerator {
|
|||
desc = "Ljava/lang/Object;";
|
||||
}
|
||||
|
||||
Class<?> c = arg.getClass();
|
||||
while (c.isArray()) {
|
||||
c = c.getComponentType();
|
||||
}
|
||||
// unique static variable name
|
||||
String name = "_DATA_" + c.getSimpleName() + "_" + classData.size();
|
||||
String name;
|
||||
if (DUMP_CLASS_FILES) {
|
||||
Class<?> c = arg.getClass();
|
||||
while (c.isArray()) {
|
||||
c = c.getComponentType();
|
||||
}
|
||||
name = "_DATA_" + c.getSimpleName() + "_" + classData.size();
|
||||
} else {
|
||||
name = "_D_" + classData.size();
|
||||
}
|
||||
ClassData cd = new ClassData(name, desc, arg);
|
||||
classData.add(cd);
|
||||
return cd.name();
|
||||
return name;
|
||||
}
|
||||
|
||||
List<Object> classDataValues() {
|
||||
Object[] data = new Object[classData.size()];
|
||||
for (int i = 0; i < classData.size(); i++) {
|
||||
data[i] = classData.get(i).value;
|
||||
}
|
||||
return List.of(data);
|
||||
final List<ClassData> cd = classData;
|
||||
return switch(cd.size()) {
|
||||
case 0 -> List.of();
|
||||
case 1 -> List.of(cd.get(0).value);
|
||||
case 2 -> List.of(cd.get(0).value, cd.get(1).value);
|
||||
case 3 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value);
|
||||
case 4 -> List.of(cd.get(0).value, cd.get(1).value, cd.get(2).value, cd.get(3).value);
|
||||
default -> {
|
||||
Object[] data = new Object[classData.size()];
|
||||
for (int i = 0; i < classData.size(); i++) {
|
||||
data[i] = classData.get(i).value;
|
||||
}
|
||||
yield List.of(data);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static String debugString(Object arg) {
|
||||
|
@ -295,26 +312,11 @@ class InvokerBytecodeGenerator {
|
|||
return arg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the number of constant pool entries from a given class file.
|
||||
*
|
||||
* @param classFile the bytes of the class file in question.
|
||||
* @return the number of entries in the constant pool.
|
||||
*/
|
||||
private static int getConstantPoolSize(byte[] classFile) {
|
||||
// The first few bytes:
|
||||
// u4 magic;
|
||||
// u2 minor_version;
|
||||
// u2 major_version;
|
||||
// u2 constant_pool_count;
|
||||
return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the MemberName of a newly-defined method.
|
||||
*/
|
||||
private MemberName loadMethod(byte[] classFile) {
|
||||
Class<?> invokerClass = LOOKUP.makeHiddenClassDefiner(className(), classFile)
|
||||
Class<?> invokerClass = LOOKUP.makeHiddenClassDefiner(className, classFile)
|
||||
.defineClass(true, classDataValues());
|
||||
return resolveInvokerMember(invokerClass, invokerName, invokerType);
|
||||
}
|
||||
|
@ -339,8 +341,8 @@ class InvokerBytecodeGenerator {
|
|||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
|
||||
setClassWriter(cw);
|
||||
cw.visit(Opcodes.V1_8, NOT_ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
|
||||
CLASS_PREFIX + className, null, INVOKER_SUPER_NAME, null);
|
||||
cw.visitSource(SOURCE_PREFIX + className, null);
|
||||
className, null, INVOKER_SUPER_NAME, null);
|
||||
cw.visitSource(SOURCE_PREFIX + name, null);
|
||||
return cw;
|
||||
}
|
||||
|
||||
|
@ -357,14 +359,6 @@ class InvokerBytecodeGenerator {
|
|||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private String className() {
|
||||
return CLASS_PREFIX + className;
|
||||
}
|
||||
|
||||
private void clinit() {
|
||||
clinit(cw, className(), classData);
|
||||
}
|
||||
|
||||
/*
|
||||
* <clinit> to initialize the static final fields with the live class data
|
||||
* LambdaForms can't use condy due to bootstrapping issue.
|
||||
|
@ -647,7 +641,7 @@ class InvokerBytecodeGenerator {
|
|||
String sig = getInternalName(cls);
|
||||
mv.visitTypeInsn(Opcodes.CHECKCAST, sig);
|
||||
} else {
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(cls), "Ljava/lang/Class;");
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className, classData(cls), "Ljava/lang/Class;");
|
||||
mv.visitInsn(Opcodes.SWAP);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CLS, "cast", LL_SIG, false);
|
||||
if (Object[].class.isAssignableFrom(cls))
|
||||
|
@ -665,17 +659,15 @@ class InvokerBytecodeGenerator {
|
|||
* Emits an actual return instruction conforming to the given return type.
|
||||
*/
|
||||
private void emitReturnInsn(BasicType type) {
|
||||
int opcode;
|
||||
switch (type) {
|
||||
case I_TYPE: opcode = Opcodes.IRETURN; break;
|
||||
case J_TYPE: opcode = Opcodes.LRETURN; break;
|
||||
case F_TYPE: opcode = Opcodes.FRETURN; break;
|
||||
case D_TYPE: opcode = Opcodes.DRETURN; break;
|
||||
case L_TYPE: opcode = Opcodes.ARETURN; break;
|
||||
case V_TYPE: opcode = Opcodes.RETURN; break;
|
||||
default:
|
||||
throw new InternalError("unknown return type: " + type);
|
||||
}
|
||||
int opcode = switch (type) {
|
||||
case I_TYPE -> Opcodes.IRETURN;
|
||||
case J_TYPE -> Opcodes.LRETURN;
|
||||
case F_TYPE -> Opcodes.FRETURN;
|
||||
case D_TYPE -> Opcodes.DRETURN;
|
||||
case L_TYPE -> Opcodes.ARETURN;
|
||||
case V_TYPE -> Opcodes.RETURN;
|
||||
default -> throw new InternalError("unknown return type: " + type);
|
||||
};
|
||||
mv.visitInsn(opcode);
|
||||
}
|
||||
|
||||
|
@ -722,7 +714,7 @@ class InvokerBytecodeGenerator {
|
|||
case LINK_TO_CALL_SITE: // fall-through
|
||||
case LINK_TO_TARGET_METHOD: // fall-through
|
||||
case GENERIC_INVOKER: // fall-through
|
||||
case GENERIC_LINKER: return resolveFrom(name, invokerType.basicType(), Invokers.Holder.class);
|
||||
case GENERIC_LINKER: return resolveFrom(name, invokerType, Invokers.Holder.class);
|
||||
case GET_REFERENCE: // fall-through
|
||||
case GET_BOOLEAN: // fall-through
|
||||
case GET_BYTE: // fall-through
|
||||
|
@ -803,7 +795,7 @@ class InvokerBytecodeGenerator {
|
|||
private byte[] generateCustomizedCodeBytes() {
|
||||
classFilePrologue();
|
||||
addMethod();
|
||||
clinit();
|
||||
clinit(cw, className, classData);
|
||||
bogusMethod(lambdaForm);
|
||||
|
||||
final byte[] classFile = toByteArray();
|
||||
|
@ -838,7 +830,7 @@ class InvokerBytecodeGenerator {
|
|||
// receiver MethodHandle (at slot #0) with an embedded constant and use it instead.
|
||||
// It enables more efficient code generation in some situations, since embedded constants
|
||||
// are compile-time constants for JIT compiler.
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(lambdaForm.customized), MH_SIG);
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className, classData(lambdaForm.customized), MH_SIG);
|
||||
mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
|
||||
assert(checkActualReceiver()); // expects MethodHandle on top of the stack
|
||||
mv.visitVarInsn(Opcodes.ASTORE, localsMap[0]);
|
||||
|
@ -971,7 +963,7 @@ class InvokerBytecodeGenerator {
|
|||
// push receiver
|
||||
MethodHandle target = name.function.resolvedHandle();
|
||||
assert(target != null) : name.exprString();
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(target), MH_SIG);
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className, classData(target), MH_SIG);
|
||||
emitReferenceCast(MethodHandle.class, target);
|
||||
} else {
|
||||
// load receiver
|
||||
|
@ -990,7 +982,7 @@ class InvokerBytecodeGenerator {
|
|||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
|
||||
}
|
||||
|
||||
private static Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
|
||||
private static final Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
|
||||
// Sample classes from each package we are willing to bind to statically:
|
||||
java.lang.Object.class,
|
||||
java.util.Arrays.class,
|
||||
|
@ -1134,7 +1126,7 @@ class InvokerBytecodeGenerator {
|
|||
}
|
||||
assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
|
||||
assert(emptyArray.getClass() == rtype); // exact typing
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(emptyArray), "Ljava/lang/Object;");
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className, classData(emptyArray), "Ljava/lang/Object;");
|
||||
emitReferenceCast(rtype, emptyArray);
|
||||
return;
|
||||
}
|
||||
|
@ -1691,13 +1683,15 @@ class InvokerBytecodeGenerator {
|
|||
Name n = (Name) arg;
|
||||
emitLoadInsn(n.type, n.index());
|
||||
emitImplicitConversion(n.type, ptype, n);
|
||||
} else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
|
||||
emitConst(arg);
|
||||
} else if (arg == null && bptype == L_TYPE) {
|
||||
mv.visitInsn(Opcodes.ACONST_NULL);
|
||||
} else if (arg instanceof String && bptype == L_TYPE) {
|
||||
mv.visitLdcInsn(arg);
|
||||
} else {
|
||||
if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
|
||||
emitConst(arg);
|
||||
} else {
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(arg), "Ljava/lang/Object;");
|
||||
mv.visitFieldInsn(Opcodes.GETSTATIC, className, classData(arg), "Ljava/lang/Object;");
|
||||
emitImplicitConversion(L_TYPE, ptype, arg);
|
||||
}
|
||||
}
|
||||
|
@ -1828,10 +1822,10 @@ class InvokerBytecodeGenerator {
|
|||
|
||||
private void emitX2I(Wrapper type) {
|
||||
switch (type) {
|
||||
case LONG: mv.visitInsn(Opcodes.L2I); break;
|
||||
case FLOAT: mv.visitInsn(Opcodes.F2I); break;
|
||||
case DOUBLE: mv.visitInsn(Opcodes.D2I); break;
|
||||
default: throw new InternalError("unknown type: " + type);
|
||||
case LONG -> mv.visitInsn(Opcodes.L2I);
|
||||
case FLOAT -> mv.visitInsn(Opcodes.F2I);
|
||||
case DOUBLE -> mv.visitInsn(Opcodes.D2I);
|
||||
default -> throw new InternalError("unknown type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1889,7 +1883,7 @@ class InvokerBytecodeGenerator {
|
|||
emitReturnInsn(basicType(rtype));
|
||||
|
||||
methodEpilogue();
|
||||
clinit();
|
||||
clinit(cw, className, classData);
|
||||
bogusMethod(invokerType);
|
||||
|
||||
final byte[] classFile = cw.toByteArray();
|
||||
|
@ -1958,7 +1952,7 @@ class InvokerBytecodeGenerator {
|
|||
emitReturnInsn(L_TYPE); // NOTE: NamedFunction invokers always return a reference value.
|
||||
|
||||
methodEpilogue();
|
||||
clinit();
|
||||
clinit(cw, className, classData);
|
||||
bogusMethod(dstType);
|
||||
|
||||
final byte[] classFile = cw.toByteArray();
|
||||
|
|
|
@ -212,26 +212,6 @@ class LambdaForm {
|
|||
if (!type.isPrimitive()) return L_TYPE;
|
||||
return basicType(Wrapper.forPrimitiveType(type));
|
||||
}
|
||||
static BasicType[] basicTypes(String types) {
|
||||
BasicType[] btypes = new BasicType[types.length()];
|
||||
for (int i = 0; i < btypes.length; i++) {
|
||||
btypes[i] = basicType(types.charAt(i));
|
||||
}
|
||||
return btypes;
|
||||
}
|
||||
static String basicTypeDesc(BasicType[] types) {
|
||||
if (types == null) {
|
||||
return null;
|
||||
}
|
||||
if (types.length == 0) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (BasicType bt : types) {
|
||||
sb.append(bt.basicTypeChar());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
static int[] basicTypeOrds(BasicType[] types) {
|
||||
if (types == null) {
|
||||
return null;
|
||||
|
@ -388,18 +368,9 @@ class LambdaForm {
|
|||
LambdaForm(int arity, Name[] names, Kind kind) {
|
||||
this(arity, names, LAST_RESULT, /*forceInline=*/true, /*customized=*/null, kind);
|
||||
}
|
||||
LambdaForm(int arity, Name[] names, boolean forceInline) {
|
||||
this(arity, names, LAST_RESULT, forceInline, /*customized=*/null, Kind.GENERIC);
|
||||
}
|
||||
LambdaForm(int arity, Name[] names, boolean forceInline, Kind kind) {
|
||||
this(arity, names, LAST_RESULT, forceInline, /*customized=*/null, kind);
|
||||
}
|
||||
LambdaForm(Name[] formals, Name[] temps, Name result) {
|
||||
this(formals.length, buildNames(formals, temps, result), LAST_RESULT, /*forceInline=*/true, /*customized=*/null);
|
||||
}
|
||||
LambdaForm(Name[] formals, Name[] temps, Name result, boolean forceInline) {
|
||||
this(formals.length, buildNames(formals, temps, result), LAST_RESULT, forceInline, /*customized=*/null);
|
||||
}
|
||||
|
||||
private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
|
||||
int arity = formals.length;
|
||||
|
@ -629,9 +600,8 @@ class LambdaForm {
|
|||
|
||||
/** Report the N-th argument name. */
|
||||
Name parameter(int n) {
|
||||
assert(n < arity);
|
||||
Name param = names[n];
|
||||
assert(param.isParam());
|
||||
assert(n < arity && param.isParam());
|
||||
return param;
|
||||
}
|
||||
|
||||
|
@ -670,9 +640,6 @@ class LambdaForm {
|
|||
assert(isValidSignature(sig));
|
||||
return sig.indexOf('_');
|
||||
}
|
||||
static BasicType signatureReturn(String sig) {
|
||||
return basicType(sig.charAt(signatureArity(sig) + 1));
|
||||
}
|
||||
static boolean isValidSignature(String sig) {
|
||||
int arity = sig.indexOf('_');
|
||||
if (arity < 0) return false; // must be of the form *_*
|
||||
|
@ -687,16 +654,6 @@ class LambdaForm {
|
|||
}
|
||||
return true; // [LIJFD]*_[LIJFDV]
|
||||
}
|
||||
static MethodType signatureType(String sig) {
|
||||
Class<?>[] ptypes = new Class<?>[signatureArity(sig)];
|
||||
for (int i = 0; i < ptypes.length; i++)
|
||||
ptypes[i] = basicType(sig.charAt(i)).btClass;
|
||||
Class<?> rtype = signatureReturn(sig).btClass;
|
||||
return MethodType.makeImpl(rtype, ptypes, true);
|
||||
}
|
||||
static MethodType basicMethodType(MethodType mt) {
|
||||
return signatureType(basicTypeSignature(mt));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if i-th name is a call to MethodHandleImpl.selectAlternative.
|
||||
|
@ -1327,7 +1284,7 @@ class LambdaForm {
|
|||
if (c1 != NO_CHAR && !('A' <= c1 && c1 <= 'Z')) {
|
||||
// wrong kind of char; bail out here
|
||||
if (buf != null) {
|
||||
buf.append(signature.substring(i - c1reps, len));
|
||||
buf.append(signature, i - c1reps, len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1410,11 +1367,6 @@ class LambdaForm {
|
|||
return type.btChar;
|
||||
}
|
||||
|
||||
void resolve() {
|
||||
if (function != null)
|
||||
function.resolve();
|
||||
}
|
||||
|
||||
Name newIndex(int i) {
|
||||
if (initIndex(i)) return this;
|
||||
return cloneWithIndex(i);
|
||||
|
@ -1609,10 +1561,6 @@ class LambdaForm {
|
|||
return count;
|
||||
}
|
||||
|
||||
boolean contains(Name n) {
|
||||
return this == n || lastUseIndex(n) >= 0;
|
||||
}
|
||||
|
||||
public boolean equals(Name that) {
|
||||
if (this == that) return true;
|
||||
if (isParam())
|
||||
|
|
|
@ -199,19 +199,13 @@ class MethodType
|
|||
/*non-public*/
|
||||
static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1; // deduct one more for invoker
|
||||
|
||||
private static void checkRtype(Class<?> rtype) {
|
||||
Objects.requireNonNull(rtype);
|
||||
}
|
||||
private static void checkPtype(Class<?> ptype) {
|
||||
Objects.requireNonNull(ptype);
|
||||
if (ptype == void.class)
|
||||
throw newIllegalArgumentException("parameter type cannot be void");
|
||||
}
|
||||
/** Return number of extra slots (count of long/double args). */
|
||||
private static int checkPtypes(Class<?>[] ptypes) {
|
||||
int slots = 0;
|
||||
for (Class<?> ptype : ptypes) {
|
||||
checkPtype(ptype);
|
||||
Objects.requireNonNull(ptype);
|
||||
if (ptype == void.class)
|
||||
throw newIllegalArgumentException("parameter type cannot be void");
|
||||
if (ptype == double.class || ptype == long.class) {
|
||||
slots++;
|
||||
}
|
||||
|
@ -328,10 +322,14 @@ class MethodType
|
|||
}
|
||||
|
||||
/**
|
||||
* Sole factory method to find or create an interned method type.
|
||||
* Sole factory method to find or create an interned method type. Will perform
|
||||
* input validation on behalf of factory methods
|
||||
*
|
||||
* @param rtype desired return type
|
||||
* @param ptypes desired parameter types
|
||||
* @param trusted whether the ptypes can be used without cloning
|
||||
* @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
|
||||
* @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
|
||||
* @return the unique method type of the desired structure
|
||||
*/
|
||||
/*trusted*/
|
||||
|
@ -345,7 +343,7 @@ class MethodType
|
|||
return mt;
|
||||
|
||||
// promote the object to the Real Thing, and reprobe
|
||||
MethodType.checkRtype(rtype);
|
||||
Objects.requireNonNull(rtype);
|
||||
if (trusted) {
|
||||
MethodType.checkPtypes(ptypes);
|
||||
mt = primordialMT;
|
||||
|
@ -415,7 +413,6 @@ class MethodType
|
|||
*/
|
||||
public MethodType changeParameterType(int num, Class<?> nptype) {
|
||||
if (parameterType(num) == nptype) return this;
|
||||
checkPtype(nptype);
|
||||
Class<?>[] nptypes = ptypes.clone();
|
||||
nptypes[num] = nptype;
|
||||
return makeImpl(rtype, nptypes, true);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue