JDK-8230501: Class data support for hidden classes

forax at univ-mlv.fr forax at univ-mlv.fr
Tue Nov 10 21:35:10 UTC 2020

> De: "mandy chung" <mandy.chung at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "valhalla-dev" <valhalla-dev at openjdk.java.net>
> Envoyé: Mardi 10 Novembre 2020 22:17:04
> Objet: Re: JDK-8230501: Class data support for hidden classes

> Hi Remi,

> This is not intended only for the vector API implementation but rather for
> clients who define hidden classes with more than one live objects as class
> data. Otherwise each client will have to write a similar convenience method
> which also needs to handle the unboxing conversion if the constant is a
> primitive type.

> I see the downside for this convenience method is only for List (recommending to
> use immutable list) which can be extended when we have frozen array.

> Any other issues you see for this convenience method?
I think it's better to use a structured object like a record instead of using a list which requires all objects to have the same type. 

> Mandy

> On 11/10/20 12:55 PM, Remi Forax wrote:

>> Hi Mandy,
>> thanks to working on this.

>> I don't think that adding classDataAt is a good idea, you can emulate it with
>> classData and it's better to get the list once from the class data instead of
>> doing all the checks for each index of the List like classDataAt does.

>> I understand that the vector API implementation needs to have several arguments
>> (my own test also needs that [1]) but it can be a helper method inside the
>> vector API implementation and not a public method in java.lang.invoke API.

>> regards,
>> Rémi

>> [1] [
>> https://urldefense.com/v3/__https://github.com/forax/panama-vector/blob/master/fr.umlv.jruntime/src/main/java/fr/umlv/jruntime/Cell.java*L851__;Iw!!GqivPVa7Brio!JZmRSoc-X98rznCWzxyjtsp-_Zskmz43hgmEGqPUUdsoVa9pGHyxU5tWdQCMLeUTFg$
>> |
>> https://urldefense.com/v3/__https://github.com/forax/panama-vector/blob/master/fr.umlv.jruntime/src/main/java/fr/umlv/jruntime/Cell.java*L851__;Iw!!GqivPVa7Brio!JZmRSoc-X98rznCWzxyjtsp-_Zskmz43hgmEGqPUUdsoVa9pGHyxU5tWdQCMLeUTFg$
>> ] ----- Mail original -----

>>> De: "mandy chung" [ mailto:mandy.chung at oracle.com | <mandy.chung at oracle.com> ]
>>> À: "valhalla-dev" [ mailto:valhalla-dev at openjdk.java.net |
>>> <valhalla-dev at openjdk.java.net> ] Envoyé: Mardi 10 Novembre 2020 01:12:23
>>> Objet: JDK-8230501: Class data support for hidden classes

>>> 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://urldefense.com/v3/__https://github.com/mlchung/jdk/tree/class-data__;!!GqivPVa7Brio!JZmRSoc-X98rznCWzxyjtsp-_Zskmz43hgmEGqPUUdsoVa9pGHyxU5tWdQBdnWA7CQ$
>>> |
>>> https://urldefense.com/v3/__https://github.com/mlchung/jdk/tree/class-data__;!!GqivPVa7Brio!JZmRSoc-X98rznCWzxyjtsp-_Zskmz43hgmEGqPUUdsoVa9pGHyxU5tWdQBdnWA7CQ$
>>> ] .

>>> 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
>>> |
>>> 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