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

Add overloads to parse and build class files from/to MemorySegment

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • core-libs
    • None
    • behavioral
    • minimal
    • These methods are all new, so compatibility risk is limited to backend implementation errors relating to extracting common code between the two code paths (in the cases where this is necessary).
    • Java API
    • SE

      Summary

      Provide method overloads to the ClassFile interface of the java.lang.classfile API which allow parsing of classes found in memory segments, as well as allowing built class files to be output to them.

      Problem

      Class file data may be found in off-heap memory, for example when reading certain kinds of memory-mapped JAR files. The current API requires the user to copy this data into a byte array before parsing or verifying the class file, which is unwieldy at best.

      It is also sometimes desirable to write generated or transformed class data into off-heap memory. At present, the class file data must be built to a byte array and manually copied to off-heap memory.

      Solution

      Provide overloads for verification and parsing which can read class file data from a memory segment in lieu of a byte array. The implementation may internally copy data in some circumstances, but the API should be designed such that a more optimal implementation is also possible.

      Provide overloads for transformation and generation which can write class file data into a memory segment which is allocated by a user-provided function.

      Specification

      Modify java.lang.classfile.ClassFile to add the following API methods:

          /**
           * Parses a {@code class} file into a {@link ClassModel}.
           * <p>
           * Due to the on-demand nature of {@code class} file parsing, an {@link
           * IllegalArgumentException} may be thrown on any accessor method invocation
           * on the returned model or any structure returned by the accessors in the
           * structure hierarchy.
           *
           * @param bytes a memory segment containing the bytes of the {@code class} file
           * @return the class model
           * @throws IllegalArgumentException if the {@code class} file is malformed
           *         or of a version {@linkplain #latestMajorVersion() not supported}
           *         by the current runtime
           * @implNote The implementation may or may not support parsing directly from
           *           a given memory segment. In the latter case, the implementation may copy
           *           the memory segment's contents to a temporary array before parsing.
           */
          ClassModel parse(MemorySegment bytes);
      
          /**
           * Builds a {@code class} file into a memory segment.
           * <p>
           * The allocator function must allocate a memory segment with a
           * {@linkplain MemorySegment#byteSize() size}
           * which is <em>at least</em> as large as the size given to it.
           * If the allocated segment has a size which is smaller than the size provided
           * to the allocator function, an unspecified exception or error may be thrown.
           *
           * @param allocator the segment allocator function
           * @param thisClass the name of the class to build
           * @param handler a handler that receives a {@link ClassBuilder}
           * @return the {@code class} file bytes
           * @throws IllegalArgumentException if {@code thisClass} represents a
           *         primitive type or building encounters a failure
           */
          MemorySegment buildToMemorySegment(SegmentAllocator allocator,
                                                     ClassDesc thisClass,
                                                     Consumer<? super ClassBuilder> handler);
      
          /**
           * Builds a {@code class} file into a memory segment using the provided constant
           * pool builder.
           *
           * @param allocator the segment allocator function
           * @param thisClassEntry the name of the class to build
           * @param constantPool the constant pool builder
           * @param handler a handler that receives a {@link ClassBuilder}
           * @return the {@code class} file bytes
           * @throws IllegalArgumentException if building encounters a failure
           */
          MemorySegment buildToMemorySegment(SegmentAllocator allocator,
                                             ClassEntry thisClassEntry,
                                             ConstantPoolBuilder constantPool,
                                             Consumer<? super ClassBuilder> handler);
      
          /**
           * Builds a module descriptor into a memory segment.
           *
           * @param allocator the segment allocator function
           * @param moduleAttribute the {@code Module} attribute
           * @return the {@code class} file bytes
           * @throws IllegalArgumentException if building encounters a failure
           */
          MemorySegment buildModuleToMemorySegment(SegmentAllocator allocator,
                                                           ModuleAttribute moduleAttribute);
      
          /**
           * Builds a module descriptor into a memory segment.
           *
           * @param allocator the segment allocator function
           * @param moduleAttribute the {@code Module} attribute
           * @param handler a handler that receives a {@link ClassBuilder}
           * @return the {@code class} file bytes
           * @throws IllegalArgumentException if building encounters a failure
           */
          MemorySegment buildModuleToMemorySegment(SegmentAllocator allocator,
                                                           ModuleAttribute moduleAttribute,
                                                           Consumer<? super ClassBuilder> handler);
      
          /**
           * Transform one {@code class} file into a new {@code class} file according
           * to a {@link ClassTransform}.  The transform will receive each element of
           * this class, as well as a {@link ClassBuilder} for building the new class.
           * The transform is free to preserve, remove, or replace elements as it
           * sees fit.
           * <p>
           * This method behaves as if:
           * {@snippet lang=java :
           * ConstantPoolBuilder cpb = null; // @replace substring=null; replacement=...
           * this.build(model.thisClass(), cpb,
           *            clb -> clb.transform(model, transform));
           * }
           * where {@code cpb} is determined by {@link ConstantPoolSharingOption}.
           * <p>
           * The allocator function must allocate a memory segment with a
           * {@linkplain MemorySegment#byteSize() size}
           * which is <em>at least</em> as large as the size given to it.
           * If the allocated segment has a size which is smaller than the size provided
           * to the allocator function, an unspecified exception or error may be thrown.
           *
           * @apiNote
           * This is named {@code transformClass} instead of {@code transform} for
           * consistency with {@link ClassBuilder#transformField}, {@link
           * ClassBuilder#transformMethod}, and {@link MethodBuilder#transformCode},
           * and to distinguish from {@link ClassFileBuilder#transform}, which is
           * more generic and powerful.
           *
           * @param allocator the segment allocator function
           * @param model the class model to transform
           * @param transform the transform
           * @return the bytes of the new class
           * @throws IllegalArgumentException if building encounters a failure
           * @see ConstantPoolSharingOption
           */
          MemorySegment transformClassToMemorySegment(SegmentAllocator allocator, ClassModel model, ClassTransform transform);
      
          /**
           * Transform one {@code class} file into a new {@code class} file according
           * to a {@link ClassTransform}.  The transform will receive each element of
           * this class, as well as a {@link ClassBuilder} for building the new class.
           * The transform is free to preserve, remove, or replace elements as it
           * sees fit.
           * <p>
           * The allocator function must allocate a memory segment with a
           * {@linkplain MemorySegment#byteSize() size}
           * which is <em>at least</em> as large as the size given to it.
           * If the allocated segment has a size which is smaller than the size provided
           * to the allocator function, an unspecified exception or error may be thrown.
           *
           * @apiNote
           * This is named {@code transformClass} instead of {@code transform} for
           * consistency with {@link ClassBuilder#transformField}, {@link
           * ClassBuilder#transformMethod}, and {@link MethodBuilder#transformCode},
           * and to distinguish from {@link ClassFileBuilder#transform}, which is
           * more generic and powerful.
           *
           * @param allocator the segment allocator function
           * @param model the class model to transform
           * @param newClassName new class name
           * @param transform the transform
           * @return the bytes of the new class
           * @throws IllegalArgumentException if building encounters a failure
           * @see ConstantPoolSharingOption
           */
          MemorySegment transformClassToMemorySegment(SegmentAllocator allocator, ClassModel model, ClassDesc newClassName, ClassTransform transform);
      
          /**
           * Transform one {@code class} file into a new {@code class} file according
           * to a {@link ClassTransform}.  The transform will receive each element of
           * this class, as well as a {@link ClassBuilder} for building the new class.
           * The transform is free to preserve, remove, or replace elements as it
           * sees fit.
           * <p>
           * This method behaves as if:
           * {@snippet lang=java :
           * ConstantPoolBuilder cpb = null; // @replace substring=null; replacement=...
           * this.build(newClassName, cpb, clb -> clb.transform(model, transform));
           * }
           * where {@code cpb} is determined by {@link ConstantPoolSharingOption}.
           * <p>
           * The allocator function must allocate a memory segment with a
           * {@linkplain MemorySegment#byteSize() size}
           * which is <em>at least</em> as large as the size given to it.
           * If the allocated segment has a size which is smaller than the size provided
           * to the allocator function, an unspecified exception or error may be thrown.
           *
           * @apiNote
           * This is named {@code transformClass} instead of {@code transform} for
           * consistency with {@link ClassBuilder#transformField}, {@link
           * ClassBuilder#transformMethod}, and {@link MethodBuilder#transformCode},
           * and to distinguish from {@link ClassFileBuilder#transform}, which is
           * more generic and powerful.
           *
           * @param allocator the segment allocator function
           * @param model the class model to transform
           * @param newClassName new class name
           * @param transform the transform
           * @return the bytes of the new class
           * @throws IllegalArgumentException if building encounters a failure
           * @see ConstantPoolSharingOption
           */
          MemorySegment transformClassToMemorySegment(SegmentAllocator allocator, ClassModel model, ClassEntry newClassName, ClassTransform transform);
      
          /**
           * Verify a {@code class} file.  All verification errors found will be returned.
           *
           * @param bytes the {@code class} file bytes to verify
           * @return a list of verification errors, or an empty list if no error is
           * found
           */
          List<VerifyError> verify(MemorySegment bytes);

            dmlloyd David Lloyd
            dmlloyd David Lloyd
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: