8341548: More concise use of classfile API

Reviewed-by: liach
This commit is contained in:
Shaojin Wen 2024-10-08 20:35:14 +00:00
parent 7312eea382
commit 62acc9c174
5 changed files with 323 additions and 342 deletions

View file

@ -394,10 +394,9 @@ import sun.invoke.util.Wrapper;
.invokespecial(CD_Object, INIT_NAME, MTD_void);
int parameterCount = factoryType.parameterCount();
for (int i = 0; i < parameterCount; i++) {
cob.aload(0);
Class<?> argType = factoryType.parameterType(i);
cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i));
cob.putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i])));
cob.aload(0)
.loadLocal(TypeKind.from(factoryType.parameterType(i)), cob.parameterSlot(i))
.putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i])));
}
cob.return_();
}

View file

@ -891,10 +891,9 @@ class InvokerBytecodeGenerator {
emitStaticInvoke(cob, invokeBasicName);
// goto L_done
cob.goto_w(L_done);
// L_fallback:
cob.labelBinding(L_fallback);
cob.goto_w(L_done)
// L_fallback:
.labelBinding(L_fallback);
// invoke selectAlternativeName.arguments[2]
System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
@ -945,26 +944,23 @@ class InvokerBytecodeGenerator {
.dropParameterTypes(0,1)
.changeReturnType(returnType);
cob.exceptionCatch(L_startBlock, L_endBlock, L_handler, CD_Throwable);
// Normal case
cob.labelBinding(L_startBlock);
cob.exceptionCatch(L_startBlock, L_endBlock, L_handler, CD_Throwable)
// Normal case
.labelBinding(L_startBlock);
// load target
emitPushArgument(cob, invoker, 0);
emitPushArguments(cob, args, 1); // skip 1st argument: method handle
cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType()));
cob.labelBinding(L_endBlock);
cob.goto_w(L_done);
// Exceptional case
cob.labelBinding(L_handler);
// Check exception's type
cob.dup();
cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType()))
.labelBinding(L_endBlock)
.goto_w(L_done)
// Exceptional case
.labelBinding(L_handler)
// Check exception's type
.dup();
// load exception class
emitPushArgument(cob, invoker, 1);
cob.swap();
cob.invokevirtual(CD_Class, "isInstance", MTD_boolean_Object);
cob.swap()
.invokevirtual(CD_Class, "isInstance", MTD_boolean_Object);
Label L_rethrow = cob.newLabel();
cob.ifeq(L_rethrow);
@ -974,13 +970,11 @@ class InvokerBytecodeGenerator {
cob.swap();
emitPushArguments(cob, args, 1); // skip 1st argument: method handle
MethodType catcherType = type.insertParameterTypes(0, Throwable.class);
cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(catcherType.basicType()));
cob.goto_w(L_done);
cob.labelBinding(L_rethrow);
cob.athrow();
cob.labelBinding(L_done);
cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(catcherType.basicType()))
.goto_w(L_done)
.labelBinding(L_rethrow)
.athrow()
.labelBinding(L_done);
return result;
}
@ -1075,8 +1069,8 @@ class InvokerBytecodeGenerator {
cob.labelBinding(lFrom);
emitPushArgument(cob, invoker, 0); // load target
emitPushArguments(cob, args, 1); // load args (skip 0: method handle)
cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType()));
cob.labelBinding(lTo);
cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType()))
.labelBinding(lTo);
// FINALLY_NORMAL:
int index = extendLocalsMap(new Class<?>[]{ returnType });
@ -1084,17 +1078,16 @@ class InvokerBytecodeGenerator {
emitStoreInsn(cob, basicReturnType.basicTypeKind(), index);
}
emitPushArgument(cob, invoker, 1); // load cleanup
cob.loadConstant(null);
cob.aconst_null();
if (isNonVoid) {
emitLoadInsn(cob, basicReturnType.basicTypeKind(), index);
}
emitPushArguments(cob, args, 1); // load args (skip 0: method handle)
cob.invokevirtual(CD_MethodHandle, "invokeBasic", cleanupDesc);
cob.goto_w(lDone);
// CATCH:
cob.labelBinding(lCatch);
cob.dup();
cob.invokevirtual(CD_MethodHandle, "invokeBasic", cleanupDesc)
.goto_w(lDone)
// CATCH:
.labelBinding(lCatch)
.dup();
// FINALLY_EXCEPTIONAL:
emitPushArgument(cob, invoker, 1); // load cleanup
@ -1107,10 +1100,9 @@ class InvokerBytecodeGenerator {
if (isNonVoid) {
emitPopInsn(cob, basicReturnType);
}
cob.athrow();
// DONE:
cob.labelBinding(lDone);
cob.athrow()
// DONE:
.labelBinding(lDone);
return result;
}
@ -1147,26 +1139,24 @@ class InvokerBytecodeGenerator {
}
emitPushArgument(cob, invoker, 0); // push switch input
cob.tableswitch(0, numCases - 1, defaultLabel, cases);
cob.labelBinding(defaultLabel);
cob.tableswitch(0, numCases - 1, defaultLabel, cases)
.labelBinding(defaultLabel);
emitPushArgument(cob, invoker, 1); // push default handle
emitPushArguments(cob, args, 1); // again, skip collector
cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor);
cob.goto_(endLabel);
cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor)
.goto_(endLabel);
for (int i = 0; i < numCases; i++) {
cob.labelBinding(cases.get(i).target());
// Load the particular case:
emitLoadInsn(cob, TypeKind.REFERENCE, casesLocal);
cob.loadConstant(i);
cob.aaload();
cob.loadConstant(i)
.aaload();
// invoke it:
emitPushArguments(cob, args, 1); // again, skip collector
cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor);
cob.goto_(endLabel);
cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor)
.goto_(endLabel);
}
cob.labelBinding(endLabel);
@ -1335,16 +1325,14 @@ class InvokerBytecodeGenerator {
// invoke fini
emitLoopHandleInvoke(cob, invoker, finis, c, args, true, finiType, loopLocalStateTypes, clauseDataIndex,
firstLoopStateIndex);
cob.goto_w(lDone);
// this is the beginning of the next loop clause
cob.labelBinding(lNext);
cob.goto_w(lDone)
// this is the beginning of the next loop clause
.labelBinding(lNext);
}
cob.goto_w(lLoop);
// DONE:
cob.labelBinding(lDone);
cob.goto_w(lLoop)
// DONE:
.labelBinding(lDone);
return result;
}
@ -1370,8 +1358,8 @@ class InvokerBytecodeGenerator {
int firstLoopStateSlot) {
// load handle for clause
emitPushClauseArray(cob, clauseDataSlot, handles);
cob.loadConstant(clause);
cob.aaload();
cob.loadConstant(clause)
.aaload();
// load loop state (preceding the other arguments)
if (pushLocalState) {
for (int s = 0; s < loopLocalStateTypes.length; ++s) {
@ -1385,8 +1373,8 @@ class InvokerBytecodeGenerator {
private void emitPushClauseArray(CodeBuilder cob, int clauseDataSlot, int which) {
emitLoadInsn(cob, TypeKind.REFERENCE, clauseDataSlot);
cob.loadConstant(which - 1);
cob.aaload();
cob.loadConstant(which - 1)
.aaload();
}
private void emitZero(CodeBuilder cob, BasicType type) {
@ -1519,14 +1507,14 @@ class InvokerBytecodeGenerator {
@Override
public void accept(CodeBuilder cob) {
// create parameter array
cob.loadConstant(invokerType.parameterCount());
cob.anewarray(CD_Object);
cob.loadConstant(invokerType.parameterCount())
.anewarray(CD_Object);
// fill parameter array
for (int i = 0; i < invokerType.parameterCount(); i++) {
Class<?> ptype = invokerType.parameterType(i);
cob.dup();
cob.loadConstant(i);
cob.dup()
.loadConstant(i);
emitLoadInsn(cob, basicType(ptype).basicTypeKind(), i);
// box if primitive type
if (ptype.isPrimitive()) {
@ -1535,10 +1523,10 @@ class InvokerBytecodeGenerator {
cob.aastore();
}
// invoke
cob.aload(0);
cob.getfield(CD_MethodHandle, "form", CD_LambdaForm);
cob.swap(); // swap form and array; avoid local variable
cob.invokevirtual(CD_LambdaForm, "interpretWithArguments", MethodTypeDescImpl.ofValidated(CD_Object, CD_Object_array));
cob.aload(0)
.getfield(CD_MethodHandle, "form", CD_LambdaForm)
.swap() // swap form and array; avoid local variable
.invokevirtual(CD_LambdaForm, "interpretWithArguments", MethodTypeDescImpl.ofValidated(CD_Object, CD_Object_array));
// maybe unbox
Class<?> rtype = invokerType.returnType();
@ -1592,9 +1580,9 @@ class InvokerBytecodeGenerator {
// Load arguments from array
for (int i = 0; i < dstType.parameterCount(); i++) {
cob.aload(1);
cob.loadConstant(i);
cob.aaload();
cob.aload(1)
.loadConstant(i)
.aaload();
// Maybe unbox
Class<?> dptype = dstType.parameterType(i);
@ -1645,9 +1633,9 @@ class InvokerBytecodeGenerator {
clb.withMethodBody("dummy", MTD_void, ACC_STATIC, new Consumer<>() {
@Override
public void accept(CodeBuilder cob) {
cob.ldc(os.toString());
cob.pop();
cob.return_();
cob.ldc(os.toString())
.pop()
.return_();
}
});
}

View file

@ -373,46 +373,43 @@ public class MethodHandleProxies {
String methodName, List<MethodInfo> methods) {
return ClassFile.of(ClassHierarchyResolverOption.of(ClassHierarchyResolver.ofClassLoading(loader)))
.build(proxyDesc, clb -> {
clb.withSuperclass(CD_Object);
clb.withFlags(ACC_FINAL | ACC_SYNTHETIC);
clb.withInterfaceSymbols(ifaceDesc);
// static and instance fields
clb.withField(TYPE_NAME, CD_Class, ACC_PRIVATE | ACC_STATIC | ACC_FINAL);
clb.withField(TARGET_NAME, CD_MethodHandle, ACC_PRIVATE | ACC_FINAL);
clb.withSuperclass(CD_Object)
.withFlags(ACC_FINAL | ACC_SYNTHETIC)
.withInterfaceSymbols(ifaceDesc)
// static and instance fields
.withField(TYPE_NAME, CD_Class, ACC_PRIVATE | ACC_STATIC | ACC_FINAL)
.withField(TARGET_NAME, CD_MethodHandle, ACC_PRIVATE | ACC_FINAL);
for (var mi : methods) {
clb.withField(mi.fieldName, CD_MethodHandle, ACC_PRIVATE | ACC_FINAL);
}
// <clinit>
clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, cob -> {
cob.loadConstant(ifaceDesc);
cob.putstatic(proxyDesc, TYPE_NAME, CD_Class);
cob.return_();
cob.loadConstant(ifaceDesc)
.putstatic(proxyDesc, TYPE_NAME, CD_Class)
.return_();
});
// <init>(Lookup, MethodHandle target, MethodHandle callerBoundTarget)
clb.withMethodBody(INIT_NAME, MTD_void_Lookup_MethodHandle_MethodHandle, 0, cob -> {
cob.aload(0);
cob.invokespecial(CD_Object, INIT_NAME, MTD_void);
// call ensureOriginalLookup to verify the given Lookup has access
cob.aload(1);
cob.invokestatic(proxyDesc, "ensureOriginalLookup", MTD_void_Lookup);
// this.target = target;
cob.aload(0);
cob.aload(2);
cob.putfield(proxyDesc, TARGET_NAME, CD_MethodHandle);
cob.aload(0)
.invokespecial(CD_Object, INIT_NAME, MTD_void)
// call ensureOriginalLookup to verify the given Lookup has access
.aload(1)
.invokestatic(proxyDesc, ENSURE_ORIGINAL_LOOKUP, MTD_void_Lookup)
// this.target = target;
.aload(0)
.aload(2)
.putfield(proxyDesc, TARGET_NAME, CD_MethodHandle);
// method handles adjusted to the method type of each method
for (var mi : methods) {
// this.m<i> = callerBoundTarget.asType(xxType);
cob.aload(0);
cob.aload(3);
cob.loadConstant(mi.desc);
cob.invokevirtual(CD_MethodHandle, "asType", MTD_MethodHandle_MethodType);
cob.putfield(proxyDesc, mi.fieldName, CD_MethodHandle);
cob.aload(0)
.aload(3)
.loadConstant(mi.desc)
.invokevirtual(CD_MethodHandle, "asType", MTD_MethodHandle_MethodType)
.putfield(proxyDesc, mi.fieldName, CD_MethodHandle);
}
// complete
@ -425,26 +422,26 @@ public class MethodHandleProxies {
clb.withMethodBody(ENSURE_ORIGINAL_LOOKUP, MTD_void_Lookup, ACC_PRIVATE | ACC_STATIC, cob -> {
var failLabel = cob.newLabel();
// check lookupClass
cob.aload(0);
cob.invokevirtual(CD_MethodHandles_Lookup, "lookupClass", MTD_Class);
cob.loadConstant(proxyDesc);
cob.if_acmpne(failLabel);
// check original access
cob.aload(0);
cob.invokevirtual(CD_MethodHandles_Lookup, "lookupModes", MTD_int);
cob.loadConstant(Lookup.ORIGINAL);
cob.iand();
cob.ifeq(failLabel);
// success
cob.return_();
// throw exception
cob.labelBinding(failLabel);
cob.new_(CD_IllegalAccessException);
cob.dup();
cob.aload(0); // lookup
cob.invokevirtual(CD_Object, "toString", MTD_String);
cob.invokespecial(CD_IllegalAccessException, INIT_NAME, MTD_void_String);
cob.athrow();
cob.aload(0)
.invokevirtual(CD_MethodHandles_Lookup, "lookupClass", MTD_Class)
.loadConstant(proxyDesc)
.if_acmpne(failLabel)
// check original access
.aload(0)
.invokevirtual(CD_MethodHandles_Lookup, "lookupModes", MTD_int)
.loadConstant(Lookup.ORIGINAL)
.iand()
.ifeq(failLabel)
// success
.return_()
// throw exception
.labelBinding(failLabel)
.new_(CD_IllegalAccessException)
.dup()
.aload(0) // lookup
.invokevirtual(CD_Object, "toString", MTD_String)
.invokespecial(CD_IllegalAccessException, INIT_NAME, MTD_void_String)
.athrow();
});
// implementation methods
@ -453,14 +450,14 @@ public class MethodHandleProxies {
clb.withMethodBody(methodName, mi.desc, ACC_PUBLIC, cob -> cob
.trying(bcb -> {
// return this.handleField.invokeExact(arguments...);
bcb.aload(0);
bcb.getfield(proxyDesc, mi.fieldName, CD_MethodHandle);
bcb.aload(0)
.getfield(proxyDesc, mi.fieldName, CD_MethodHandle);
for (int j = 0; j < mi.desc.parameterCount(); j++) {
bcb.loadLocal(TypeKind.from(mi.desc.parameterType(j)),
bcb.parameterSlot(j));
}
bcb.invokevirtual(CD_MethodHandle, "invokeExact", mi.desc);
bcb.return_(TypeKind.from(mi.desc.returnType()));
bcb.invokevirtual(CD_MethodHandle, "invokeExact", mi.desc)
.return_(TypeKind.from(mi.desc.returnType()));
}, ctb -> ctb
// catch (Error | RuntimeException | Declared ex) { throw ex; }
.catchingMulti(mi.thrown, CodeBuilder::athrow)

View file

@ -29,7 +29,6 @@ import java.lang.Enum.EnumDesc;
import java.lang.classfile.CodeBuilder;
import java.lang.constant.ClassDesc;
import java.lang.constant.ConstantDesc;
import java.lang.constant.ConstantDescs;
import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
@ -55,6 +54,7 @@ import jdk.internal.constant.ReferenceClassDescImpl;
import jdk.internal.misc.PreviewFeatures;
import jdk.internal.vm.annotation.Stable;
import static java.lang.constant.ConstantDescs.*;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
import java.util.Arrays;
@ -86,15 +86,15 @@ public class SwitchBootstraps {
private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;");
private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR =
MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, ConstantDescs.CD_int, ConstantDescs.CD_int);
private static final MethodTypeDesc MTD_TYPE_SWITCH = MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int,
ConstantDescs.CD_Object,
ConstantDescs.CD_int);
private static final MethodTypeDesc MTD_TYPE_SWITCH_EXTRA = MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int,
ConstantDescs.CD_Object,
ConstantDescs.CD_int,
MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_int);
private static final MethodTypeDesc MTD_TYPE_SWITCH = MethodTypeDescImpl.ofValidated(CD_int,
CD_Object,
CD_int);
private static final MethodTypeDesc MTD_TYPE_SWITCH_EXTRA = MethodTypeDescImpl.ofValidated(CD_int,
CD_Object,
CD_int,
CD_BiPredicate,
ConstantDescs.CD_List);
CD_List);
private static final MethodType MT_TYPE_SWITCH_EXTRA = MethodType.methodType(int.class,
Object.class,
int.class,
@ -484,19 +484,19 @@ public class SwitchBootstraps {
return cb -> {
// Objects.checkIndex(RESTART_IDX, labelConstants + 1)
cb.iload(RESTART_IDX);
cb.loadConstant(labelConstants.length + 1);
cb.invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR);
cb.pop();
cb.aload(SELECTOR_OBJ);
cb.iload(RESTART_IDX)
.loadConstant(labelConstants.length + 1)
.invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR)
.pop()
.aload(SELECTOR_OBJ);
Label nonNullLabel = cb.newLabel();
cb.ifnonnull(nonNullLabel);
cb.iconst_m1();
cb.ireturn();
cb.labelBinding(nonNullLabel);
cb.ifnonnull(nonNullLabel)
.iconst_m1()
.ireturn()
.labelBinding(nonNullLabel);
if (labelConstants.length == 0) {
cb.loadConstant(0)
.ireturn();
.ireturn();
return;
}
cb.iload(RESTART_IDX);
@ -535,132 +535,132 @@ public class SwitchBootstraps {
if (!selectorType.isPrimitive() && !Wrapper.isWrapperNumericOrBooleanType(selectorType)) {
// Object o = ...
// o instanceof Wrapped(float)
cb.aload(SELECTOR_OBJ);
cb.instanceOf(Wrapper.forBasicType(classLabel).wrapperClassDescriptor());
cb.ifeq(next);
cb.aload(SELECTOR_OBJ)
.instanceOf(Wrapper.forBasicType(classLabel).wrapperClassDescriptor())
.ifeq(next);
} else if (!unconditionalExactnessCheck(Wrapper.asPrimitiveType(selectorType), classLabel)) {
// Integer i = ... or int i = ...
// o instanceof float
Label notNumber = cb.newLabel();
cb.aload(SELECTOR_OBJ);
cb.instanceOf(ConstantDescs.CD_Number);
cb.aload(SELECTOR_OBJ)
.instanceOf(CD_Number);
if (selectorType == long.class || selectorType == float.class || selectorType == double.class ||
selectorType == Long.class || selectorType == Float.class || selectorType == Double.class) {
cb.ifeq(next);
} else {
cb.ifeq(notNumber);
}
cb.aload(SELECTOR_OBJ);
cb.checkcast(ConstantDescs.CD_Number);
cb.aload(SELECTOR_OBJ)
.checkcast(CD_Number);
if (selectorType == long.class || selectorType == Long.class) {
cb.invokevirtual(ConstantDescs.CD_Number,
cb.invokevirtual(CD_Number,
"longValue",
MethodTypeDesc.of(ConstantDescs.CD_long));
MethodTypeDesc.of(CD_long));
} else if (selectorType == float.class || selectorType == Float.class) {
cb.invokevirtual(ConstantDescs.CD_Number,
cb.invokevirtual(CD_Number,
"floatValue",
MethodTypeDesc.of(ConstantDescs.CD_float));
MethodTypeDesc.of(CD_float));
} else if (selectorType == double.class || selectorType == Double.class) {
cb.invokevirtual(ConstantDescs.CD_Number,
cb.invokevirtual(CD_Number,
"doubleValue",
MethodTypeDesc.of(ConstantDescs.CD_double));
MethodTypeDesc.of(CD_double));
} else {
Label compare = cb.newLabel();
cb.invokevirtual(ConstantDescs.CD_Number,
cb.invokevirtual(CD_Number,
"intValue",
MethodTypeDesc.of(ConstantDescs.CD_int));
cb.goto_(compare);
cb.labelBinding(notNumber);
cb.aload(SELECTOR_OBJ);
cb.instanceOf(ConstantDescs.CD_Character);
cb.ifeq(next);
cb.aload(SELECTOR_OBJ);
cb.checkcast(ConstantDescs.CD_Character);
cb.invokevirtual(ConstantDescs.CD_Character,
MethodTypeDesc.of(CD_int))
.goto_(compare)
.labelBinding(notNumber)
.aload(SELECTOR_OBJ)
.instanceOf(CD_Character)
.ifeq(next)
.aload(SELECTOR_OBJ)
.checkcast(CD_Character)
.invokevirtual(CD_Character,
"charValue",
MethodTypeDesc.of(ConstantDescs.CD_char));
cb.labelBinding(compare);
MethodTypeDesc.of(CD_char))
.labelBinding(compare);
}
TypePairs typePair = TypePairs.of(Wrapper.asPrimitiveType(selectorType), classLabel);
String methodName = TypePairs.typePairToName.get(typePair);
cb.invokestatic(referenceClassDesc(ExactConversionsSupport.class),
methodName,
MethodTypeDesc.of(ConstantDescs.CD_boolean, classDesc(typePair.from)));
cb.ifeq(next);
MethodTypeDesc.of(CD_boolean, classDesc(typePair.from)))
.ifeq(next);
}
} else {
Optional<ClassDesc> classLabelConstableOpt = classLabel.describeConstable();
if (classLabelConstableOpt.isPresent()) {
cb.aload(SELECTOR_OBJ);
cb.instanceOf(classLabelConstableOpt.orElseThrow());
cb.ifeq(next);
cb.aload(SELECTOR_OBJ)
.instanceOf(classLabelConstableOpt.orElseThrow())
.ifeq(next);
} else {
cb.aload(EXTRA_CLASS_LABELS);
cb.loadConstant(extraClassLabels.size());
cb.invokeinterface(ConstantDescs.CD_List,
cb.aload(EXTRA_CLASS_LABELS)
.loadConstant(extraClassLabels.size())
.invokeinterface(CD_List,
"get",
MethodTypeDesc.of(ConstantDescs.CD_Object,
ConstantDescs.CD_int));
cb.checkcast(ConstantDescs.CD_Class);
cb.aload(SELECTOR_OBJ);
cb.invokevirtual(ConstantDescs.CD_Class,
MethodTypeDesc.of(CD_Object,
CD_int))
.checkcast(CD_Class)
.aload(SELECTOR_OBJ)
.invokevirtual(CD_Class,
"isInstance",
MethodTypeDesc.of(ConstantDescs.CD_boolean,
ConstantDescs.CD_Object));
cb.ifeq(next);
MethodTypeDesc.of(CD_boolean,
CD_Object))
.ifeq(next);
extraClassLabels.add(classLabel);
}
}
} else if (caseLabel instanceof EnumDesc<?> enumLabel) {
int enumIdx = enumDescs.size();
enumDescs.add(enumLabel);
cb.aload(ENUM_CACHE);
cb.loadConstant(enumIdx);
cb.invokestatic(ConstantDescs.CD_Integer,
cb.aload(ENUM_CACHE)
.loadConstant(enumIdx)
.invokestatic(CD_Integer,
"valueOf",
MethodTypeDesc.of(ConstantDescs.CD_Integer,
ConstantDescs.CD_int));
cb.aload(SELECTOR_OBJ);
cb.invokeinterface(CD_BiPredicate,
MethodTypeDesc.of(CD_Integer,
CD_int))
.aload(SELECTOR_OBJ)
.invokeinterface(CD_BiPredicate,
"test",
MethodTypeDesc.of(ConstantDescs.CD_boolean,
ConstantDescs.CD_Object,
ConstantDescs.CD_Object));
cb.ifeq(next);
MethodTypeDesc.of(CD_boolean,
CD_Object,
CD_Object))
.ifeq(next);
} else if (caseLabel instanceof String stringLabel) {
cb.ldc(stringLabel);
cb.aload(SELECTOR_OBJ);
cb.invokevirtual(ConstantDescs.CD_Object,
cb.ldc(stringLabel)
.aload(SELECTOR_OBJ)
.invokevirtual(CD_Object,
"equals",
MethodTypeDesc.of(ConstantDescs.CD_boolean,
ConstantDescs.CD_Object));
cb.ifeq(next);
MethodTypeDesc.of(CD_boolean,
CD_Object))
.ifeq(next);
} else if (caseLabel instanceof Integer integerLabel) {
Label compare = cb.newLabel();
Label notNumber = cb.newLabel();
cb.aload(SELECTOR_OBJ);
cb.instanceOf(ConstantDescs.CD_Number);
cb.ifeq(notNumber);
cb.aload(SELECTOR_OBJ);
cb.checkcast(ConstantDescs.CD_Number);
cb.invokevirtual(ConstantDescs.CD_Number,
cb.aload(SELECTOR_OBJ)
.instanceOf(CD_Number)
.ifeq(notNumber)
.aload(SELECTOR_OBJ)
.checkcast(CD_Number)
.invokevirtual(CD_Number,
"intValue",
MethodTypeDesc.of(ConstantDescs.CD_int));
cb.goto_(compare);
cb.labelBinding(notNumber);
cb.aload(SELECTOR_OBJ);
cb.instanceOf(ConstantDescs.CD_Character);
cb.ifeq(next);
cb.aload(SELECTOR_OBJ);
cb.checkcast(ConstantDescs.CD_Character);
cb.invokevirtual(ConstantDescs.CD_Character,
MethodTypeDesc.of(CD_int))
.goto_(compare)
.labelBinding(notNumber)
.aload(SELECTOR_OBJ)
.instanceOf(CD_Character)
.ifeq(next)
.aload(SELECTOR_OBJ)
.checkcast(CD_Character)
.invokevirtual(CD_Character,
"charValue",
MethodTypeDesc.of(ConstantDescs.CD_char));
cb.labelBinding(compare);
MethodTypeDesc.of(CD_char))
.labelBinding(compare)
cb.loadConstant(integerLabel);
cb.if_icmpne(next);
.loadConstant(integerLabel)
.if_icmpne(next);
} else if ((caseLabel instanceof Long ||
caseLabel instanceof Float ||
caseLabel instanceof Double ||
@ -674,23 +674,23 @@ public class SwitchBootstraps {
cb.invokestatic(caseLabelWrapper.wrapperClassDescriptor(),
"valueOf",
MethodTypeDesc.of(caseLabelWrapper.wrapperClassDescriptor(),
caseLabelWrapper.basicClassDescriptor()));
cb.aload(SELECTOR_OBJ);
cb.invokevirtual(ConstantDescs.CD_Object,
caseLabelWrapper.basicClassDescriptor()))
.aload(SELECTOR_OBJ)
.invokevirtual(CD_Object,
"equals",
MethodTypeDesc.of(ConstantDescs.CD_boolean,
ConstantDescs.CD_Object));
cb.ifeq(next);
MethodTypeDesc.of(CD_boolean,
CD_Object))
.ifeq(next);
} else {
throw new InternalError("Unsupported label type: " +
caseLabel.getClass());
}
cb.loadConstant(idx);
cb.ireturn();
cb.loadConstant(idx)
.ireturn();
}
cb.labelBinding(dflt);
cb.loadConstant(labelConstants.length);
cb.ireturn();
cb.labelBinding(dflt)
.loadConstant(labelConstants.length)
.ireturn();
};
}