Review Request: 8238358: Implementation of JEP 371: Hidden Classes

Peter Levart peter.levart at
Fri Apr 3 09:11:04 UTC 2020

Hi Mandy,

Good work.

I'm trying to find out which language use-case is covered by the 
InnerClassLambdaMetafactory needing to inject method handle into the 
generated proxy class to be invoked instead of proxy class directly 
invoking the method:

         useImplMethodHandle = 

If I check what implClass and implInfo get resolved to in 
AbstractValidatingLambdaMetafactory, there are several cases:

         this.implInfo = caller.revealDirect(implMethod);
         switch (implInfo.getReferenceKind()) {
             case REF_invokeVirtual:
             case REF_invokeInterface:
                 this.implClass = implMethodType.parameterType(0);
                 // reference kind reported by implInfo may not match 
implMethodType's first param
                 // Example: implMethodType is (Cloneable)String, 
implInfo is for Object.toString
                 this.implKind = implClass.isInterface() ? 
REF_invokeInterface : REF_invokeVirtual;
                 this.implIsInstanceMethod = true;
             case REF_invokeSpecial:
                 // JDK-8172817: should use referenced class here, but 
we don't know what it was
                 this.implClass = implInfo.getDeclaringClass();
                 this.implIsInstanceMethod = true;

                 // Classes compiled prior to dynamic nestmate support 
invokes a private instance
                 // method with REF_invokeSpecial.
                 // invokespecial should only be used to invoke private 
nestmate constructors.
                 // The lambda proxy class will be defined as a nestmate 
of targetClass.
                 // If the method to be invoked is an instance method of 
targetClass, then
                 // convert to use invokevirtual or invokeinterface.
                 if (targetClass == implClass && 
!implInfo.getName().equals("<init>")) {
                     this.implKind = implClass.isInterface() ? 
REF_invokeInterface : REF_invokeVirtual;
                 } else {
                     this.implKind = REF_invokeSpecial;
             case REF_invokeStatic:
             case REF_newInvokeSpecial:
                 // JDK-8172817: should use referenced class here for 
invokestatic, but we don't know what it was
                 this.implClass = implInfo.getDeclaringClass();
                 this.implKind = implInfo.getReferenceKind();
                 this.implIsInstanceMethod = false;
                 throw new 
LambdaConversionException(String.format("Unsupported MethodHandle kind: 
%s", implInfo));

For majority of cases (REF_invokeSpecial, REF_invokeStatic, 
REF_newInvokeSpecial) the this.implClass = implInfo.getDeclaringClass();

Only REF_invokeVirtual and REF_invokeInterface are possible kandidates, 

So when does the implMethod type of parameter 0 differ from the 
declaring class of the MethodHandleInfo cracked from that same 
implMethod and in addition those two types leave in different packages?

Regards, Peter

On 3/27/20 12:57 AM, Mandy Chung wrote:
> Please review the implementation of JEP 371: Hidden Classes. The main 
> changes are in core-libs and hotspot runtime area.  Small changes are 
> made in javac, VM compiler (intrinsification of Class::isHiddenClass), 
> JFR, JDI, and jcmd.  CSR [1]has been reviewed and is in the finalized 
> state (see specdiff and javadoc below for reference).
> Webrev:
> Hidden class is created via `Lookup::defineHiddenClass`. From JVM's point
> of view, a hidden class is a normal class except the following:
> - A hidden class has no initiating class loader and is not registered 
> in any dictionary.
> - A hidden class has a name containing an illegal character 
> `Class::getName` returns `p.Foo/0x1234` whereas `GetClassSignature` 
> returns "Lp/Foo.0x1234;".
> - A hidden class is not modifiable, i.e. cannot be redefined or 
> retransformed. JVM TI IsModifableClass returns false on a hidden.
> - Final fields in a hidden class is "final".  The value of final 
> fields cannot be overriden via reflection.  setAccessible(true) can 
> still be called on reflected objects representing final fields in a 
> hidden class and its access check will be suppressed but only have 
> read-access (i.e. can do Field::getXXX but not setXXX).
> Brief summary of this patch:
> 1. A new Lookup::defineHiddenClass method is the API to create a 
> hidden class.
> 2. A new Lookup.ClassOption enum class defines NESTMATE and STRONG 
> option that
>    can be specified when creating a hidden class.
> 3. A new Class::isHiddenClass method tests if a class is a hidden class.
> 4. Field::setXXX method will throw IAE on a final field of a hidden class
>    regardless of the value of the accessible flag.
> 5. JVM_LookupDefineClass is the new JVM entry point for 
> Lookup::defineClass
>    and defineHiddenClass to create a class from the given bytes.
> 6. ClassLoaderData implementation is not changed.  There is one 
> primary CLD
>    that holds the classes strongly referenced by its defining loader.  
> There
>    can be zero or more additional CLDs - one per weak class.
> 7. Nest host determination is updated per revised JVMS 5.4.4. Access 
> control
>    check no longer throws LinkageError but instead it will throw IAE with
>    a clear message if a class fails to resolve/validate the nest host 
> declared
>    in NestHost/NestMembers attribute.
> 8. JFR, jcmd, JDI are updated to support hidden classes.
> 9. update javac LambdaToMethod as lambda proxy starts using nestmates
>    and generate a bridge method to desuger a method reference to a 
> protected
>    method in its supertype in a different package
> This patch also updates StringConcatFactory, LambdaMetaFactory, and 
> LambdaForms
> to use hidden classes.  The webrev includes changes in nashorn to 
> hidden class
> and I will update the webrev if JEP 372 removes it any time soon.
> We uncovered a bug in Lookup::defineClass spec throws LinkageError and 
> intends
> to have the newly created class linked.  However, the implementation 
> in 14
> does not link the class.  A separate CSR [2] proposes to update the
> implementation to match the spec.  This patch fixes the implementation.
> The spec update on JVM TI, JDI and Instrumentation will be done as
> a separate RFE [3].  This patch includes new tests for JVM TI and
> java.instrument that validates how the existing APIs work for hidden 
> classes.
> javadoc/specdiff
> JVMS 5.4.4 change:
> CSR:
> Thanks
> Mandy
> [1]
> [2]
> [3]

More information about the valhalla-dev mailing list