< prev index next >

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java

Print this page
rev 15353 : 8164044: Generate the corresponding BoundMethodHandle to all generated DirectMethodHandles
Reviewed-by: vlivanov, mhaupt


  38 import jdk.tools.jlink.plugin.PluginException;
  39 import jdk.tools.jlink.plugin.ResourcePool;
  40 import jdk.tools.jlink.plugin.ResourcePoolBuilder;
  41 import jdk.tools.jlink.plugin.Plugin;
  42 
  43 /**
  44  * Plugin to generate java.lang.invoke classes.
  45  */
  46 public final class GenerateJLIClassesPlugin implements Plugin {
  47 
  48     private static final String NAME = "generate-jli-classes";
  49 
  50     private static final String BMH_PARAM = "bmh";
  51 
  52     private static final String BMH_SPECIES_PARAM = "bmh-species";
  53 
  54     private static final String DMH_PARAM = "dmh";
  55 
  56     private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
  57 
  58     private static final String DMH = "java/lang/invoke/DirectMethodHandle$Holder";
  59     private static final String DMH_INVOKE_VIRTUAL = "invokeVirtual";
  60     private static final String DMH_INVOKE_STATIC = "invokeStatic";
  61     private static final String DMH_INVOKE_SPECIAL = "invokeSpecial";
  62     private static final String DMH_NEW_INVOKE_SPECIAL = "newInvokeSpecial";
  63     private static final String DMH_INVOKE_INTERFACE = "invokeInterface";
  64     private static final String DMH_INVOKE_STATIC_INIT = "invokeStaticInit";
  65 


  66     private static final JavaLangInvokeAccess JLIA
  67             = SharedSecrets.getJavaLangInvokeAccess();
  68 
  69     List<String> speciesTypes;
  70 
  71     Map<String, List<String>> dmhMethods;
  72 
  73     public GenerateJLIClassesPlugin() {
  74     }
  75 
  76     @Override
  77     public String getName() {
  78         return NAME;
  79     }
  80 
  81     @Override
  82     public String getDescription() {
  83         return DESCRIPTION;
  84     }
  85 


 205                         expandSignature(typeParts[0]);
 206                     }
 207                 }
 208             }
 209             if (dmhMethods.isEmpty()) {
 210                 dmhMethods = defaultDMHMethods();
 211             }
 212         }
 213     }
 214 
 215     private static void requireBasicType(char c) {
 216         if ("LIJFD".indexOf(c) < 0) {
 217             throw new PluginException(
 218                     "Character " + c + " must correspond to a basic field type: LIJFD");
 219         }
 220     }
 221 
 222     @Override
 223     public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
 224         // Copy all but DMH_ENTRY to out
 225         in.transformAndCopy(entry -> entry.path().equals(DMH_ENTRY) ? null : entry, out);








 226         speciesTypes.forEach(types -> generateBMHClass(types, out));
 227         generateDMHClass(out);
 228         return out.build();
 229     }
 230 
 231     @SuppressWarnings("unchecked")
 232     private void generateBMHClass(String types, ResourcePoolBuilder out) {
 233         try {
 234             // Generate class
 235             Map.Entry<String, byte[]> result =
 236                     JLIA.generateConcreteBMHClassBytes(types);
 237             String className = result.getKey();
 238             byte[] bytes = result.getValue();
 239 
 240             // Add class to pool
 241             ResourcePoolEntry ndata = ResourcePoolEntry.create(
 242                     "/java.base/" + className + ".class",
 243                     bytes);
 244             out.add(ndata);
 245         } catch (Exception ex) {


 247         }
 248     }
 249 
 250     private void generateDMHClass(ResourcePoolBuilder out) {
 251         int count = 0;
 252         for (List<String> entry : dmhMethods.values()) {
 253             count += entry.size();
 254         }
 255         MethodType[] methodTypes = new MethodType[count];
 256         int[] dmhTypes = new int[count];
 257         int index = 0;
 258         for (Map.Entry<String, List<String>> entry : dmhMethods.entrySet()) {
 259             String dmhType = entry.getKey();
 260             for (String type : entry.getValue()) {
 261                 methodTypes[index] = asMethodType(type);
 262                 dmhTypes[index] = DMH_METHOD_TYPE_MAP.get(dmhType);
 263                 index++;
 264             }
 265         }
 266         try {
 267             byte[] bytes =
 268                     JLIA.generateDMHClassBytes(DMH, methodTypes, dmhTypes);
 269             ResourcePoolEntry ndata = ResourcePoolEntry.create(DMH_ENTRY, bytes);






 270             out.add(ndata);
 271         } catch (Exception ex) {
 272             throw new PluginException(ex);
 273         }
 274     }
 275     private static final String DMH_ENTRY = "/java.base/" + DMH + ".class";



 276 
 277     // Convert LL -> LL, L3 -> LLL
 278     private static String expandSignature(String signature) {
 279         StringBuilder sb = new StringBuilder();
 280         char last = 'X';
 281         int count = 0;
 282         for (int i = 0; i < signature.length(); i++) {
 283             char c = signature.charAt(i);
 284             if (c >= '0' && c <= '9') {
 285                 count *= 10;
 286                 count += (c - '0');
 287             } else {
 288                 requireBasicType(c);
 289                 for (int j = 1; j < count; j++) {
 290                     sb.append(last);
 291                 }
 292                 sb.append(c);
 293                 last = c;
 294                 count = 0;
 295             }
 296         }
 297 
 298         // ended with a number, e.g., "L2": append last char count - 1 times
 299         if (count > 1) {
 300             requireBasicType(last);
 301             for (int j = 1; j < count; j++) {
 302                 sb.append(last);
 303             }
 304         }
 305         return sb.toString();
 306     }
 307 
 308     private static MethodType asMethodType(String basicSignatureString) {
 309         String[] parts = basicSignatureString.split("_");
 310         assert(parts.length == 2);
 311         assert(parts[1].length() == 1);
 312         String parameters = expandSignature(parts[0]);
 313         Class<?> rtype = primitiveType(parts[1].charAt(0));
 314         Class<?>[] ptypes = new Class<?>[parameters.length()];



 315         for (int i = 0; i < ptypes.length; i++) {
 316             ptypes[i] = primitiveType(parameters.charAt(i));
 317         }
 318         return MethodType.methodType(rtype, ptypes);
 319     }

 320 
 321     private static Class<?> primitiveType(char c) {
 322         switch (c) {
 323             case 'F':
 324                 return float.class;
 325             case 'D':
 326                 return double.class;
 327             case 'I':
 328                 return int.class;
 329             case 'L':
 330                 return Object.class;
 331             case 'J':
 332                 return long.class;
 333             case 'V':
 334                 return void.class;
 335             case 'Z':
 336             case 'B':
 337             case 'S':
 338             case 'C':
 339                 throw new IllegalArgumentException("Not a valid primitive: " + c +
 340                         " (use I instead)");
 341             default:


  38 import jdk.tools.jlink.plugin.PluginException;
  39 import jdk.tools.jlink.plugin.ResourcePool;
  40 import jdk.tools.jlink.plugin.ResourcePoolBuilder;
  41 import jdk.tools.jlink.plugin.Plugin;
  42 
  43 /**
  44  * Plugin to generate java.lang.invoke classes.
  45  */
  46 public final class GenerateJLIClassesPlugin implements Plugin {
  47 
  48     private static final String NAME = "generate-jli-classes";
  49 
  50     private static final String BMH_PARAM = "bmh";
  51 
  52     private static final String BMH_SPECIES_PARAM = "bmh-species";
  53 
  54     private static final String DMH_PARAM = "dmh";
  55 
  56     private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
  57 
  58     private static final String DIRECT_METHOD_HANDLE = "java/lang/invoke/DirectMethodHandle$Holder";
  59     private static final String DMH_INVOKE_VIRTUAL = "invokeVirtual";
  60     private static final String DMH_INVOKE_STATIC = "invokeStatic";
  61     private static final String DMH_INVOKE_SPECIAL = "invokeSpecial";
  62     private static final String DMH_NEW_INVOKE_SPECIAL = "newInvokeSpecial";
  63     private static final String DMH_INVOKE_INTERFACE = "invokeInterface";
  64     private static final String DMH_INVOKE_STATIC_INIT = "invokeStaticInit";
  65 
  66     private static final String DELEGATING_METHOD_HANDLE = "java/lang/invoke/DelegatingMethodHandle$Holder";
  67 
  68     private static final JavaLangInvokeAccess JLIA
  69             = SharedSecrets.getJavaLangInvokeAccess();
  70 
  71     List<String> speciesTypes;
  72 
  73     Map<String, List<String>> dmhMethods;
  74 
  75     public GenerateJLIClassesPlugin() {
  76     }
  77 
  78     @Override
  79     public String getName() {
  80         return NAME;
  81     }
  82 
  83     @Override
  84     public String getDescription() {
  85         return DESCRIPTION;
  86     }
  87 


 207                         expandSignature(typeParts[0]);
 208                     }
 209                 }
 210             }
 211             if (dmhMethods.isEmpty()) {
 212                 dmhMethods = defaultDMHMethods();
 213             }
 214         }
 215     }
 216 
 217     private static void requireBasicType(char c) {
 218         if ("LIJFD".indexOf(c) < 0) {
 219             throw new PluginException(
 220                     "Character " + c + " must correspond to a basic field type: LIJFD");
 221         }
 222     }
 223 
 224     @Override
 225     public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
 226         // Copy all but DMH_ENTRY to out
 227         in.transformAndCopy(entry -> {
 228                 // filter out placeholder entries
 229                 if (entry.path().equals(DIRECT_METHOD_HANDLE_ENTRY) ||
 230                     entry.path().equals(DELEGATING_METHOD_HANDLE_ENTRY)) {
 231                     return null;
 232                 } else {
 233                     return entry;
 234                 }
 235             }, out);
 236         speciesTypes.forEach(types -> generateBMHClass(types, out));
 237         generateDMHClass(out);
 238         return out.build();
 239     }
 240 
 241     @SuppressWarnings("unchecked")
 242     private void generateBMHClass(String types, ResourcePoolBuilder out) {
 243         try {
 244             // Generate class
 245             Map.Entry<String, byte[]> result =
 246                     JLIA.generateConcreteBMHClassBytes(types);
 247             String className = result.getKey();
 248             byte[] bytes = result.getValue();
 249 
 250             // Add class to pool
 251             ResourcePoolEntry ndata = ResourcePoolEntry.create(
 252                     "/java.base/" + className + ".class",
 253                     bytes);
 254             out.add(ndata);
 255         } catch (Exception ex) {


 257         }
 258     }
 259 
 260     private void generateDMHClass(ResourcePoolBuilder out) {
 261         int count = 0;
 262         for (List<String> entry : dmhMethods.values()) {
 263             count += entry.size();
 264         }
 265         MethodType[] methodTypes = new MethodType[count];
 266         int[] dmhTypes = new int[count];
 267         int index = 0;
 268         for (Map.Entry<String, List<String>> entry : dmhMethods.entrySet()) {
 269             String dmhType = entry.getKey();
 270             for (String type : entry.getValue()) {
 271                 methodTypes[index] = asMethodType(type);
 272                 dmhTypes[index] = DMH_METHOD_TYPE_MAP.get(dmhType);
 273                 index++;
 274             }
 275         }
 276         try {
 277             byte[] bytes = JLIA.generateDirectMethodHandleHolderClassBytes(
 278                     DIRECT_METHOD_HANDLE, methodTypes, dmhTypes);
 279             ResourcePoolEntry ndata = ResourcePoolEntry
 280                     .create(DIRECT_METHOD_HANDLE_ENTRY, bytes);
 281             out.add(ndata);
 282 
 283             bytes = JLIA.generateDelegatingMethodHandleHolderClassBytes(
 284                     DELEGATING_METHOD_HANDLE, methodTypes);
 285             ndata = ResourcePoolEntry.create(DELEGATING_METHOD_HANDLE_ENTRY, bytes);
 286             out.add(ndata);
 287         } catch (Exception ex) {
 288             throw new PluginException(ex);
 289         }
 290     }
 291     private static final String DIRECT_METHOD_HANDLE_ENTRY =
 292             "/java.base/" + DIRECT_METHOD_HANDLE + ".class";
 293     private static final String DELEGATING_METHOD_HANDLE_ENTRY =
 294             "/java.base/" + DELEGATING_METHOD_HANDLE + ".class";
 295 
 296     // Convert LL -> LL, L3 -> LLL
 297     private static String expandSignature(String signature) {
 298         StringBuilder sb = new StringBuilder();
 299         char last = 'X';
 300         int count = 0;
 301         for (int i = 0; i < signature.length(); i++) {
 302             char c = signature.charAt(i);
 303             if (c >= '0' && c <= '9') {
 304                 count *= 10;
 305                 count += (c - '0');
 306             } else {
 307                 requireBasicType(c);
 308                 for (int j = 1; j < count; j++) {
 309                     sb.append(last);
 310                 }
 311                 sb.append(c);
 312                 last = c;
 313                 count = 0;
 314             }
 315         }
 316 
 317         // ended with a number, e.g., "L2": append last char count - 1 times
 318         if (count > 1) {
 319             requireBasicType(last);
 320             for (int j = 1; j < count; j++) {
 321                 sb.append(last);
 322             }
 323         }
 324         return sb.toString();
 325     }
 326 
 327     private static MethodType asMethodType(String basicSignatureString) {
 328         String[] parts = basicSignatureString.split("_");
 329         assert(parts.length == 2);
 330         assert(parts[1].length() == 1);
 331         String parameters = expandSignature(parts[0]);
 332         Class<?> rtype = simpleType(parts[1].charAt(0));
 333         Class<?>[] ptypes = new Class<?>[parameters.length()];
 334         if (ptypes.length == 0) {
 335             return MethodType.methodType(rtype);
 336         } else {
 337             for (int i = 0; i < ptypes.length; i++) {
 338                 ptypes[i] = simpleType(parameters.charAt(i));
 339             }
 340             return MethodType.methodType(rtype, ptypes);
 341         }
 342     }
 343 
 344     private static Class<?> simpleType(char c) {
 345         switch (c) {
 346             case 'F':
 347                 return float.class;
 348             case 'D':
 349                 return double.class;
 350             case 'I':
 351                 return int.class;
 352             case 'L':
 353                 return Object.class;
 354             case 'J':
 355                 return long.class;
 356             case 'V':
 357                 return void.class;
 358             case 'Z':
 359             case 'B':
 360             case 'S':
 361             case 'C':
 362                 throw new IllegalArgumentException("Not a valid primitive: " + c +
 363                         " (use I instead)");
 364             default:
< prev index next >