2727
2828import java .lang .Enum .EnumDesc ;
2929import java .lang .classfile .CodeBuilder ;
30+ import java .lang .classfile .attribute .StackMapFrameInfo ;
31+ import java .lang .classfile .attribute .StackMapTableAttribute ;
3032import java .lang .constant .ClassDesc ;
3133import java .lang .constant .ConstantDesc ;
3234import java .lang .constant .MethodTypeDesc ;
4850import java .lang .classfile .Label ;
4951import java .lang .classfile .instruction .SwitchCase ;
5052
53+ import jdk .internal .classfile .impl .DirectCodeBuilder ;
5154import jdk .internal .constant .ClassOrInterfaceDescImpl ;
5255import jdk .internal .constant .ConstantUtils ;
5356import jdk .internal .constant .MethodTypeDescImpl ;
@@ -103,6 +106,13 @@ private SwitchBootstraps() {}
103106 private static final MethodType MT_TYPE_SWITCH = MethodType .methodType (int .class ,
104107 Object .class ,
105108 int .class );
109+ private static final List <StackMapFrameInfo .VerificationTypeInfo > TYPE_SWITCH_LOCALS = List .of (
110+ StackMapFrameInfo .ObjectVerificationTypeInfo .of (CD_Object ), StackMapFrameInfo .SimpleVerificationTypeInfo .INTEGER
111+ );
112+ private static final List <StackMapFrameInfo .VerificationTypeInfo > TYPE_SWITCH_EXTRA_LOCALS = List .of (
113+ StackMapFrameInfo .ObjectVerificationTypeInfo .of (CD_Object ), StackMapFrameInfo .SimpleVerificationTypeInfo .INTEGER ,
114+ StackMapFrameInfo .ObjectVerificationTypeInfo .of (CD_BiPredicate ), StackMapFrameInfo .ObjectVerificationTypeInfo .of (CD_List )
115+ );
106116
107117 private static class StaticHolders {
108118 private static final MethodHandle MAPPED_ENUM_SWITCH ;
@@ -482,8 +492,11 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
482492 int ENUM_CACHE = 2 ;
483493 int EXTRA_CLASS_LABELS = 3 ;
484494
495+ var locals = enumDescs == null && extraClassLabels == null ? TYPE_SWITCH_LOCALS : TYPE_SWITCH_EXTRA_LOCALS ;
496+
485497 return cb -> {
486498 // Objects.checkIndex(RESTART_IDX, labelConstants + 1)
499+ var stackMapFrames = new ArrayList <StackMapFrameInfo >(labelConstants .length * 2 );
487500 cb .iload (RESTART_IDX )
488501 .loadConstant (labelConstants .length + 1 )
489502 .invokestatic (CD_Objects , "checkIndex" , CHECK_INDEX_DESCRIPTOR )
@@ -494,9 +507,12 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
494507 .iconst_m1 ()
495508 .ireturn ()
496509 .labelBinding (nonNullLabel );
510+ stackMapFrames .add (StackMapFrameInfo .of (nonNullLabel , locals , List .of ()));
497511 if (labelConstants .length == 0 ) {
498512 cb .loadConstant (0 )
499- .ireturn ();
513+ .ireturn ()
514+ .with (StackMapTableAttribute .of (stackMapFrames ));
515+ DirectCodeBuilder .withMaxs (cb , 2 , locals .size ()); // checkIndex uses 2
500516 return ;
501517 }
502518 cb .iload (RESTART_IDX );
@@ -509,6 +525,7 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
509525 for (int idx = labelConstants .length - 1 ; idx >= 0 ; idx --) {
510526 Object currentLabel = labelConstants [idx ];
511527 Label target = cb .newLabel ();
528+ stackMapFrames .add (StackMapFrameInfo .of (target , locals , List .of ()));
512529 Label next ;
513530 if (lastLabel == null ) {
514531 next = dflt ;
@@ -541,7 +558,7 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
541558 } else if (!unconditionalExactnessCheck (Wrapper .asPrimitiveType (selectorType ), classLabel )) {
542559 // Integer i = ... or int i = ...
543560 // o instanceof float
544- Label notNumber = cb .newLabel ();
561+ Label notNumber = cb .newLabel (); // this label may end up unbound
545562 cb .aload (SELECTOR_OBJ )
546563 .instanceOf (CD_Number );
547564 if (selectorType == long .class || selectorType == float .class || selectorType == double .class ||
@@ -570,8 +587,9 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
570587 "intValue" ,
571588 MethodTypeDesc .of (CD_int ))
572589 .goto_ (compare )
573- .labelBinding (notNumber )
574- .aload (SELECTOR_OBJ )
590+ .labelBinding (notNumber );
591+ stackMapFrames .add (StackMapFrameInfo .of (notNumber , locals , List .of ()));
592+ cb .aload (SELECTOR_OBJ )
575593 .instanceOf (CD_Character )
576594 .ifeq (next )
577595 .aload (SELECTOR_OBJ )
@@ -580,6 +598,7 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
580598 "charValue" ,
581599 MethodTypeDesc .of (CD_char ))
582600 .labelBinding (compare );
601+ stackMapFrames .add (StackMapFrameInfo .of (compare , locals , List .of (StackMapFrameInfo .SimpleVerificationTypeInfo .INTEGER )));
583602 }
584603
585604 TypePairs typePair = TypePairs .of (Wrapper .asPrimitiveType (selectorType ), classLabel );
@@ -648,18 +667,19 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
648667 "intValue" ,
649668 MethodTypeDesc .of (CD_int ))
650669 .goto_ (compare )
651- .labelBinding (notNumber )
652- .aload (SELECTOR_OBJ )
670+ .labelBinding (notNumber );
671+ stackMapFrames .add (StackMapFrameInfo .of (notNumber , locals , List .of ()));
672+ cb .aload (SELECTOR_OBJ )
653673 .instanceOf (CD_Character )
654674 .ifeq (next )
655675 .aload (SELECTOR_OBJ )
656676 .checkcast (CD_Character )
657677 .invokevirtual (CD_Character ,
658678 "charValue" ,
659679 MethodTypeDesc .of (CD_char ))
660- .labelBinding (compare )
661-
662- .loadConstant (integerLabel )
680+ .labelBinding (compare );
681+ stackMapFrames . add ( StackMapFrameInfo . of ( compare , locals , List . of ( StackMapFrameInfo . SimpleVerificationTypeInfo . INTEGER )));
682+ cb .loadConstant (integerLabel )
663683 .if_icmpne (next );
664684 } else if ((caseLabel instanceof Long ||
665685 caseLabel instanceof Float ||
@@ -688,9 +708,12 @@ private static Consumer<CodeBuilder> generateTypeSwitchSkeleton(Class<?> selecto
688708 cb .loadConstant (idx )
689709 .ireturn ();
690710 }
711+ stackMapFrames .add (StackMapFrameInfo .of (dflt , locals , List .of ()));
691712 cb .labelBinding (dflt )
692713 .loadConstant (labelConstants .length )
693- .ireturn ();
714+ .ireturn ()
715+ .with (StackMapTableAttribute .of (stackMapFrames ));
716+ DirectCodeBuilder .withMaxs (cb , 3 , locals .size ()); // enum labels use 3 stack, others use 2
694717 };
695718 }
696719
@@ -702,7 +725,7 @@ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Clas
702725 List <EnumDesc <?>> enumDescs = addExtraInfo ? new ArrayList <>() : null ;
703726 List <Class <?>> extraClassLabels = addExtraInfo ? new ArrayList <>() : null ;
704727
705- byte [] classBytes = ClassFile .of ().build (ConstantUtils .binaryNameToDesc (typeSwitchClassName (caller .lookupClass ())),
728+ byte [] classBytes = ClassFile .of (ClassFile . StackMapsOption . DROP_STACK_MAPS ).build (ConstantUtils .binaryNameToDesc (typeSwitchClassName (caller .lookupClass ())),
706729 clb -> {
707730 clb .withFlags (AccessFlag .FINAL , AccessFlag .SUPER , AccessFlag .SYNTHETIC )
708731 .withMethodBody ("typeSwitch" ,
0 commit comments