32 import java.lang.constant.ConstantDescs;
33 import java.lang.constant.MethodTypeDesc;
34 import java.lang.invoke.CallSite;
35 import java.lang.invoke.ConstantCallSite;
36 import java.lang.invoke.MethodHandle;
37 import java.lang.invoke.MethodHandles;
38 import java.lang.invoke.MethodType;
39 import java.lang.reflect.AccessFlag;
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Objects;
43 import java.util.Optional;
44 import java.util.function.BiPredicate;
45 import java.util.function.Consumer;
46 import java.util.stream.Stream;
47 import jdk.internal.access.SharedSecrets;
48 import java.lang.classfile.ClassFile;
49 import java.lang.classfile.Label;
50 import java.lang.classfile.instruction.SwitchCase;
51
52 import jdk.internal.constant.ConstantUtils;
53 import jdk.internal.constant.ReferenceClassDescImpl;
54 import jdk.internal.misc.PreviewFeatures;
55 import jdk.internal.vm.annotation.Stable;
56
57 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
58 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
59 import java.util.HashMap;
60 import java.util.Map;
61 import static java.util.Objects.requireNonNull;
62 import static jdk.internal.constant.ConstantUtils.classDesc;
63 import static jdk.internal.constant.ConstantUtils.referenceClassDesc;
64
65 import sun.invoke.util.Wrapper;
66
67 /**
68 * Bootstrap methods for linking {@code invokedynamic} call sites that implement
69 * the selection functionality of the {@code switch} statement. The bootstraps
70 * take additional static arguments corresponding to the {@code case} labels
71 * of the {@code switch}, implicitly numbered sequentially from {@code [0..N)}.
72 *
73 * @since 21
75 public class SwitchBootstraps {
76
77 private SwitchBootstraps() {}
78
79 private static final Object SENTINEL = new Object();
80 private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
81 private static final boolean previewEnabled = PreviewFeatures.isEnabled();
82
83
84 private static final MethodType TYPES_SWITCH_TYPE = MethodType.methodType(int.class,
85 Object.class,
86 int.class,
87 BiPredicate.class,
88 List.class);
89
90 private static final MethodTypeDesc TYPES_SWITCH_DESCRIPTOR =
91 MethodTypeDesc.ofDescriptor("(Ljava/lang/Object;ILjava/util/function/BiPredicate;Ljava/util/List;)I");
92 private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR =
93 MethodTypeDesc.ofDescriptor("(II)I");
94
95 private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;");
96
97 private static class StaticHolders {
98 private static final MethodHandle NULL_CHECK;
99 private static final MethodHandle IS_ZERO;
100 private static final MethodHandle MAPPED_ENUM_LOOKUP;
101
102 static {
103 try {
104 NULL_CHECK = LOOKUP.findStatic(Objects.class, "isNull",
105 MethodType.methodType(boolean.class, Object.class));
106 IS_ZERO = LOOKUP.findStatic(SwitchBootstraps.class, "isZero",
107 MethodType.methodType(boolean.class, int.class));
108 MAPPED_ENUM_LOOKUP = LOOKUP.findStatic(SwitchBootstraps.class, "mappedEnumLookup",
109 MethodType.methodType(int.class, Enum.class, MethodHandles.Lookup.class,
110 Class.class, EnumDesc[].class, EnumMap.class));
111 }
112 catch (ReflectiveOperationException e) {
113 throw new ExceptionInInitializerError(e);
114 }
115 }
617 element.caseLabel().getClass());
618 }
619 cb.loadConstant(idx);
620 cb.ireturn();
621 }
622 cb.labelBinding(dflt);
623 cb.loadConstant(cases.size());
624 cb.ireturn();
625 };
626 }
627
628 /*
629 * Construct the method handle that represents the method int typeSwitch(Object, int, BiPredicate, List)
630 */
631 private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Class<?> selectorType, Object[] labelConstants) {
632 List<EnumDesc<?>> enumDescs = new ArrayList<>();
633 List<Class<?>> extraClassLabels = new ArrayList<>();
634
635 byte[] classBytes = ClassFile.of().build(ConstantUtils.binaryNameToDesc(typeSwitchClassName(caller.lookupClass())),
636 clb -> {
637 clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC)
638 .withMethodBody("typeSwitch",
639 TYPES_SWITCH_DESCRIPTOR,
640 ClassFile.ACC_FINAL | ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC,
641 generateTypeSwitchSkeleton(selectorType, labelConstants, enumDescs, extraClassLabels));
642 });
643
644 try {
645 // this class is linked at the indy callsite; so define a hidden nestmate
646 MethodHandles.Lookup lookup;
647 lookup = caller.defineHiddenClass(classBytes, true, NESTMATE, STRONG);
648 MethodHandle typeSwitch = lookup.findStatic(lookup.lookupClass(),
649 "typeSwitch",
650 TYPES_SWITCH_TYPE);
651 typeSwitch = MethodHandles.insertArguments(typeSwitch, 2, new ResolvedEnumLabels(caller, enumDescs.toArray(new EnumDesc<?>[0])),
652 List.copyOf(extraClassLabels));
653 typeSwitch = MethodHandles.explicitCastArguments(typeSwitch,
654 MethodType.methodType(int.class,
655 selectorType,
656 int.class));
657 return typeSwitch;
|
32 import java.lang.constant.ConstantDescs;
33 import java.lang.constant.MethodTypeDesc;
34 import java.lang.invoke.CallSite;
35 import java.lang.invoke.ConstantCallSite;
36 import java.lang.invoke.MethodHandle;
37 import java.lang.invoke.MethodHandles;
38 import java.lang.invoke.MethodType;
39 import java.lang.reflect.AccessFlag;
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Objects;
43 import java.util.Optional;
44 import java.util.function.BiPredicate;
45 import java.util.function.Consumer;
46 import java.util.stream.Stream;
47 import jdk.internal.access.SharedSecrets;
48 import java.lang.classfile.ClassFile;
49 import java.lang.classfile.Label;
50 import java.lang.classfile.instruction.SwitchCase;
51
52 import jdk.internal.constant.ClassDescImpl;
53 import jdk.internal.constant.ConstantUtils;
54 import jdk.internal.misc.PreviewFeatures;
55 import jdk.internal.vm.annotation.Stable;
56
57 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
58 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
59 import java.util.HashMap;
60 import java.util.Map;
61 import static java.util.Objects.requireNonNull;
62 import static jdk.internal.constant.ConstantUtils.classDesc;
63 import static jdk.internal.constant.ConstantUtils.referenceClassDesc;
64
65 import sun.invoke.util.Wrapper;
66
67 /**
68 * Bootstrap methods for linking {@code invokedynamic} call sites that implement
69 * the selection functionality of the {@code switch} statement. The bootstraps
70 * take additional static arguments corresponding to the {@code case} labels
71 * of the {@code switch}, implicitly numbered sequentially from {@code [0..N)}.
72 *
73 * @since 21
75 public class SwitchBootstraps {
76
77 private SwitchBootstraps() {}
78
79 private static final Object SENTINEL = new Object();
80 private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
81 private static final boolean previewEnabled = PreviewFeatures.isEnabled();
82
83
84 private static final MethodType TYPES_SWITCH_TYPE = MethodType.methodType(int.class,
85 Object.class,
86 int.class,
87 BiPredicate.class,
88 List.class);
89
90 private static final MethodTypeDesc TYPES_SWITCH_DESCRIPTOR =
91 MethodTypeDesc.ofDescriptor("(Ljava/lang/Object;ILjava/util/function/BiPredicate;Ljava/util/List;)I");
92 private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR =
93 MethodTypeDesc.ofDescriptor("(II)I");
94
95 private static final ClassDesc CD_Objects = ClassDescImpl.ofValidated("Ljava/util/Objects;");
96
97 private static class StaticHolders {
98 private static final MethodHandle NULL_CHECK;
99 private static final MethodHandle IS_ZERO;
100 private static final MethodHandle MAPPED_ENUM_LOOKUP;
101
102 static {
103 try {
104 NULL_CHECK = LOOKUP.findStatic(Objects.class, "isNull",
105 MethodType.methodType(boolean.class, Object.class));
106 IS_ZERO = LOOKUP.findStatic(SwitchBootstraps.class, "isZero",
107 MethodType.methodType(boolean.class, int.class));
108 MAPPED_ENUM_LOOKUP = LOOKUP.findStatic(SwitchBootstraps.class, "mappedEnumLookup",
109 MethodType.methodType(int.class, Enum.class, MethodHandles.Lookup.class,
110 Class.class, EnumDesc[].class, EnumMap.class));
111 }
112 catch (ReflectiveOperationException e) {
113 throw new ExceptionInInitializerError(e);
114 }
115 }
617 element.caseLabel().getClass());
618 }
619 cb.loadConstant(idx);
620 cb.ireturn();
621 }
622 cb.labelBinding(dflt);
623 cb.loadConstant(cases.size());
624 cb.ireturn();
625 };
626 }
627
628 /*
629 * Construct the method handle that represents the method int typeSwitch(Object, int, BiPredicate, List)
630 */
631 private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Class<?> selectorType, Object[] labelConstants) {
632 List<EnumDesc<?>> enumDescs = new ArrayList<>();
633 List<Class<?>> extraClassLabels = new ArrayList<>();
634
635 byte[] classBytes = ClassFile.of().build(ConstantUtils.binaryNameToDesc(typeSwitchClassName(caller.lookupClass())),
636 clb -> {
637 clb.withFlags(AccessFlag.FINAL, (PreviewFeatures.isEnabled()) ? AccessFlag.IDENTITY : AccessFlag.SUPER, AccessFlag.SYNTHETIC)
638 .withMethodBody("typeSwitch",
639 TYPES_SWITCH_DESCRIPTOR,
640 ClassFile.ACC_FINAL | ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC,
641 generateTypeSwitchSkeleton(selectorType, labelConstants, enumDescs, extraClassLabels));
642 });
643
644 try {
645 // this class is linked at the indy callsite; so define a hidden nestmate
646 MethodHandles.Lookup lookup;
647 lookup = caller.defineHiddenClass(classBytes, true, NESTMATE, STRONG);
648 MethodHandle typeSwitch = lookup.findStatic(lookup.lookupClass(),
649 "typeSwitch",
650 TYPES_SWITCH_TYPE);
651 typeSwitch = MethodHandles.insertArguments(typeSwitch, 2, new ResolvedEnumLabels(caller, enumDescs.toArray(new EnumDesc<?>[0])),
652 List.copyOf(extraClassLabels));
653 typeSwitch = MethodHandles.explicitCastArguments(typeSwitch,
654 MethodType.methodType(int.class,
655 selectorType,
656 int.class));
657 return typeSwitch;
|