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<>();
|