Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8256214

Class data support for hidden classes

    XMLWordPrintable

Details

    • CSR
    • Resolution: Approved
    • P3
    • 16
    • core-libs
    • None
    • behavioral
    • low
    • Hide
      The incompatibility risk of this spec change is low.

      A new ORIGINAL bit is added. Most lookup operations ignore this original bit
      except creating method handles for caller-sensitive methods that expects
      the lookup from the original lookup class. Looking up caller-sensitive methods
      is expected to use lookup created by `MethodHandles::lookup` but not
      `MethodHandles::privateLookupIn`.

      Existing code that compares the return value of lookupModes to be a fixed
      value may be impacted. However existing client has no need to expect a
      fixed value of lookup modes.
      Show
      The incompatibility risk of this spec change is low. A new ORIGINAL bit is added. Most lookup operations ignore this original bit except creating method handles for caller-sensitive methods that expects the lookup from the original lookup class. Looking up caller-sensitive methods is expected to use lookup created by `MethodHandles::lookup` but not `MethodHandles::privateLookupIn`. Existing code that compares the return value of lookupModes to be a fixed value may be impacted. However existing client has no need to expect a fixed value of lookup modes.
    • 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:

      1. 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 mode
          • Lookup::lookupModes
          • Lookup::in
          • Lookup::dropLookupIn
      2. 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 and MethodHandles::privateLookupIn are updated to reflect the new ORIGINAL mode

      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

          Activity

            People

              mchung Mandy Chung
              mchung Mandy Chung
              Chris Hegarty, John Rose, Jorn Vernee, Paul Sandoz
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: