JDK-8230501: Class data support for hidden classes

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Nov 11 21:16:16 UTC 2020


Hi Mandy,
this looks like a nice API, and using condy directly to access class 
data seems a very convenient solution for code generators.

The only comment I have is that the Foreign Memory Access generator is 
about to go as part of the third incubator round (which we'll push very 
shortly), so you might want to use some other examples to assess 
performances.

Cheers
Maurizio

On 10/11/2020 00:12, Mandy Chung wrote:
> I'd like to get the discussion on the proposal APIs for class data
> support for hidden classes before posting PR.
>
> The patch is in https://github.com/mlchung/jdk/tree/class-data.
>
> This patch also updates the implementation of lambda meta factory and
> Memory Access API to use class data.  I ran the jdk.incubator.foreign
> microbenchmarks and no performance difference.  I'm running more
> performance testing.
>
> Specdiff
> http://cr.openjdk.java.net/~mchung/jdk16/webrevs/8230501/specdiff/overview-summary.html 
>
>
>
> Summary
> -------
>
> Provide `Lookup::defineHiddenClassWithClassData` API that allow live 
> objects
> be shared between a hidden class and other classes.  A hidden class 
> can load
> these live objects as dynamically-computed constants via 
> `MethodHandles::classData`
> and `MethodHandles::classDataAt` bootstrap methods.
>
> With this class data support and hidden classes, 
> `sun.misc.Unsafe::defineAnonymousClass`
> will be deprecated for removal.  Existing libraries should replace their
> calls to `sun.misc.Unsafe::defineAnonymousClass` with 
> `Lookup::defineHiddenClass`
> or `Lookup::defineHiddenClassWithClassData`.
>
>
> Background
> ----------
>
> This is an enhancement following up JEP 371: Hidden Classes w.r.t.
> "Constant-pool patching" in the "Risks and Assumption" section.
>
> A VM-anonymous class can be defined with its constant-pool entries 
> already
> resolved to concrete values. This allows critical constants to be shared
> between a VM-anonymous class and the language runtime that defines it, 
> and
> between multiple VM-anonymous classes. For example, a language runtime 
> will
> often have `MethodHandle` objects in its address space that would be 
> useful
> to newly-defined VM-anonymous classes. Instead of the runtime serializing
> the objects to constant-pool entries in VM-anonymous classes and then
> generating bytecode in those classes to laboriously `ldc` the entries,
> the runtime can simply supply `Unsafe::defineAnonymousClass` with 
> references
> to its live objects. The relevant constant-pool entries in the 
> newly-defined
> VM-anonymous class are pre-linked to those objects, improving performance
> and reducing footprint. In addition, this allows VM-anonymous classes to
> refer to each other: Constant-pool entries in a class file are based 
> on names.
> They thus cannot refer to nameless VM-anonymous classes. A language 
> runtime can,
> however, easily track the live Class objects for its VM-anonymous 
> classes and
> supply them to `Unsafe::defineAnonymousClass`, thus pre-linking the 
> new class's
> constant pool entries to other VM-anonymous classes.
>
> This extends the hidden classes to allow live objects to be injected
> in a hidden class and loaded them via condy.
>
> Details
> -------
>
> Provide `Lookup::defineHiddenClassWithClassData` API that takes 
> additional
> `classData` argument compared to `Lookup::defineHiddenClass`
> class data can be method handles, lookup objects, arbitrary user objects
> or collections of all of the above.
>
>    This method behaves as if calling `Lookup::defineHiddenClass` to 
> define
>    a hidden class with a private static unnamed field that is initialized
>    with `classData` at the first instruction of the class initializer.
>
> `MethodHandles::classData(Lookup lookup, String name, Class<?> type)`
> is a bootstrap method for the class data of the given lookup's lookup 
> class.
>
> `MethodHandles::classDataAt(Lookup lookup, String name, Class<?> type, 
> int index)`
> is a bootstrap method for the element at the given index in the class 
> data
> of the given lookup's lookup class, if the class data is a `List`.
>
> The hidden class will be initialized when `classData` or `classDataAt` 
> method
> is called if the hidden class has not been initialized.
>
> Bootstrap methods for class data of other type such as `Map` can be 
> considered
> in the future while this version also provides a bootstrap method for
> class data list.
>
> Frameworks sometimes want to dynamically create a hidden class (HC) 
> and add it
> it the lookup class nest and have HC to carry secrets hidden from that 
> nest.
> In this case, frameworks should not to use private static finals (in 
> the HCs
> they spin) to hold secrets because a nestmate of HC may obtain access to
> such a private static final and observe the framework's secret. It should
> use condy.
>
> In addition, we need to differentiate if a lookup object is created from
> the original lookup class or created from teleporting e.g. `Lookup::in`
> and `MethodHandles::privateLookupIn`.
>
> This proposes to add a new `ORIGINAL` bit that is only set if the lookup
> object is created by `MethodHandles::lookup` or by bootstrap method 
> invocation.
> `Lookup::hasFullPrivilegeAccess` returns true only if it has private, 
> module
> and originl access.
>
> `MethodHandles::privateLookupIn` spec is updated to check if the 
> caller lookup
> has private and module access.  It does not check for original access 
> so that
> a caller can pass a lookup without original access to a framework for
> deep reflection if desired.  It addition, the resulting Lookup object
> does not have the original access.
>
>
>
> Compatibility Risks
> -------------------
>
> The Lookup object returned by `MethodHandles::privateLookupIn` does 
> not have
> the original access.  If the caller lookup class and target class is 
> in the same
> module, it will return a Lookup object with private and module access but
> no original access. The return Lookup object no longer has full 
> privilege access.
>
> Existing code calling `Lookup::hasFullPrivilegeAccess` on a Lookup object
> returned from `privateLookupIn` is impacted since the resulting Lookup 
> object
> has private access but not full privilege access. `privateLookupIn` is 
> designed
> for frameworks to teleport to a target class with private access for deep
> reflection.  It is believed that `hasFullPrivilegeAccess` is not 
> popularly
> used (it was introduced in 14) and the compatibility risk is expected 
> to be low.
>
> `Lookup::toString` on the return Lookup object from 
> `MethodHandles::privateLookupIn`
> will have "/allaccess" suffix as opposed to no suffix to indicate full
> privilege access.


More information about the valhalla-dev mailing list