-
CSR
-
Resolution: Approved
-
P3
-
None
-
behavioral
-
low
-
-
Java API
-
SE
Summary
Provide Lookup::defineHiddenClassWithClassData API that allows live objects
be shared between a hidden class and other classes. A hidden class can load
these live objects as dynamically-computed constants via this API.
sun.misc.Unsafe::defineAnonymousClass will be deprecated for removal.
Existing libraries depending on the constant pool patching of VM-anonymous
class should replace their calls to sun.misc.Unsafe::defineAnonymousClass
with Lookup::defineHiddenClassWithClassData.
Problem
This is a follow up enhancement to JEP 371: Hidden Classes as documented in the "Risks and Assumption" section:
Constant-pool patching
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.
Solution
Define a new 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 to load an element at the specified index from the class data
if it's a list. It's a convenience method to load one element from class data
via condy.
The hidden class will be initialized when classData or classDataAt method
is called if the hidden class has not been initialized.
Specification
See attached specdiff for the spec changes for:
- In java.lang.invoke.MethodHandles.Lookup class:
- New
Lookup::defineHiddenClassWithClassDatamethod - New
Lookup::ORIGINALmode and the following methods are updated to reflect this new modeLookup::lookupModesLookup::inLookup::dropLookupIn
- New
- java.lang.invoke.MethodHandles class
- New
MethodHandles::classData(Lookup lookup, String name, Class<?> type)static method - New
MethodHandles::classDataAt(Lookup lookup, String name, Class<?> type, int index)static method MethodHandles::lookupandMethodHandles::privateLookupInare updated to reflect the newORIGINALmode
- New
Compatibility Risks
The Lookup object produced via teleporting will drop ORIGINAL bit (including Lookup::in, Lookup::dropLookupIn and MethodHandles::privateLookupIn)
A Lookup with original access ensures that this lookup is created by the original lookup class and the bootstrap method invoked by the VM. Such a lookup with original access also has private and module access which has the following additional capability:
- create method handles which invoke caller sensitive methods, such as Class.forName
- obtain the class data associated with the lookup class
Prior to the new ORIGINAL bit, a Lookup returned by MethodHandles::privateLookupIn with both private and module access can lookup caller-sensitive methods. The behavior of the Lookup returned by MethodHandles::privateLookupIn with both private and module access is changed and it will not be able to lookup any caller-sensitive method.
The behavior of a caller-sensitive method is dependent on the lookup context. So a method handle of caller-sensitive methods is bound with the lookup context at creation time and the lookup context is evaluated at runtime instead of the caller at method invocation time. Therefore a lookup object with the original access must be provided; otherwise, IllegalAccessException will be thrown. The intent for MethodHandles::privateLookupIn is to allow module authors to authorize libraries or frameworks to do deep reflection on private and module-internal members. Existing code should use MethodHandles::lookup (its own lookup with original full privilege access) to obtain caller-sensitive methods instead. The compatibility risk of this behavioral change is low because the full privilege access requirement to lookup caller-sensitive methods is prior to Java SE 9 when privateLookupIn is introduced.
- csr of
-
JDK-8230501 Class data support for hidden classes
-
- Resolved
-