< prev index next >

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

Print this page

 33 import java.lang.invoke.ConstantCallSite;
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.invoke.MethodType;
 37 import java.lang.reflect.AccessFlag;
 38 import java.util.ArrayList;
 39 import java.util.List;
 40 import java.util.Objects;
 41 import java.util.Optional;
 42 import java.util.function.BiPredicate;
 43 import java.util.stream.Stream;
 44 import jdk.internal.access.SharedSecrets;
 45 import java.lang.classfile.ClassFile;
 46 import java.lang.classfile.Label;
 47 import java.lang.classfile.instruction.SwitchCase;
 48 import jdk.internal.vm.annotation.Stable;
 49 
 50 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
 51 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
 52 import static java.util.Objects.requireNonNull;

 53 
 54 /**
 55  * Bootstrap methods for linking {@code invokedynamic} call sites that implement
 56  * the selection functionality of the {@code switch} statement.  The bootstraps
 57  * take additional static arguments corresponding to the {@code case} labels
 58  * of the {@code switch}, implicitly numbered sequentially from {@code [0..N)}.
 59  *
 60  * @since 21
 61  */
 62 public class SwitchBootstraps {
 63 
 64     private SwitchBootstraps() {}
 65 
 66     private static final Object SENTINEL = new Object();
 67     private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
 68 
 69     private static final MethodHandle NULL_CHECK;
 70     private static final MethodHandle IS_ZERO;
 71     private static final MethodHandle CHECK_INDEX;
 72     private static final MethodHandle MAPPED_ENUM_LOOKUP;

370 
371     private static final class EnumMap {
372         @Stable
373         public int[] map;
374     }
375 
376     /*
377      * Construct test chains for labels inside switch, to handle switch repeats:
378      * switch (idx) {
379      *     case 0 -> if (selector matches label[0]) return 0;
380      *     case 1 -> if (selector matches label[1]) return 1;
381      *     ...
382      * }
383      */
384     @SuppressWarnings("removal")
385     private static MethodHandle generateInnerClass(MethodHandles.Lookup caller, Object[] labels) {
386         List<EnumDesc<?>> enumDescs = new ArrayList<>();
387         List<Class<?>> extraClassLabels = new ArrayList<>();
388 
389         byte[] classBytes = ClassFile.of().build(ClassDesc.of(typeSwitchClassName(caller.lookupClass())), clb -> {
390             clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC)
391                .withMethodBody("typeSwitch",
392                                TYPES_SWITCH_DESCRIPTOR,
393                                ClassFile.ACC_FINAL | ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC,
394                                cb -> {
395                     cb.aload(0);
396                     Label nonNullLabel = cb.newLabel();
397                     cb.if_nonnull(nonNullLabel);
398                     cb.iconst_m1();
399                     cb.ireturn();
400                     cb.labelBinding(nonNullLabel);
401                     if (labels.length == 0) {
402                         cb.constantInstruction(0)
403                           .ireturn();
404                         return ;
405                     }
406                     cb.iload(1);
407                     Label dflt = cb.newLabel();
408                     record Element(Label target, Label next, Object caseLabel) {}
409                     List<Element> cases = new ArrayList<>();
410                     List<SwitchCase> switchCases = new ArrayList<>();

 33 import java.lang.invoke.ConstantCallSite;
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.invoke.MethodType;
 37 import java.lang.reflect.AccessFlag;
 38 import java.util.ArrayList;
 39 import java.util.List;
 40 import java.util.Objects;
 41 import java.util.Optional;
 42 import java.util.function.BiPredicate;
 43 import java.util.stream.Stream;
 44 import jdk.internal.access.SharedSecrets;
 45 import java.lang.classfile.ClassFile;
 46 import java.lang.classfile.Label;
 47 import java.lang.classfile.instruction.SwitchCase;
 48 import jdk.internal.vm.annotation.Stable;
 49 
 50 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
 51 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
 52 import static java.util.Objects.requireNonNull;
 53 import jdk.internal.misc.PreviewFeatures;
 54 
 55 /**
 56  * Bootstrap methods for linking {@code invokedynamic} call sites that implement
 57  * the selection functionality of the {@code switch} statement.  The bootstraps
 58  * take additional static arguments corresponding to the {@code case} labels
 59  * of the {@code switch}, implicitly numbered sequentially from {@code [0..N)}.
 60  *
 61  * @since 21
 62  */
 63 public class SwitchBootstraps {
 64 
 65     private SwitchBootstraps() {}
 66 
 67     private static final Object SENTINEL = new Object();
 68     private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
 69 
 70     private static final MethodHandle NULL_CHECK;
 71     private static final MethodHandle IS_ZERO;
 72     private static final MethodHandle CHECK_INDEX;
 73     private static final MethodHandle MAPPED_ENUM_LOOKUP;

371 
372     private static final class EnumMap {
373         @Stable
374         public int[] map;
375     }
376 
377     /*
378      * Construct test chains for labels inside switch, to handle switch repeats:
379      * switch (idx) {
380      *     case 0 -> if (selector matches label[0]) return 0;
381      *     case 1 -> if (selector matches label[1]) return 1;
382      *     ...
383      * }
384      */
385     @SuppressWarnings("removal")
386     private static MethodHandle generateInnerClass(MethodHandles.Lookup caller, Object[] labels) {
387         List<EnumDesc<?>> enumDescs = new ArrayList<>();
388         List<Class<?>> extraClassLabels = new ArrayList<>();
389 
390         byte[] classBytes = ClassFile.of().build(ClassDesc.of(typeSwitchClassName(caller.lookupClass())), clb -> {
391             clb.withFlags(AccessFlag.FINAL, (PreviewFeatures.isEnabled())  ? AccessFlag.IDENTITY : AccessFlag.SUPER, AccessFlag.SYNTHETIC)
392                .withMethodBody("typeSwitch",
393                                TYPES_SWITCH_DESCRIPTOR,
394                                ClassFile.ACC_FINAL | ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC,
395                                cb -> {
396                     cb.aload(0);
397                     Label nonNullLabel = cb.newLabel();
398                     cb.if_nonnull(nonNullLabel);
399                     cb.iconst_m1();
400                     cb.ireturn();
401                     cb.labelBinding(nonNullLabel);
402                     if (labels.length == 0) {
403                         cb.constantInstruction(0)
404                           .ireturn();
405                         return ;
406                     }
407                     cb.iload(1);
408                     Label dflt = cb.newLabel();
409                     record Element(Label target, Label next, Object caseLabel) {}
410                     List<Element> cases = new ArrayList<>();
411                     List<SwitchCase> switchCases = new ArrayList<>();
< prev index next >