JDK-8230501: Class data support for hidden classes

Mandy Chung mandy.chung at oracle.com
Tue Nov 10 00:12:23 UTC 2020


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