From a253e0ff4b88541d01596b0e73ede4b96a258fca Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Mon, 15 Jul 2024 12:11:53 +0000 Subject: [PATCH] 8335642: Hide Transform implementation for Class-File API Reviewed-by: asotona --- .../java/lang/classfile/ClassFileBuilder.java | 17 ++-- .../lang/classfile/ClassFileTransform.java | 45 +---------- .../java/lang/classfile/ClassTransform.java | 13 +--- .../java/lang/classfile/CodeBuilder.java | 3 +- .../java/lang/classfile/CodeTransform.java | 13 +--- .../java/lang/classfile/FieldTransform.java | 13 +--- .../java/lang/classfile/MethodTransform.java | 13 +--- .../classfile/impl/AbstractDirectBuilder.java | 7 +- .../classfile/impl/TransformImpl.java | 78 +++++++++++-------- 9 files changed, 66 insertions(+), 136 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java index b4993976ecd..56a2088370c 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileBuilder.java @@ -27,8 +27,9 @@ package java.lang.classfile; import java.lang.constant.ClassDesc; import java.util.function.Consumer; -import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.ConstantPoolBuilder; + +import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; /** @@ -71,25 +72,19 @@ public sealed interface ClassFileBuilder model, ClassFileTransform transform) { + default B transform(CompoundElement model, ClassFileTransform transform) { @SuppressWarnings("unchecked") B builder = (B) this; - var resolved = transform.resolve(builder); + var resolved = TransformImpl.resolve(transform, builder); resolved.startHandler().run(); model.forEach(resolved.consumer()); resolved.endHandler().run(); + return builder; } } diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java b/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java index f67da06a36d..851f4deb03e 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ */ package java.lang.classfile; -import java.util.function.Consumer; import java.util.function.Supplier; import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; @@ -124,46 +123,4 @@ public sealed interface ClassFileTransform< * @return the chained transform */ C andThen(C next); - - /** - * The result of binding a transform to a builder. Used primarily within - * the implementation to perform transformation. - * - * @param the element type - * - * @since 22 - */ - @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - interface ResolvedTransform { - /** - * {@return a {@link Consumer} to receive elements} - */ - Consumer consumer(); - - /** - * {@return an action to call at the end of transformation} - */ - Runnable endHandler(); - - /** - * {@return an action to call at the start of transformation} - */ - Runnable startHandler(); - } - - /** - * Bind a transform to a builder. If the transform is chained, intermediate - * builders are created for each chain link. If the transform is stateful - * (see, e.g., {@link ClassTransform#ofStateful(Supplier)}), the supplier is - * invoked to get a fresh transform object. - * - *

This method is a low-level method that should rarely be used by - * user code; most of the time, user code should prefer - * {@link ClassFileBuilder#transform(CompoundElement, ClassFileTransform)}, - * which resolves the transform and executes it on the current builder. - * - * @param builder the builder to bind to - * @return the bound result - */ - ResolvedTransform resolve(B builder); } diff --git a/src/java.base/share/classes/java/lang/classfile/ClassTransform.java b/src/java.base/share/classes/java/lang/classfile/ClassTransform.java index a2391b320f9..743a3985114 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -171,15 +171,4 @@ public non-sealed interface ClassTransform default ClassTransform andThen(ClassTransform t) { return new TransformImpl.ChainedClassTransform(this, t); } - - /** - * @implSpec The default implementation returns a resolved transform bound - * to the given class builder. - */ - @Override - default ResolvedTransform resolve(ClassBuilder builder) { - return new TransformImpl.ResolvedTransformImpl<>(e -> accept(builder, e), - () -> atEnd(builder), - () -> atStart(builder)); - } } diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index a1666375091..dffa9c7f89a 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -87,6 +87,7 @@ import java.lang.classfile.instruction.TypeCheckInstruction; import static java.util.Objects.requireNonNull; import static jdk.internal.classfile.impl.BytecodeHelpers.handleDescToHandleInfo; +import jdk.internal.classfile.impl.TransformImpl; import jdk.internal.javac.PreviewFeature; /** @@ -190,7 +191,7 @@ public sealed interface CodeBuilder * @return this builder */ default CodeBuilder transforming(CodeTransform transform, Consumer handler) { - var resolved = transform.resolve(this); + var resolved = TransformImpl.resolve(transform, this); resolved.startHandler().run(); handler.accept(new ChainedCodeBuilder(this, resolved.consumer())); resolved.endHandler().run(); diff --git a/src/java.base/share/classes/java/lang/classfile/CodeTransform.java b/src/java.base/share/classes/java/lang/classfile/CodeTransform.java index a0996a9cb34..cdc7a3b1434 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,15 +96,4 @@ public non-sealed interface CodeTransform default CodeTransform andThen(CodeTransform t) { return new TransformImpl.ChainedCodeTransform(this, t); } - - /** - * @implSpec The default implementation returns a resolved transform bound - * to the given code builder. - */ - @Override - default ResolvedTransform resolve(CodeBuilder builder) { - return new TransformImpl.ResolvedTransformImpl<>(e -> accept(builder, e), - () -> atEnd(builder), - () -> atStart(builder)); - } } diff --git a/src/java.base/share/classes/java/lang/classfile/FieldTransform.java b/src/java.base/share/classes/java/lang/classfile/FieldTransform.java index 1a27a1d6ee6..4e39f1e9c7f 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,15 +111,4 @@ public non-sealed interface FieldTransform default FieldTransform andThen(FieldTransform t) { return new TransformImpl.ChainedFieldTransform(this, t); } - - /** - * @implSpec The default implementation returns a resolved transform bound - * to the given field builder. - */ - @Override - default ResolvedTransform resolve(FieldBuilder builder) { - return new TransformImpl.ResolvedTransformImpl<>(e -> accept(builder, e), - () -> atEnd(builder), - () -> atStart(builder)); - } } diff --git a/src/java.base/share/classes/java/lang/classfile/MethodTransform.java b/src/java.base/share/classes/java/lang/classfile/MethodTransform.java index 829ca041c5a..e7e024ebc34 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodTransform.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodTransform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,17 +111,6 @@ public non-sealed interface MethodTransform return new TransformImpl.MethodCodeTransform(xform); } - /** - * @implSpec The default implementation returns a resolved transform bound - * to the given method builder. - */ - @Override - default ResolvedTransform resolve(MethodBuilder builder) { - return new TransformImpl.ResolvedTransformImpl<>(e -> accept(builder, e), - () -> atEnd(builder), - () -> atStart(builder)); - } - /** * @implSpec * The default implementation returns this method transform chained with another diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractDirectBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractDirectBuilder.java index 13c2a5fb745..2feba5f9e0b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractDirectBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractDirectBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.constantpool.ConstantPool; import java.util.Optional; import java.lang.classfile.Attribute; @@ -43,6 +44,10 @@ public class AbstractDirectBuilder { return constantPool; } + public boolean canWriteDirect(ConstantPool source) { + return constantPool().canWriteDirect(source); + } + public Optional original() { return Optional.ofNullable(original); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java index 1677d421be9..4075f209666 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TransformImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.ClassFileBuilder; +import java.lang.classfile.ClassFileTransform; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; @@ -32,7 +34,6 @@ import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassElement; import java.lang.classfile.ClassTransform; import java.lang.classfile.ClassFileElement; -import java.lang.classfile.ClassFileTransform; import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; @@ -46,7 +47,7 @@ import java.lang.classfile.MethodElement; import java.lang.classfile.MethodModel; import java.lang.classfile.MethodTransform; -public class TransformImpl { +public final class TransformImpl { // ClassTransform private TransformImpl() { @@ -58,7 +59,23 @@ public class TransformImpl { private static final Runnable NOTHING = () -> { }; - interface UnresolvedClassTransform extends ClassTransform { + public static > + ResolvedTransform resolve(ClassFileTransform transform, B builder) { + if (transform instanceof ResolvableTransform) { + @SuppressWarnings("unchecked") + var ut = (ResolvableTransform) transform; + return ut.resolve(builder); + } + return new ResolvedTransform<>(e -> transform.accept(builder, e), + () -> transform.atEnd(builder), + () -> transform.atStart(builder)); + } + + interface ResolvableTransform> { + ResolvedTransform resolve(B builder); + } + + interface UnresolvedClassTransform extends ClassTransform, ResolvableTransform { @Override default void accept(ClassBuilder builder, ClassElement element) { throw new UnsupportedOperationException("transforms must be resolved before running"); @@ -75,12 +92,11 @@ public class TransformImpl { } } - public record ResolvedTransformImpl(Consumer consumer, + public record ResolvedTransform(Consumer consumer, Runnable endHandler, - Runnable startHandler) - implements ClassFileTransform.ResolvedTransform { + Runnable startHandler) { - public ResolvedTransformImpl(Consumer consumer) { + public ResolvedTransform(Consumer consumer) { this(consumer, NOTHING, NOTHING); } } @@ -89,11 +105,11 @@ public class TransformImpl { ClassTransform next) implements UnresolvedClassTransform { @Override - public ResolvedTransformImpl resolve(ClassBuilder builder) { - ResolvedTransform downstream = next.resolve(builder); + public ResolvedTransform resolve(ClassBuilder builder) { + ResolvedTransform downstream = TransformImpl.resolve(next, builder); ClassBuilder chainedBuilder = new ChainedClassBuilder(builder, downstream.consumer()); - ResolvedTransform upstream = t.resolve(chainedBuilder); - return new ResolvedTransformImpl<>(upstream.consumer(), + ResolvedTransform upstream = TransformImpl.resolve(t, chainedBuilder); + return new ResolvedTransform<>(upstream.consumer(), chainRunnable(upstream.endHandler(), downstream.endHandler()), chainRunnable(upstream.startHandler(), downstream.startHandler())); } @@ -103,7 +119,7 @@ public class TransformImpl { implements UnresolvedClassTransform { @Override public ResolvedTransform resolve(ClassBuilder builder) { - return supplier.get().resolve(builder); + return TransformImpl.resolve(supplier.get(), builder); } } @@ -112,7 +128,7 @@ public class TransformImpl { implements UnresolvedClassTransform { @Override public ResolvedTransform resolve(ClassBuilder builder) { - return new ResolvedTransformImpl<>(ce -> { + return new ResolvedTransform<>(ce -> { if (ce instanceof MethodModel mm && filter.test(mm)) builder.transformMethod(mm, transform); else @@ -135,7 +151,7 @@ public class TransformImpl { implements UnresolvedClassTransform { @Override public ResolvedTransform resolve(ClassBuilder builder) { - return new ResolvedTransformImpl<>(ce -> { + return new ResolvedTransform<>(ce -> { if (ce instanceof FieldModel fm && filter.test(fm)) builder.transformField(fm, transform); else @@ -155,7 +171,7 @@ public class TransformImpl { // MethodTransform - interface UnresolvedMethodTransform extends MethodTransform { + interface UnresolvedMethodTransform extends MethodTransform, ResolvableTransform { @Override default void accept(MethodBuilder builder, MethodElement element) { throw new UnsupportedOperationException("transforms must be resolved before running"); @@ -177,10 +193,10 @@ public class TransformImpl { implements TransformImpl.UnresolvedMethodTransform { @Override public ResolvedTransform resolve(MethodBuilder builder) { - ResolvedTransform downstream = next.resolve(builder); + ResolvedTransform downstream = TransformImpl.resolve(next, builder); MethodBuilder chainedBuilder = new ChainedMethodBuilder(builder, downstream.consumer()); - ResolvedTransform upstream = t.resolve(chainedBuilder); - return new ResolvedTransformImpl<>(upstream.consumer(), + ResolvedTransform upstream = TransformImpl.resolve(t, chainedBuilder); + return new ResolvedTransform<>(upstream.consumer(), chainRunnable(upstream.endHandler(), downstream.endHandler()), chainRunnable(upstream.startHandler(), downstream.startHandler())); } @@ -190,7 +206,7 @@ public class TransformImpl { implements TransformImpl.UnresolvedMethodTransform { @Override public ResolvedTransform resolve(MethodBuilder builder) { - return supplier.get().resolve(builder); + return TransformImpl.resolve(supplier.get(), builder); } } @@ -198,7 +214,7 @@ public class TransformImpl { implements TransformImpl.UnresolvedMethodTransform { @Override public ResolvedTransform resolve(MethodBuilder builder) { - return new ResolvedTransformImpl<>(me -> { + return new ResolvedTransform<>(me -> { if (me instanceof CodeModel cm) { builder.transformCode(cm, xform); } @@ -219,7 +235,7 @@ public class TransformImpl { // FieldTransform - interface UnresolvedFieldTransform extends FieldTransform { + interface UnresolvedFieldTransform extends FieldTransform, ResolvableTransform { @Override default void accept(FieldBuilder builder, FieldElement element) { throw new UnsupportedOperationException("transforms must be resolved before running"); @@ -240,10 +256,10 @@ public class TransformImpl { implements UnresolvedFieldTransform { @Override public ResolvedTransform resolve(FieldBuilder builder) { - ResolvedTransform downstream = next.resolve(builder); + ResolvedTransform downstream = TransformImpl.resolve(next, builder); FieldBuilder chainedBuilder = new ChainedFieldBuilder(builder, downstream.consumer()); - ResolvedTransform upstream = t.resolve(chainedBuilder); - return new ResolvedTransformImpl<>(upstream.consumer(), + ResolvedTransform upstream = TransformImpl.resolve(t, chainedBuilder); + return new ResolvedTransform<>(upstream.consumer(), chainRunnable(upstream.endHandler(), downstream.endHandler()), chainRunnable(upstream.startHandler(), downstream.startHandler())); } @@ -253,13 +269,13 @@ public class TransformImpl { implements UnresolvedFieldTransform { @Override public ResolvedTransform resolve(FieldBuilder builder) { - return supplier.get().resolve(builder); + return TransformImpl.resolve(supplier.get(), builder); } } // CodeTransform - interface UnresolvedCodeTransform extends CodeTransform { + interface UnresolvedCodeTransform extends CodeTransform, ResolvableTransform { @Override default void accept(CodeBuilder builder, CodeElement element) { throw new UnsupportedOperationException("transforms must be resolved before running"); @@ -280,10 +296,10 @@ public class TransformImpl { implements UnresolvedCodeTransform { @Override public ResolvedTransform resolve(CodeBuilder builder) { - ResolvedTransform downstream = next.resolve(builder); + ResolvedTransform downstream = TransformImpl.resolve(next, builder); CodeBuilder chainedBuilder = new ChainedCodeBuilder(builder, downstream.consumer()); - ResolvedTransform upstream = t.resolve(chainedBuilder); - return new ResolvedTransformImpl<>(upstream.consumer(), + ResolvedTransform upstream = TransformImpl.resolve(t, chainedBuilder); + return new ResolvedTransform<>(upstream.consumer(), chainRunnable(upstream.endHandler(), downstream.endHandler()), chainRunnable(upstream.startHandler(), downstream.startHandler())); } @@ -293,7 +309,7 @@ public class TransformImpl { implements UnresolvedCodeTransform { @Override public ResolvedTransform resolve(CodeBuilder builder) { - return supplier.get().resolve(builder); + return TransformImpl.resolve(supplier.get(), builder); } } }