940 default: 941 throw new StringConcatException("Unhandled tag: " + el.getTag()); 942 } 943 mv.visitMethodInsn( 944 INVOKEVIRTUAL, 945 "java/lang/StringBuilder", 946 "append", 947 desc, 948 false 949 ); 950 } 951 } 952 953 if (DEBUG && mode.isExact()) { 954 /* 955 Exactness checks compare the final StringBuilder.capacity() with a resulting 956 String.length(). If these values disagree, that means StringBuilder had to perform 957 storage trimming, which defeats the purpose of exact strategies. 958 */ 959 960 mv.visitInsn(DUP); 961 962 mv.visitMethodInsn( 963 INVOKEVIRTUAL, 964 "java/lang/StringBuilder", 965 "capacity", 966 "()I", 967 false 968 ); 969 970 mv.visitIntInsn(ISTORE, 0); 971 972 mv.visitMethodInsn( 973 INVOKEVIRTUAL, 974 "java/lang/StringBuilder", 975 "toString", 976 "()Ljava/lang/String;", 977 false 978 ); 979 980 mv.visitInsn(DUP); 981 982 mv.visitMethodInsn( 983 INVOKEVIRTUAL, 984 "java/lang/String", 985 "length", 986 "()I", 987 false 988 ); 989 990 mv.visitIntInsn(ILOAD, 0); 991 992 Label l0 = new Label(); 993 mv.visitJumpInsn(IF_ICMPEQ, l0); 994 995 mv.visitTypeInsn(NEW, "java/lang/AssertionError"); 996 mv.visitInsn(DUP); 997 mv.visitLdcInsn("Failed exactness check"); 998 mv.visitMethodInsn(INVOKESPECIAL, 999 "java/lang/AssertionError", 1000 "<init>", 1001 "(Ljava/lang/Object;)V", 1002 false); 1003 mv.visitInsn(ATHROW); 1004 1005 mv.visitLabel(l0); 1006 } else { 1007 mv.visitMethodInsn( 1008 INVOKEVIRTUAL, 1009 "java/lang/StringBuilder", 1010 "toString", 1011 "()Ljava/lang/String;", 1012 false 1013 ); 1014 } 1015 1016 mv.visitInsn(ARETURN); 1017 1018 mv.visitMaxs(-1, -1); 1019 mv.visitEnd(); 1020 cw.visitEnd(); 1021 1022 Class<?> targetClass = lookup.lookupClass(); 1023 final byte[] classBytes = cw.toByteArray(); 1024 final Class<?> innerClass = UNSAFE.defineAnonymousClass(targetClass, classBytes, null); 1025 1026 try { 1027 UNSAFE.ensureClassInitialized(innerClass); 1028 return lookup.findStatic(innerClass, NAME_FACTORY, args); 1029 } catch (ReflectiveOperationException e) { 1030 throw new StringConcatException("Exception finding constructor", e); 1031 } 1032 } 1033 1034 private static String getSBAppendDesc(Class<?> cl) { | 940 default: 941 throw new StringConcatException("Unhandled tag: " + el.getTag()); 942 } 943 mv.visitMethodInsn( 944 INVOKEVIRTUAL, 945 "java/lang/StringBuilder", 946 "append", 947 desc, 948 false 949 ); 950 } 951 } 952 953 if (DEBUG && mode.isExact()) { 954 /* 955 Exactness checks compare the final StringBuilder.capacity() with a resulting 956 String.length(). If these values disagree, that means StringBuilder had to perform 957 storage trimming, which defeats the purpose of exact strategies. 958 */ 959 960 /* 961 The logic for this check is as follows: 962 963 Stack before: Op: 964 (SB) dup, dup 965 (SB, SB, SB) capacity() 966 (int, SB, SB) swap 967 (SB, int, SB) toString() 968 (S, int, SB) length() 969 (int, int, SB) if_icmpeq 970 (SB) <end> 971 972 Note that it leaves the same StringBuilder on exit, like the one on enter. 973 */ 974 975 mv.visitInsn(DUP); 976 mv.visitInsn(DUP); 977 978 mv.visitMethodInsn( 979 INVOKEVIRTUAL, 980 "java/lang/StringBuilder", 981 "capacity", 982 "()I", 983 false 984 ); 985 986 mv.visitInsn(SWAP); 987 988 mv.visitMethodInsn( 989 INVOKEVIRTUAL, 990 "java/lang/StringBuilder", 991 "toString", 992 "()Ljava/lang/String;", 993 false 994 ); 995 996 mv.visitMethodInsn( 997 INVOKEVIRTUAL, 998 "java/lang/String", 999 "length", 1000 "()I", 1001 false 1002 ); 1003 1004 Label l0 = new Label(); 1005 mv.visitJumpInsn(IF_ICMPEQ, l0); 1006 1007 mv.visitTypeInsn(NEW, "java/lang/AssertionError"); 1008 mv.visitInsn(DUP); 1009 mv.visitLdcInsn("Failed exactness check"); 1010 mv.visitMethodInsn(INVOKESPECIAL, 1011 "java/lang/AssertionError", 1012 "<init>", 1013 "(Ljava/lang/Object;)V", 1014 false); 1015 mv.visitInsn(ATHROW); 1016 1017 mv.visitLabel(l0); 1018 } 1019 1020 mv.visitMethodInsn( 1021 INVOKEVIRTUAL, 1022 "java/lang/StringBuilder", 1023 "toString", 1024 "()Ljava/lang/String;", 1025 false 1026 ); 1027 1028 mv.visitInsn(ARETURN); 1029 1030 mv.visitMaxs(-1, -1); 1031 mv.visitEnd(); 1032 cw.visitEnd(); 1033 1034 Class<?> targetClass = lookup.lookupClass(); 1035 final byte[] classBytes = cw.toByteArray(); 1036 final Class<?> innerClass = UNSAFE.defineAnonymousClass(targetClass, classBytes, null); 1037 1038 try { 1039 UNSAFE.ensureClassInitialized(innerClass); 1040 return lookup.findStatic(innerClass, NAME_FACTORY, args); 1041 } catch (ReflectiveOperationException e) { 1042 throw new StringConcatException("Exception finding constructor", e); 1043 } 1044 } 1045 1046 private static String getSBAppendDesc(Class<?> cl) { |