< prev index next >

src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java

Print this page




 165          * MethodHandle-based generator, that constructs its own byte[] array from
 166          * the arguments. It computes the required storage exactly.
 167          */
 168         MH_INLINE_SIZED_EXACT
 169     }
 170 
 171     /**
 172      * Enables debugging: this may print debugging messages, perform additional (non-neutral for performance)
 173      * checks, etc.
 174      */
 175     private static final boolean DEBUG;
 176 
 177     /**
 178      * Enables caching of strategy stubs. This may improve the linkage time by reusing the generated
 179      * code, at the expense of contaminating the profiles.
 180      */
 181     private static final boolean CACHE_ENABLE;
 182 
 183     private static final ConcurrentMap<Key, MethodHandle> CACHE;
 184 





 185     static {
 186         // Poke the privileged block once, taking everything we need:
 187         final Object[] values = new Object[3];
 188         AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
 189             values[0] = System.getProperty("java.lang.invoke.stringConcat");
 190             values[1] = Boolean.getBoolean("java.lang.invoke.stringConcat.cache");
 191             values[2] = Boolean.getBoolean("java.lang.invoke.stringConcat.debug");

 192             return null;
 193         });
 194 
 195         final String strategy = (String)  values[0];
 196         CACHE_ENABLE          = (Boolean) values[1];
 197         DEBUG                 = (Boolean) values[2];

 198 
 199         STRATEGY = (strategy == null) ? DEFAULT_STRATEGY : Strategy.valueOf(strategy);
 200         CACHE = CACHE_ENABLE ? new ConcurrentHashMap<>() : null;

 201     }
 202 
 203     private static final class Key {
 204         final MethodType mt;
 205         final Recipe recipe;
 206 
 207         public Key(MethodType mt, Recipe recipe) {
 208             this.mt = mt;
 209             this.recipe = recipe;
 210         }
 211 
 212         @Override
 213         public boolean equals(Object o) {
 214             if (this == o) return true;
 215             if (o == null || getClass() != o.getClass()) return false;
 216 
 217             Key key = (Key) o;
 218 
 219             if (!mt.equals(key.mt)) return false;
 220             if (!recipe.equals(key.recipe)) return false;


 535         }
 536 
 537         return doStringConcat(lookup, name, concatType, false, recipe, constants);
 538     }
 539 
 540     private static CallSite doStringConcat(MethodHandles.Lookup lookup,
 541                                            String name,
 542                                            MethodType concatType,
 543                                            boolean generateRecipe,
 544                                            String recipe,
 545                                            Object... constants) throws StringConcatException {
 546         Objects.requireNonNull(lookup, "Lookup is null");
 547         Objects.requireNonNull(name, "Name is null");
 548         Objects.requireNonNull(concatType, "Concat type is null");
 549         Objects.requireNonNull(constants, "Constants are null");
 550 
 551         for (Object o : constants) {
 552             Objects.requireNonNull(o, "Cannot accept null constants");
 553         }
 554 






 555         int cCount = 0;
 556         int oCount = 0;
 557         if (generateRecipe) {
 558             // Mock the recipe to reuse the concat generator code
 559             char[] value = new char[concatType.parameterCount()];
 560             Arrays.fill(value, TAG_ARG);
 561             recipe = new String(value);
 562             oCount = concatType.parameterCount();
 563         } else {
 564             Objects.requireNonNull(recipe, "Recipe is null");
 565 
 566             for (int i = 0; i < recipe.length(); i++) {
 567                 char c = recipe.charAt(i);
 568                 if (c == TAG_CONST) cCount++;
 569                 if (c == TAG_ARG)   oCount++;
 570             }
 571         }
 572 
 573         if (oCount != concatType.parameterCount()) {
 574             throw new StringConcatException(


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) {
1047             if (cl.isPrimitive()) {
1048                 if (cl == Integer.TYPE || cl == Byte.TYPE || cl == Short.TYPE) {
1049                     return "(I)Ljava/lang/StringBuilder;";
1050                 } else if (cl == Boolean.TYPE) {
1051                     return "(Z)Ljava/lang/StringBuilder;";
1052                 } else if (cl == Character.TYPE) {
1053                     return "(C)Ljava/lang/StringBuilder;";
1054                 } else if (cl == Double.TYPE) {
1055                     return "(D)Ljava/lang/StringBuilder;";
1056                 } else if (cl == Float.TYPE) {




 165          * MethodHandle-based generator, that constructs its own byte[] array from
 166          * the arguments. It computes the required storage exactly.
 167          */
 168         MH_INLINE_SIZED_EXACT
 169     }
 170 
 171     /**
 172      * Enables debugging: this may print debugging messages, perform additional (non-neutral for performance)
 173      * checks, etc.
 174      */
 175     private static final boolean DEBUG;
 176 
 177     /**
 178      * Enables caching of strategy stubs. This may improve the linkage time by reusing the generated
 179      * code, at the expense of contaminating the profiles.
 180      */
 181     private static final boolean CACHE_ENABLE;
 182 
 183     private static final ConcurrentMap<Key, MethodHandle> CACHE;
 184 
 185     /**
 186      * Dump generated classes to disk, for debugging purposes.
 187      */
 188     private static final ProxyClassesDumper DUMPER;
 189 
 190     static {
 191         // Poke the privileged block once, taking everything we need:
 192         final Object[] values = new Object[4];
 193         AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
 194             values[0] = System.getProperty("java.lang.invoke.stringConcat");
 195             values[1] = Boolean.getBoolean("java.lang.invoke.stringConcat.cache");
 196             values[2] = Boolean.getBoolean("java.lang.invoke.stringConcat.debug");
 197             values[3] = System.getProperty("java.lang.invoke.stringConcat.dumpClasses");
 198             return null;
 199         });
 200 
 201         final String strategy = (String)  values[0];
 202         CACHE_ENABLE          = (Boolean) values[1];
 203         DEBUG                 = (Boolean) values[2];
 204         final String dumpPath = (String)  values[3];
 205 
 206         STRATEGY = (strategy == null) ? DEFAULT_STRATEGY : Strategy.valueOf(strategy);
 207         CACHE = CACHE_ENABLE ? new ConcurrentHashMap<>() : null;
 208         DUMPER = (dumpPath == null) ? null : ProxyClassesDumper.getInstance(dumpPath);
 209     }
 210 
 211     private static final class Key {
 212         final MethodType mt;
 213         final Recipe recipe;
 214 
 215         public Key(MethodType mt, Recipe recipe) {
 216             this.mt = mt;
 217             this.recipe = recipe;
 218         }
 219 
 220         @Override
 221         public boolean equals(Object o) {
 222             if (this == o) return true;
 223             if (o == null || getClass() != o.getClass()) return false;
 224 
 225             Key key = (Key) o;
 226 
 227             if (!mt.equals(key.mt)) return false;
 228             if (!recipe.equals(key.recipe)) return false;


 543         }
 544 
 545         return doStringConcat(lookup, name, concatType, false, recipe, constants);
 546     }
 547 
 548     private static CallSite doStringConcat(MethodHandles.Lookup lookup,
 549                                            String name,
 550                                            MethodType concatType,
 551                                            boolean generateRecipe,
 552                                            String recipe,
 553                                            Object... constants) throws StringConcatException {
 554         Objects.requireNonNull(lookup, "Lookup is null");
 555         Objects.requireNonNull(name, "Name is null");
 556         Objects.requireNonNull(concatType, "Concat type is null");
 557         Objects.requireNonNull(constants, "Constants are null");
 558 
 559         for (Object o : constants) {
 560             Objects.requireNonNull(o, "Cannot accept null constants");
 561         }
 562 
 563         if ((lookup.lookupModes() & MethodHandles.Lookup.PRIVATE) == 0) {
 564             throw new StringConcatException(String.format(
 565                     "Invalid caller: %s",
 566                     lookup.lookupClass().getName()));
 567         }
 568 
 569         int cCount = 0;
 570         int oCount = 0;
 571         if (generateRecipe) {
 572             // Mock the recipe to reuse the concat generator code
 573             char[] value = new char[concatType.parameterCount()];
 574             Arrays.fill(value, TAG_ARG);
 575             recipe = new String(value);
 576             oCount = concatType.parameterCount();
 577         } else {
 578             Objects.requireNonNull(recipe, "Recipe is null");
 579 
 580             for (int i = 0; i < recipe.length(); i++) {
 581                 char c = recipe.charAt(i);
 582                 if (c == TAG_CONST) cCount++;
 583                 if (c == TAG_ARG)   oCount++;
 584             }
 585         }
 586 
 587         if (oCount != concatType.parameterCount()) {
 588             throw new StringConcatException(


1031                 mv.visitLabel(l0);
1032             }
1033 
1034             mv.visitMethodInsn(
1035                     INVOKEVIRTUAL,
1036                     "java/lang/StringBuilder",
1037                     "toString",
1038                     "()Ljava/lang/String;",
1039                     false
1040             );
1041 
1042             mv.visitInsn(ARETURN);
1043 
1044             mv.visitMaxs(-1, -1);
1045             mv.visitEnd();
1046             cw.visitEnd();
1047 
1048             Class<?> targetClass = lookup.lookupClass();
1049             final byte[] classBytes = cw.toByteArray();
1050             final Class<?> innerClass = UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
1051 
1052             if (DUMPER != null) {
1053                 DUMPER.dumpClass(innerClass.getName(), classBytes);
1054             }
1055 
1056             try {
1057                 UNSAFE.ensureClassInitialized(innerClass);
1058                 return lookup.findStatic(innerClass, NAME_FACTORY, args);
1059             } catch (ReflectiveOperationException e) {
1060                 throw new StringConcatException("Exception finding constructor", e);
1061             }
1062         }
1063 
1064         private static String getSBAppendDesc(Class<?> cl) {
1065             if (cl.isPrimitive()) {
1066                 if (cl == Integer.TYPE || cl == Byte.TYPE || cl == Short.TYPE) {
1067                     return "(I)Ljava/lang/StringBuilder;";
1068                 } else if (cl == Boolean.TYPE) {
1069                     return "(Z)Ljava/lang/StringBuilder;";
1070                 } else if (cl == Character.TYPE) {
1071                     return "(C)Ljava/lang/StringBuilder;";
1072                 } else if (cl == Double.TYPE) {
1073                     return "(D)Ljava/lang/StringBuilder;";
1074                 } else if (cl == Float.TYPE) {


< prev index next >