2626package java .lang .runtime ;
2727
2828import java .lang .Enum .EnumDesc ;
29+ import java .lang .classfile .ClassBuilder ;
2930import java .lang .classfile .CodeBuilder ;
3031import java .lang .constant .ClassDesc ;
3132import java .lang .constant .ConstantDesc ;
4849import java .lang .classfile .ClassFile ;
4950import java .lang .classfile .Label ;
5051import java .lang .classfile .instruction .SwitchCase ;
52+
53+ import jdk .internal .constant .ReferenceClassDescImpl ;
5154import jdk .internal .misc .PreviewFeatures ;
5255import jdk .internal .vm .annotation .Stable ;
5356
@@ -74,28 +77,38 @@ private SwitchBootstraps() {}
7477 private static final MethodHandles .Lookup LOOKUP = MethodHandles .lookup ();
7578 private static final boolean previewEnabled = PreviewFeatures .isEnabled ();
7679
77- private static final MethodHandle NULL_CHECK ;
78- private static final MethodHandle IS_ZERO ;
79- private static final MethodHandle CHECK_INDEX ;
80- private static final MethodHandle MAPPED_ENUM_LOOKUP ;
80+
81+ private static final MethodType TYPES_SWITCH_TYPE = MethodType .methodType (int .class ,
82+ Object .class ,
83+ int .class ,
84+ BiPredicate .class ,
85+ List .class );
8186
8287 private static final MethodTypeDesc TYPES_SWITCH_DESCRIPTOR =
8388 MethodTypeDesc .ofDescriptor ("(Ljava/lang/Object;ILjava/util/function/BiPredicate;Ljava/util/List;)I" );
84-
85- static {
86- try {
87- NULL_CHECK = LOOKUP .findStatic (Objects .class , "isNull" ,
88- MethodType .methodType (boolean .class , Object .class ));
89- IS_ZERO = LOOKUP .findStatic (SwitchBootstraps .class , "isZero" ,
90- MethodType .methodType (boolean .class , int .class ));
91- CHECK_INDEX = LOOKUP .findStatic (Objects .class , "checkIndex" ,
92- MethodType .methodType (int .class , int .class , int .class ));
93- MAPPED_ENUM_LOOKUP = LOOKUP .findStatic (SwitchBootstraps .class , "mappedEnumLookup" ,
94- MethodType .methodType (int .class , Enum .class , MethodHandles .Lookup .class ,
95- Class .class , EnumDesc [].class , EnumMap .class ));
96- }
97- catch (ReflectiveOperationException e ) {
98- throw new ExceptionInInitializerError (e );
89+ private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR =
90+ MethodTypeDesc .ofDescriptor ("(II)I" );
91+
92+ private static final ClassDesc CD_Objects = ReferenceClassDescImpl .ofValidated ("Ljava/util/Objects;" );
93+
94+ private static class StaticHolders {
95+ private static final MethodHandle NULL_CHECK ;
96+ private static final MethodHandle IS_ZERO ;
97+ private static final MethodHandle MAPPED_ENUM_LOOKUP ;
98+
99+ static {
100+ try {
101+ NULL_CHECK = LOOKUP .findStatic (Objects .class , "isNull" ,
102+ MethodType .methodType (boolean .class , Object .class ));
103+ IS_ZERO = LOOKUP .findStatic (SwitchBootstraps .class , "isZero" ,
104+ MethodType .methodType (boolean .class , int .class ));
105+ MAPPED_ENUM_LOOKUP = LOOKUP .findStatic (SwitchBootstraps .class , "mappedEnumLookup" ,
106+ MethodType .methodType (int .class , Enum .class , MethodHandles .Lookup .class ,
107+ Class .class , EnumDesc [].class , EnumMap .class ));
108+ }
109+ catch (ReflectiveOperationException e ) {
110+ throw new ExceptionInInitializerError (e );
111+ }
99112 }
100113 }
101114
@@ -163,14 +176,13 @@ public static CallSite typeSwitch(MethodHandles.Lookup lookup,
163176 || (!invocationType .returnType ().equals (int .class ))
164177 || !invocationType .parameterType (1 ).equals (int .class ))
165178 throw new IllegalArgumentException ("Illegal invocation type " + invocationType );
166- requireNonNull (labels );
167179
168- Stream .of (labels ).forEach (l -> verifyLabel (l , selectorType ));
180+ for (Object l : labels ) { // implicit null-check
181+ verifyLabel (l , selectorType );
182+ }
169183
170184 MethodHandle target = generateTypeSwitch (lookup , selectorType , labels );
171185
172- target = withIndexCheck (target , labels .length );
173-
174186 return new ConstantCallSite (target );
175187 }
176188
@@ -282,18 +294,17 @@ public static CallSite enumSwitch(MethodHandles.Lookup lookup,
282294 //else if (idx == 0) return mappingArray[selector.ordinal()]; //mapping array created lazily
283295 //else return "typeSwitch(labels)"
284296 MethodHandle body =
285- MethodHandles .guardWithTest (MethodHandles .dropArguments (NULL_CHECK , 0 , int .class ),
297+ MethodHandles .guardWithTest (MethodHandles .dropArguments (StaticHolders . NULL_CHECK , 0 , int .class ),
286298 MethodHandles .dropArguments (MethodHandles .constant (int .class , -1 ), 0 , int .class , Object .class ),
287- MethodHandles .guardWithTest (MethodHandles .dropArguments (IS_ZERO , 1 , Object .class ),
299+ MethodHandles .guardWithTest (MethodHandles .dropArguments (StaticHolders . IS_ZERO , 1 , Object .class ),
288300 generateTypeSwitch (lookup , invocationType .parameterType (0 ), labels ),
289- MethodHandles .insertArguments (MAPPED_ENUM_LOOKUP , 1 , lookup , enumClass , labels , new EnumMap ())));
301+ MethodHandles .insertArguments (StaticHolders . MAPPED_ENUM_LOOKUP , 1 , lookup , enumClass , labels , new EnumMap ())));
290302 target = MethodHandles .permuteArguments (body , MethodType .methodType (int .class , Object .class , int .class ), 1 , 0 );
291303 } else {
292304 target = generateTypeSwitch (lookup , invocationType .parameterType (0 ), labels );
293305 }
294306
295307 target = target .asType (invocationType );
296- target = withIndexCheck (target , labels .length );
297308
298309 return new ConstantCallSite (target );
299310 }
@@ -339,12 +350,6 @@ private static <T extends Enum<T>> int mappedEnumLookup(T value, MethodHandles.L
339350 return enumMap .map [value .ordinal ()];
340351 }
341352
342- private static MethodHandle withIndexCheck (MethodHandle target , int labelsCount ) {
343- MethodHandle checkIndex = MethodHandles .insertArguments (CHECK_INDEX , 1 , labelsCount + 1 );
344-
345- return MethodHandles .filterArguments (target , 1 , checkIndex );
346- }
347-
348353 private static final class ResolvedEnumLabels implements BiPredicate <Integer , Object > {
349354
350355 private final MethodHandles .Lookup lookup ;
@@ -407,6 +412,11 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
407412 int EXTRA_CLASS_LABELS = 3 ;
408413
409414 return cb -> {
415+ // Objects.checkIndex(RESTART_IDX, labelConstants + 1)
416+ cb .iload (RESTART_IDX );
417+ cb .loadConstant (labelConstants .length + 1 );
418+ cb .invokestatic (CD_Objects , "checkIndex" , CHECK_INDEX_DESCRIPTOR );
419+ cb .pop ();
410420 cb .aload (SELECTOR_OBJ );
411421 Label nonNullLabel = cb .newLabel ();
412422 cb .if_nonnull (nonNullLabel );
@@ -621,7 +631,7 @@ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Clas
621631 List <EnumDesc <?>> enumDescs = new ArrayList <>();
622632 List <Class <?>> extraClassLabels = new ArrayList <>();
623633
624- byte [] classBytes = ClassFile .of ().build (ClassDesc . of (typeSwitchClassName (caller .lookupClass ())),
634+ byte [] classBytes = ClassFile .of ().build (ReferenceClassDescImpl . ofValidatedBinaryName (typeSwitchClassName (caller .lookupClass ())),
625635 clb -> {
626636 clb .withFlags (AccessFlag .FINAL , AccessFlag .SUPER , AccessFlag .SYNTHETIC )
627637 .withMethodBody ("typeSwitch" ,
@@ -636,12 +646,8 @@ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Clas
636646 lookup = caller .defineHiddenClass (classBytes , true , NESTMATE , STRONG );
637647 MethodHandle typeSwitch = lookup .findStatic (lookup .lookupClass (),
638648 "typeSwitch" ,
639- MethodType .methodType (int .class ,
640- Object .class ,
641- int .class ,
642- BiPredicate .class ,
643- List .class ));
644- typeSwitch = MethodHandles .insertArguments (typeSwitch , 2 , new ResolvedEnumLabels (caller , enumDescs .toArray (EnumDesc []::new )),
649+ TYPES_SWITCH_TYPE );
650+ typeSwitch = MethodHandles .insertArguments (typeSwitch , 2 , new ResolvedEnumLabels (caller , enumDescs .toArray (new EnumDesc <?>[0 ])),
645651 List .copyOf (extraClassLabels ));
646652 typeSwitch = MethodHandles .explicitCastArguments (typeSwitch ,
647653 MethodType .methodType (int .class ,
0 commit comments