Details
-
CSR
-
Resolution: Approved
-
P3
-
None
-
behavioral
-
low
-
-
Java API
-
SE
Description
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::defineHiddenClassWithClassData
method - New
Lookup::ORIGINAL
mode and the following methods are updated to reflect this new modeLookup::lookupModes
Lookup::in
Lookup::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::lookup
andMethodHandles::privateLookupIn
are updated to reflect the newORIGINAL
mode
- 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.
Attachments
Issue Links
- csr of
-
JDK-8230501 Class data support for hidden classes
- Resolved