3939import sun .reflect .misc .ReflectUtil ;
4040import sun .security .util .SecurityConstants ;
4141
42+ import java .lang .classfile .ClassFile ;
4243import java .lang .classfile .ClassModel ;
44+ import java .lang .constant .ClassDesc ;
4345import java .lang .constant .ConstantDescs ;
4446import java .lang .invoke .LambdaForm .BasicType ;
4547import java .lang .invoke .MethodHandleImpl .Intrinsic ;
@@ -2242,85 +2244,70 @@ private static ClassFileDumper defaultDumper() {
22422244 private static final ClassFileDumper DEFAULT_DUMPER = ClassFileDumper .getInstance (
22432245 "jdk.invoke.MethodHandle.dumpClassFiles" , "DUMP_CLASS_FILES" );
22442246
2245- static class ClassFile {
2246- final String name ; // internal name
2247- final int accessFlags ;
2248- final byte [] bytes ;
2249- ClassFile (String name , int accessFlags , byte [] bytes ) {
2250- this .name = name ;
2251- this .accessFlags = accessFlags ;
2252- this .bytes = bytes ;
2247+ /**
2248+ * This method checks the class file version and the structure of `this_class`.
2249+ * and checks if the bytes is a class or interface (ACC_MODULE flag not set)
2250+ * that is in the named package.
2251+ *
2252+ * @throws IllegalArgumentException if ACC_MODULE flag is set in access flags
2253+ * or the class is not in the given package name.
2254+ */
2255+ static String validateAndFindInternalName (byte [] bytes , String pkgName ) {
2256+ int magic = readInt (bytes , 0 );
2257+ if (magic != ClassFile .MAGIC_NUMBER ) {
2258+ throw new ClassFormatError ("Incompatible magic value: " + magic );
22532259 }
2260+ // We have to read major and minor this way as ClassFile API throws IAE
2261+ // yet we want distinct ClassFormatError and UnsupportedClassVersionError
2262+ int minor = readUnsignedShort (bytes , 4 );
2263+ int major = readUnsignedShort (bytes , 6 );
22542264
2255- static ClassFile newInstanceNoCheck ( String name , byte [] bytes ) {
2256- return new ClassFile ( name , 0 , bytes );
2265+ if (! VM . isSupportedClassFileVersion ( major , minor ) ) {
2266+ throw new UnsupportedClassVersionError ( "Unsupported class file version " + major + "." + minor );
22572267 }
22582268
2259- /**
2260- * This method checks the class file version and the structure of `this_class`.
2261- * and checks if the bytes is a class or interface (ACC_MODULE flag not set)
2262- * that is in the named package.
2263- *
2264- * @throws IllegalArgumentException if ACC_MODULE flag is set in access flags
2265- * or the class is not in the given package name.
2266- */
2267- static ClassFile newInstance (byte [] bytes , String pkgName ) {
2268- var cf = readClassFile (bytes );
2269-
2270- // check if it's in the named package
2271- int index = cf .name .lastIndexOf ('/' );
2272- String pn = (index == -1 ) ? "" : cf .name .substring (0 , index ).replace ('/' , '.' );
2273- if (!pn .equals (pkgName )) {
2274- throw newIllegalArgumentException (cf .name + " not in same package as lookup class" );
2275- }
2276- return cf ;
2269+ String name ;
2270+ ClassDesc sym ;
2271+ int accessFlags ;
2272+ try {
2273+ ClassModel cm = ClassFile .of ().parse (bytes );
2274+ var thisClass = cm .thisClass ();
2275+ name = thisClass .asInternalName ();
2276+ sym = thisClass .asSymbol ();
2277+ accessFlags = cm .flags ().flagsMask ();
2278+ } catch (IllegalArgumentException e ) {
2279+ ClassFormatError cfe = new ClassFormatError ();
2280+ cfe .initCause (e );
2281+ throw cfe ;
2282+ }
2283+ // must be a class or interface
2284+ if ((accessFlags & ACC_MODULE ) != 0 ) {
2285+ throw newIllegalArgumentException ("Not a class or interface: ACC_MODULE flag is set" );
22772286 }
22782287
2279- private static ClassFile readClassFile (byte [] bytes ) {
2280- int magic = readInt (bytes , 0 );
2281- if (magic != 0xCAFEBABE ) {
2282- throw new ClassFormatError ("Incompatible magic value: " + magic );
2283- }
2284- int minor = readUnsignedShort (bytes , 4 );
2285- int major = readUnsignedShort (bytes , 6 );
2286- if (!VM .isSupportedClassFileVersion (major , minor )) {
2287- throw new UnsupportedClassVersionError ("Unsupported class file version " + major + "." + minor );
2288- }
2289-
2290- String name ;
2291- int accessFlags ;
2292- try {
2293- ClassModel cm = java .lang .classfile .ClassFile .of ().parse (bytes );
2294- name = cm .thisClass ().asInternalName ();
2295- accessFlags = cm .flags ().flagsMask ();
2296- } catch (IllegalArgumentException e ) {
2297- ClassFormatError cfe = new ClassFormatError ();
2298- cfe .initCause (e );
2299- throw cfe ;
2300- }
2301- // must be a class or interface
2302- if ((accessFlags & ACC_MODULE ) != 0 ) {
2303- throw newIllegalArgumentException ("Not a class or interface: ACC_MODULE flag is set" );
2304- }
2305- return new ClassFile (name , accessFlags , bytes );
2288+ String pn = sym .packageName ();
2289+ if (!pn .equals (pkgName )) {
2290+ throw newIllegalArgumentException (name + " not in same package as lookup class" );
23062291 }
23072292
2308- private static int readInt (byte [] bytes , int offset ) {
2309- if ((offset +4 ) > bytes .length ) {
2310- throw new ClassFormatError ("Invalid ClassFile structure" );
2311- }
2312- return ((bytes [offset ] & 0xFF ) << 24 )
2313- | ((bytes [offset + 1 ] & 0xFF ) << 16 )
2314- | ((bytes [offset + 2 ] & 0xFF ) << 8 )
2315- | (bytes [offset + 3 ] & 0xFF );
2293+ return name ;
2294+ }
2295+
2296+ private static int readInt (byte [] bytes , int offset ) {
2297+ if ((offset + 4 ) > bytes .length ) {
2298+ throw new ClassFormatError ("Invalid ClassFile structure" );
23162299 }
2300+ return ((bytes [offset ] & 0xFF ) << 24 )
2301+ | ((bytes [offset + 1 ] & 0xFF ) << 16 )
2302+ | ((bytes [offset + 2 ] & 0xFF ) << 8 )
2303+ | (bytes [offset + 3 ] & 0xFF );
2304+ }
23172305
2318- private static int readUnsignedShort (byte [] bytes , int offset ) {
2319- if ((offset +2 ) > bytes .length ) {
2320- throw new ClassFormatError ("Invalid ClassFile structure" );
2321- }
2322- return ((bytes [offset ] & 0xFF ) << 8 ) | (bytes [offset + 1 ] & 0xFF );
2306+ private static int readUnsignedShort (byte [] bytes , int offset ) {
2307+ if ((offset +2 ) > bytes .length ) {
2308+ throw new ClassFormatError ("Invalid ClassFile structure" );
23232309 }
2310+ return ((bytes [offset ] & 0xFF ) << 8 ) | (bytes [offset + 1 ] & 0xFF );
23242311 }
23252312
23262313 /*
@@ -2334,23 +2321,22 @@ private static int readUnsignedShort(byte[] bytes, int offset) {
23342321 * {@code bytes} denotes a class in a different package than the lookup class
23352322 */
23362323 private ClassDefiner makeClassDefiner (byte [] bytes ) {
2337- ClassFile cf = ClassFile . newInstance (bytes , lookupClass ().getPackageName ());
2338- return new ClassDefiner (this , cf , STRONG_LOADER_LINK , defaultDumper ());
2324+ var internalName = validateAndFindInternalName (bytes , lookupClass ().getPackageName ());
2325+ return new ClassDefiner (this , internalName , bytes , STRONG_LOADER_LINK , defaultDumper ());
23392326 }
23402327
23412328 /**
23422329 * Returns a ClassDefiner that creates a {@code Class} object of a normal class
23432330 * from the given bytes. No package name check on the given bytes.
23442331 *
2345- * @param name internal name
2332+ * @param internalName internal name
23462333 * @param bytes class bytes
23472334 * @param dumper dumper to write the given bytes to the dumper's output directory
23482335 * @return ClassDefiner that defines a normal class of the given bytes.
23492336 */
2350- ClassDefiner makeClassDefiner (String name , byte [] bytes , ClassFileDumper dumper ) {
2337+ ClassDefiner makeClassDefiner (String internalName , byte [] bytes , ClassFileDumper dumper ) {
23512338 // skip package name validation
2352- ClassFile cf = ClassFile .newInstanceNoCheck (name , bytes );
2353- return new ClassDefiner (this , cf , STRONG_LOADER_LINK , dumper );
2339+ return new ClassDefiner (this , internalName , bytes , STRONG_LOADER_LINK , dumper );
23542340 }
23552341
23562342 /**
@@ -2368,8 +2354,8 @@ ClassDefiner makeClassDefiner(String name, byte[] bytes, ClassFileDumper dumper)
23682354 * {@code bytes} denotes a class in a different package than the lookup class
23692355 */
23702356 ClassDefiner makeHiddenClassDefiner (byte [] bytes , ClassFileDumper dumper ) {
2371- ClassFile cf = ClassFile . newInstance (bytes , lookupClass ().getPackageName ());
2372- return makeHiddenClassDefiner (cf , false , dumper , 0 );
2357+ var internalName = validateAndFindInternalName (bytes , lookupClass ().getPackageName ());
2358+ return makeHiddenClassDefiner (internalName , bytes , false , dumper , 0 );
23732359 }
23742360
23752361 /**
@@ -2391,51 +2377,53 @@ ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) {
23912377 private ClassDefiner makeHiddenClassDefiner (byte [] bytes ,
23922378 boolean accessVmAnnotations ,
23932379 int flags ) {
2394- ClassFile cf = ClassFile . newInstance (bytes , lookupClass ().getPackageName ());
2395- return makeHiddenClassDefiner (cf , accessVmAnnotations , defaultDumper (), flags );
2380+ var internalName = validateAndFindInternalName (bytes , lookupClass ().getPackageName ());
2381+ return makeHiddenClassDefiner (internalName , bytes , accessVmAnnotations , defaultDumper (), flags );
23962382 }
23972383
23982384 /**
23992385 * Returns a ClassDefiner that creates a {@code Class} object of a hidden class
24002386 * from the given bytes and the given options. No package name check on the given bytes.
24012387 *
2402- * @param name internal name that specifies the prefix of the hidden class
2388+ * @param internalName internal name that specifies the prefix of the hidden class
24032389 * @param bytes class bytes
24042390 * @param dumper dumper to write the given bytes to the dumper's output directory
24052391 * @return ClassDefiner that defines a hidden class of the given bytes and options.
24062392 */
2407- ClassDefiner makeHiddenClassDefiner (String name , byte [] bytes , ClassFileDumper dumper ) {
2393+ ClassDefiner makeHiddenClassDefiner (String internalName , byte [] bytes , ClassFileDumper dumper ) {
24082394 Objects .requireNonNull (dumper );
24092395 // skip name and access flags validation
2410- return makeHiddenClassDefiner (ClassFile . newInstanceNoCheck ( name , bytes ) , false , dumper , 0 );
2396+ return makeHiddenClassDefiner (internalName , bytes , false , dumper , 0 );
24112397 }
24122398
24132399 /**
24142400 * Returns a ClassDefiner that creates a {@code Class} object of a hidden class
24152401 * from the given bytes and the given options. No package name check on the given bytes.
24162402 *
2417- * @param name internal name that specifies the prefix of the hidden class
2403+ * @param internalName internal name that specifies the prefix of the hidden class
24182404 * @param bytes class bytes
24192405 * @param flags class options flag mask
24202406 * @param dumper dumper to write the given bytes to the dumper's output directory
24212407 * @return ClassDefiner that defines a hidden class of the given bytes and options.
24222408 */
2423- ClassDefiner makeHiddenClassDefiner (String name , byte [] bytes , ClassFileDumper dumper , int flags ) {
2409+ ClassDefiner makeHiddenClassDefiner (String internalName , byte [] bytes , ClassFileDumper dumper , int flags ) {
24242410 Objects .requireNonNull (dumper );
24252411 // skip name and access flags validation
2426- return makeHiddenClassDefiner (ClassFile . newInstanceNoCheck ( name , bytes ) , false , dumper , flags );
2412+ return makeHiddenClassDefiner (internalName , bytes , false , dumper , flags );
24272413 }
24282414
24292415 /**
24302416 * Returns a ClassDefiner that creates a {@code Class} object of a hidden class
24312417 * from the given class file and options.
24322418 *
2433- * @param cf ClassFile
2419+ * @param internalName internal name
2420+ * @param bytes Class byte array
24342421 * @param flags class option flag mask
24352422 * @param accessVmAnnotations true to give the hidden class access to VM annotations
24362423 * @param dumper dumper to write the given bytes to the dumper's output directory
24372424 */
2438- private ClassDefiner makeHiddenClassDefiner (ClassFile cf ,
2425+ private ClassDefiner makeHiddenClassDefiner (String internalName ,
2426+ byte [] bytes ,
24392427 boolean accessVmAnnotations ,
24402428 ClassFileDumper dumper ,
24412429 int flags ) {
@@ -2446,27 +2434,12 @@ private ClassDefiner makeHiddenClassDefiner(ClassFile cf,
24462434 flags |= ACCESS_VM_ANNOTATIONS ;
24472435 }
24482436
2449- return new ClassDefiner (this , cf , flags , dumper );
2437+ return new ClassDefiner (this , internalName , bytes , flags , dumper );
24502438 }
24512439
2452- static class ClassDefiner {
2453- private final Lookup lookup ;
2454- private final String name ; // internal name
2455- private final byte [] bytes ;
2456- private final int classFlags ;
2457- private final ClassFileDumper dumper ;
2458-
2459- private ClassDefiner (Lookup lookup , ClassFile cf , int flags , ClassFileDumper dumper ) {
2460- assert ((flags & HIDDEN_CLASS ) != 0 || (flags & STRONG_LOADER_LINK ) == STRONG_LOADER_LINK );
2461- this .lookup = lookup ;
2462- this .bytes = cf .bytes ;
2463- this .name = cf .name ;
2464- this .classFlags = flags ;
2465- this .dumper = dumper ;
2466- }
2467-
2468- String internalName () {
2469- return name ;
2440+ record ClassDefiner (Lookup lookup , String internalName , byte [] bytes , int classFlags , ClassFileDumper dumper ) {
2441+ ClassDefiner {
2442+ assert ((classFlags & HIDDEN_CLASS ) != 0 || (classFlags & STRONG_LOADER_LINK ) == STRONG_LOADER_LINK );
24702443 }
24712444
24722445 Class <?> defineClass (boolean initialize ) {
@@ -2495,7 +2468,7 @@ Class<?> defineClass(boolean initialize, Object classData) {
24952468 Class <?> c = null ;
24962469 try {
24972470 c = SharedSecrets .getJavaLangAccess ()
2498- .defineClass (loader , lookupClass , name , bytes , pd , initialize , classFlags , classData );
2471+ .defineClass (loader , lookupClass , internalName , bytes , pd , initialize , classFlags , classData );
24992472 assert !isNestmate () || c .getNestHost () == lookupClass .getNestHost ();
25002473 return c ;
25012474 } finally {
0 commit comments