@@ -86,10 +86,10 @@ public void exitCompilationScope() {
8686 }
8787
8888 /**
89- * @return the descriptor for the item currently on top of the stack (in the current scope)
89+ * Return the descriptor for the item currently on top of the stack (in the current scope).
9090 */
9191 public String lastDescriptor () {
92- if (this .compilationScopes .peek ().size () == 0 ) {
92+ if (this .compilationScopes .peek ().isEmpty () ) {
9393 return null ;
9494 }
9595 return this .compilationScopes .peek ().get (this .compilationScopes .peek ().size () - 1 );
@@ -106,6 +106,7 @@ public void unboxBooleanIfNecessary(MethodVisitor mv) {
106106 }
107107 }
108108
109+
109110 /**
110111 * Insert any necessary cast and value call to convert from a boxed type to a
111112 * primitive value
@@ -115,56 +116,56 @@ public void unboxBooleanIfNecessary(MethodVisitor mv) {
115116 */
116117 public static void insertUnboxInsns (MethodVisitor mv , char ch , String stackDescriptor ) {
117118 switch (ch ) {
118- case 'I ' :
119- if (!stackDescriptor .equals ("Ljava/lang/Integer " )) {
120- mv .visitTypeInsn (CHECKCAST , "java/lang/Integer " );
121- }
122- mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Integer " , "intValue " , "()I " , false );
123- break ;
124- case 'Z ' :
125- if (!stackDescriptor .equals ("Ljava/lang/Boolean " )) {
126- mv .visitTypeInsn (CHECKCAST , "java/lang/Boolean " );
127- }
128- mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Boolean " , "booleanValue " , "()Z " , false );
129- break ;
130- case 'B ' :
131- if (!stackDescriptor .equals ("Ljava/lang/Byte " )) {
132- mv .visitTypeInsn (CHECKCAST , "java/lang/Byte " );
133- }
134- mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Byte " , "byteValue " , "()B " , false );
135- break ;
136- case 'C ' :
137- if (!stackDescriptor .equals ("Ljava/lang/Character " )) {
138- mv .visitTypeInsn (CHECKCAST , "java/lang/Character " );
139- }
140- mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Character " , "charValue " , "()C " , false );
141- break ;
142- case 'D ' :
143- if (!stackDescriptor .equals ("Ljava/lang/Double " )) {
144- mv .visitTypeInsn (CHECKCAST , "java/lang/Double " );
145- }
146- mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Double " , "doubleValue " , "()D " , false );
147- break ;
148- case 'S ' :
149- if (!stackDescriptor .equals ("Ljava/lang/Short " )) {
150- mv .visitTypeInsn (CHECKCAST , "java/lang/Short " );
151- }
152- mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Short " , "shortValue " , "()S " , false );
153- break ;
154- case 'F ' :
155- if (!stackDescriptor .equals ("Ljava/lang/Float " )) {
156- mv .visitTypeInsn (CHECKCAST , "java/lang/Float " );
157- }
158- mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Float " , "floatValue " , "()F " , false );
159- break ;
160- case 'J ' :
161- if (!stackDescriptor .equals ("Ljava/lang/Long " )) {
162- mv .visitTypeInsn (CHECKCAST , "java/lang/Long " );
163- }
164- mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Long " , "longValue " , "()J " , false );
165- break ;
166- default :
167- throw new IllegalArgumentException ("Unboxing should not be attempted for descriptor '" + ch + "'" );
119+ case 'Z ' :
120+ if (!stackDescriptor .equals ("Ljava/lang/Boolean " )) {
121+ mv .visitTypeInsn (CHECKCAST , "java/lang/Boolean " );
122+ }
123+ mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Boolean " , "booleanValue " , "()Z " , false );
124+ break ;
125+ case 'B ' :
126+ if (!stackDescriptor .equals ("Ljava/lang/Byte " )) {
127+ mv .visitTypeInsn (CHECKCAST , "java/lang/Byte " );
128+ }
129+ mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Byte " , "byteValue " , "()B " , false );
130+ break ;
131+ case 'C ' :
132+ if (!stackDescriptor .equals ("Ljava/lang/Character " )) {
133+ mv .visitTypeInsn (CHECKCAST , "java/lang/Character " );
134+ }
135+ mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Character " , "charValue " , "()C " , false );
136+ break ;
137+ case 'D ' :
138+ if (!stackDescriptor .equals ("Ljava/lang/Double " )) {
139+ mv .visitTypeInsn (CHECKCAST , "java/lang/Double " );
140+ }
141+ mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Double " , "doubleValue " , "()D " , false );
142+ break ;
143+ case 'F ' :
144+ if (!stackDescriptor .equals ("Ljava/lang/Float " )) {
145+ mv .visitTypeInsn (CHECKCAST , "java/lang/Float " );
146+ }
147+ mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Float " , "floatValue " , "()F " , false );
148+ break ;
149+ case 'I ' :
150+ if (!stackDescriptor .equals ("Ljava/lang/Integer " )) {
151+ mv .visitTypeInsn (CHECKCAST , "java/lang/Integer " );
152+ }
153+ mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Integer " , "intValue " , "()I " , false );
154+ break ;
155+ case 'J ' :
156+ if (!stackDescriptor .equals ("Ljava/lang/Long " )) {
157+ mv .visitTypeInsn (CHECKCAST , "java/lang/Long " );
158+ }
159+ mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Long " , "longValue " , "()J " , false );
160+ break ;
161+ case 'S ' :
162+ if (!stackDescriptor .equals ("Ljava/lang/Short " )) {
163+ mv .visitTypeInsn (CHECKCAST , "java/lang/Short " );
164+ }
165+ mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Short " , "shortValue " , "()S " , false );
166+ break ;
167+ default :
168+ throw new IllegalArgumentException ("Unboxing should not be attempted for descriptor '" + ch + "'" );
168169 }
169170 }
170171
@@ -182,10 +183,10 @@ public static String createSignatureDescriptor(Method method) {
182183 StringBuilder sb = new StringBuilder ();
183184 sb .append ("(" );
184185 for (Class <?> param : params ) {
185- sb .append (toJVMDescriptor (param ));
186+ sb .append (toJvmDescriptor (param ));
186187 }
187188 sb .append (")" );
188- sb .append (toJVMDescriptor (method .getReturnType ()));
189+ sb .append (toJvmDescriptor (method .getReturnType ()));
189190 return sb .toString ();
190191 }
191192
@@ -202,7 +203,7 @@ public static String createSignatureDescriptor(Constructor<?> ctor) {
202203 StringBuilder sb = new StringBuilder ();
203204 sb .append ("(" );
204205 for (Class <?> param : params ) {
205- sb .append (toJVMDescriptor (param ));
206+ sb .append (toJvmDescriptor (param ));
206207 }
207208 sb .append (")V" );
208209 return sb .toString ();
@@ -216,7 +217,7 @@ public static String createSignatureDescriptor(Constructor<?> ctor) {
216217 * @param clazz a class
217218 * @return the JVM descriptor for the class
218219 */
219- public static String toJVMDescriptor (Class <?> clazz ) {
220+ public static String toJvmDescriptor (Class <?> clazz ) {
220221 StringBuilder sb = new StringBuilder ();
221222 if (clazz .isArray ()) {
222223 while (clazz .isArray ()) {
@@ -319,37 +320,37 @@ public static boolean areBoxingCompatible(String desc1, String desc2) {
319320 return true ;
320321 }
321322 if (desc1 .length () == 1 ) {
322- if (desc1 .equals ("D" )) {
323+ if (desc1 .equals ("Z" )) {
324+ return desc2 .equals ("Ljava/lang/Boolean" );
325+ }
326+ else if (desc1 .equals ("D" )) {
323327 return desc2 .equals ("Ljava/lang/Double" );
324328 }
325329 else if (desc1 .equals ("F" )) {
326330 return desc2 .equals ("Ljava/lang/Float" );
327331 }
328- else if (desc1 .equals ("J" )) {
329- return desc2 .equals ("Ljava/lang/Long" );
330- }
331332 else if (desc1 .equals ("I" )) {
332333 return desc2 .equals ("Ljava/lang/Integer" );
333334 }
334- else if (desc1 .equals ("Z " )) {
335- return desc2 .equals ("Ljava/lang/Boolean " );
335+ else if (desc1 .equals ("J " )) {
336+ return desc2 .equals ("Ljava/lang/Long " );
336337 }
337338 }
338339 else if (desc2 .length () == 1 ) {
339- if (desc2 .equals ("D" )) {
340+ if (desc2 .equals ("Z" )) {
341+ return desc1 .equals ("Ljava/lang/Boolean" );
342+ }
343+ else if (desc2 .equals ("D" )) {
340344 return desc1 .equals ("Ljava/lang/Double" );
341345 }
342346 else if (desc2 .equals ("F" )) {
343347 return desc1 .equals ("Ljava/lang/Float" );
344348 }
345- else if (desc2 .equals ("J" )) {
346- return desc1 .equals ("Ljava/lang/Long" );
347- }
348349 else if (desc2 .equals ("I" )) {
349350 return desc1 .equals ("Ljava/lang/Integer" );
350351 }
351- else if (desc2 .equals ("Z " )) {
352- return desc1 .equals ("Ljava/lang/Boolean " );
352+ else if (desc2 .equals ("J " )) {
353+ return desc1 .equals ("Ljava/lang/Long " );
353354 }
354355 }
355356 return false ;
@@ -366,17 +367,10 @@ public static boolean isPrimitiveOrUnboxableSupportedNumberOrBoolean(String desc
366367 if (descriptor == null ) {
367368 return false ;
368369 }
369- if (descriptor .length ( )== 1 ) {
370- return ("DFJZI" .indexOf (descriptor .charAt (0 )) != -1 );
371- }
372- if (descriptor .startsWith ("Ljava/lang/" )) {
373- if (descriptor .equals ("Ljava/lang/Double" ) || descriptor .equals ("Ljava/lang/Integer" ) ||
374- descriptor .equals ("Ljava/lang/Float" ) || descriptor .equals ("Ljava/lang/Long" ) ||
375- descriptor .equals ("Ljava/lang/Boolean" )) {
376- return true ;
377- }
370+ if (isPrimitiveOrUnboxableSupportedNumber (descriptor )) {
371+ return true ;
378372 }
379- return false ;
373+ return ( "Z" . equals ( descriptor ) || descriptor . equals ( "Ljava/lang/Boolean" )) ;
380374 }
381375
382376 /**
@@ -391,17 +385,27 @@ public static boolean isPrimitiveOrUnboxableSupportedNumber(String descriptor) {
391385 return false ;
392386 }
393387 if (descriptor .length () == 1 ) {
394- return ( "DFJI" . indexOf (descriptor . charAt ( 0 )) != - 1 );
388+ return "DFIJ" . contains (descriptor );
395389 }
396390 if (descriptor .startsWith ("Ljava/lang/" )) {
397- if ( descriptor . equals ( "Ljava/lang/Double" ) || descriptor .equals ("Ljava/lang/Integer" ) ||
398- descriptor .equals ("Ljava/lang/ Float" ) || descriptor .equals ("Ljava/lang/ Long" )) {
391+ String name = descriptor .substring ("Ljava/lang/" . length ());
392+ if ( name .equals ("Double" ) || name . equals ( " Float" ) || name .equals ("Integer" ) || name . equals ( " Long" )) {
399393 return true ;
400394 }
401395 }
402396 return false ;
403397 }
404398
399+ /**
400+ * Determine whether the given number is to be considered as an integer
401+ * for the purposes of a numeric operation at the bytecode level.
402+ * @param number the number to check
403+ * @return {@code true} if it is an {@link Integer}, {@link Short} or {@link Byte}
404+ */
405+ public static boolean isIntegerForNumericOp (Number number ) {
406+ return (number instanceof Integer || number instanceof Short || number instanceof Byte );
407+ }
408+
405409 /**
406410 * @param descriptor a descriptor for a type that should have a primitive representation
407411 * @return the single character descriptor for a primitive input descriptor
@@ -410,23 +414,32 @@ public static char toPrimitiveTargetDesc(String descriptor) {
410414 if (descriptor .length () == 1 ) {
411415 return descriptor .charAt (0 );
412416 }
413- if (descriptor .equals ("Ljava/lang/Double " )) {
414- return 'D ' ;
417+ else if (descriptor .equals ("Ljava/lang/Boolean " )) {
418+ return 'Z ' ;
415419 }
416- else if (descriptor .equals ("Ljava/lang/Integer" )) {
417- return 'I' ;
420+ else if (descriptor .equals ("Ljava/lang/Byte" )) {
421+ return 'B' ;
422+ }
423+ else if (descriptor .equals ("Ljava/lang/Character" )) {
424+ return 'C' ;
425+ }
426+ else if (descriptor .equals ("Ljava/lang/Double" )) {
427+ return 'D' ;
418428 }
419429 else if (descriptor .equals ("Ljava/lang/Float" )) {
420430 return 'F' ;
421431 }
432+ else if (descriptor .equals ("Ljava/lang/Integer" )) {
433+ return 'I' ;
434+ }
422435 else if (descriptor .equals ("Ljava/lang/Long" )) {
423436 return 'J' ;
424437 }
425- else if (descriptor .equals ("Ljava/lang/Boolean " )) {
426- return 'Z ' ;
438+ else if (descriptor .equals ("Ljava/lang/Short " )) {
439+ return 'S ' ;
427440 }
428441 else {
429- throw new IllegalStateException ("No primitive for '" + descriptor + "'" );
442+ throw new IllegalStateException ("No primitive for '" + descriptor + "'" );
430443 }
431444 }
432445
@@ -474,37 +487,37 @@ public static void insertBoxIfNecessary(MethodVisitor mv, String descriptor) {
474487 */
475488 public static void insertBoxIfNecessary (MethodVisitor mv , char ch ) {
476489 switch (ch ) {
477- case 'I ' :
478- mv .visitMethodInsn (INVOKESTATIC , "java/lang/Integer " , "valueOf" , "(I )Ljava/lang/Integer ;" , false );
479- break ;
480- case 'F ' :
481- mv .visitMethodInsn (INVOKESTATIC , "java/lang/Float " , "valueOf" , "(F )Ljava/lang/Float ;" , false );
482- break ;
483- case 'S ' :
484- mv .visitMethodInsn (INVOKESTATIC , "java/lang/Short " , "valueOf" , "(S )Ljava/lang/Short ;" , false );
485- break ;
486- case 'Z ' :
487- mv .visitMethodInsn (INVOKESTATIC , "java/lang/Boolean " , "valueOf" , "(Z )Ljava/lang/Boolean ;" , false );
488- break ;
489- case 'J ' :
490- mv .visitMethodInsn (INVOKESTATIC , "java/lang/Long " , "valueOf" , "(J )Ljava/lang/Long ;" , false );
491- break ;
492- case 'D ' :
493- mv .visitMethodInsn (INVOKESTATIC , "java/lang/Double " , "valueOf" , "(D )Ljava/lang/Double ;" , false );
494- break ;
495- case 'C ' :
496- mv .visitMethodInsn (INVOKESTATIC , "java/lang/Character " , "valueOf" , "(C )Ljava/lang/Character ;" , false );
497- break ;
498- case 'B ' :
499- mv .visitMethodInsn (INVOKESTATIC , "java/lang/Byte " , "valueOf" , "(B )Ljava/lang/Byte ;" , false );
500- break ;
501- case 'L' :
490+ case 'Z ' :
491+ mv .visitMethodInsn (INVOKESTATIC , "java/lang/Boolean " , "valueOf" , "(Z )Ljava/lang/Boolean ;" , false );
492+ break ;
493+ case 'B ' :
494+ mv .visitMethodInsn (INVOKESTATIC , "java/lang/Byte " , "valueOf" , "(B )Ljava/lang/Byte ;" , false );
495+ break ;
496+ case 'C ' :
497+ mv .visitMethodInsn (INVOKESTATIC , "java/lang/Character " , "valueOf" , "(C )Ljava/lang/Character ;" , false );
498+ break ;
499+ case 'D ' :
500+ mv .visitMethodInsn (INVOKESTATIC , "java/lang/Double " , "valueOf" , "(D )Ljava/lang/Double ;" , false );
501+ break ;
502+ case 'F ' :
503+ mv .visitMethodInsn (INVOKESTATIC , "java/lang/Float " , "valueOf" , "(F )Ljava/lang/Float ;" , false );
504+ break ;
505+ case 'I ' :
506+ mv .visitMethodInsn (INVOKESTATIC , "java/lang/Integer " , "valueOf" , "(I )Ljava/lang/Integer ;" , false );
507+ break ;
508+ case 'J ' :
509+ mv .visitMethodInsn (INVOKESTATIC , "java/lang/Long " , "valueOf" , "(J )Ljava/lang/Long ;" , false );
510+ break ;
511+ case 'S ' :
512+ mv .visitMethodInsn (INVOKESTATIC , "java/lang/Short " , "valueOf" , "(S )Ljava/lang/Short ;" , false );
513+ break ;
514+ case 'L' :
502515 case 'V' :
503- case '[' :
504- // no box needed
505- break ;
506- default :
507- throw new IllegalArgumentException ("Boxing should not be attempted for descriptor '" + ch + "'" );
516+ case '[' :
517+ // no box needed
518+ break ;
519+ default :
520+ throw new IllegalArgumentException ("Boxing should not be attempted for descriptor '" + ch + "'" );
508521 }
509522 }
510523
@@ -522,14 +535,14 @@ public static String toDescriptor(Class<?> type) {
522535 case 3 :
523536 return "I" ;
524537 case 4 :
525- if (name .equals ("long " )) {
526- return "J " ;
538+ if (name .equals ("byte " )) {
539+ return "B " ;
527540 }
528541 else if (name .equals ("char" )) {
529542 return "C" ;
530543 }
531- else if (name .equals ("byte " )) {
532- return "B " ;
544+ else if (name .equals ("long " )) {
545+ return "J " ;
533546 }
534547 else if (name .equals ("void" )) {
535548 return "V" ;
0 commit comments