< prev index next >

src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java

Print this page

 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;
< prev index next >