From a68751a04f3a58f4ec03972143b0e058f87318bd Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 23 Jul 2024 04:59:58 +0000 Subject: [PATCH 01/10] 8335938: Review XxxBuilder.original and XxxModel.parent Reviewed-by: asotona --- .../classes/java/lang/classfile/ClassBuilder.java | 9 +-------- .../classes/java/lang/classfile/CodeBuilder.java | 6 ------ .../classes/java/lang/classfile/FieldBuilder.java | 8 +------- .../java/lang/classfile/MethodBuilder.java | 9 +-------- .../classfile/impl/AbstractDirectBuilder.java | 8 +------- .../classfile/impl/BufferedCodeBuilder.java | 5 ----- .../classfile/impl/BufferedFieldBuilder.java | 15 +++------------ .../classfile/impl/BufferedMethodBuilder.java | 7 +------ .../classfile/impl/ChainedClassBuilder.java | 11 ++--------- .../classfile/impl/ChainedFieldBuilder.java | 9 +-------- .../classfile/impl/ChainedMethodBuilder.java | 7 ------- .../classfile/impl/NonterminalCodeBuilder.java | 10 +--------- 12 files changed, 12 insertions(+), 92 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java index f1b8bb13d27..a55b93e7c07 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.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 @@ -30,7 +30,6 @@ import java.lang.constant.MethodTypeDesc; import java.util.Arrays; import java.util.List; -import java.util.Optional; import java.util.function.Consumer; import java.lang.classfile.constantpool.ClassEntry; @@ -58,12 +57,6 @@ public sealed interface ClassBuilder extends ClassFileBuilder permits ChainedClassBuilder, DirectClassBuilder { - /** - * {@return the {@link ClassModel} representing the class being transformed, - * if this class builder represents the transformation of some {@link ClassModel}} - */ - Optional original(); - /** * Sets the classfile version. * @param major the major version number 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 dffa9c7f89a..64a677d63ad 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -128,12 +128,6 @@ public sealed interface CodeBuilder extends ClassFileBuilder permits CodeBuilder.BlockCodeBuilder, ChainedCodeBuilder, TerminalCodeBuilder, NonterminalCodeBuilder { - /** - * {@return the {@link CodeModel} representing the method body being transformed, - * if this code builder represents the transformation of some {@link CodeModel}} - */ - Optional original(); - /** {@return a fresh unbound label} */ Label newLabel(); diff --git a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java index 18a598398ec..c0e733676f7 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.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 @@ -30,7 +30,6 @@ import jdk.internal.classfile.impl.TerminalFieldBuilder; import java.lang.reflect.AccessFlag; -import java.util.Optional; import java.util.function.Consumer; import jdk.internal.javac.PreviewFeature; @@ -68,9 +67,4 @@ default FieldBuilder withFlags(AccessFlag... flags) { return with(AccessFlags.ofField(flags)); } - /** - * {@return the {@link FieldModel} representing the field being transformed, - * if this field builder represents the transformation of some {@link FieldModel}} - */ - Optional original(); } diff --git a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java index ece292c361b..4cf34c95ed0 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.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 @@ -25,7 +25,6 @@ package java.lang.classfile; -import java.util.Optional; import java.util.function.Consumer; import java.lang.classfile.constantpool.Utf8Entry; @@ -50,12 +49,6 @@ public sealed interface MethodBuilder extends ClassFileBuilder permits ChainedMethodBuilder, TerminalMethodBuilder { - /** - * {@return the {@link MethodModel} representing the method being transformed, - * if this method builder represents the transformation of some {@link MethodModel}} - */ - Optional original(); - /** * Sets the method access flags. * @param flags the access flags, as a bit mask 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 2feba5f9e0b..f574627491f 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 @@ -24,10 +24,8 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.constantpool.ConstantPool; -import java.util.Optional; - import java.lang.classfile.Attribute; +import java.lang.classfile.constantpool.ConstantPool; public class AbstractDirectBuilder { protected final SplitConstantPool constantPool; @@ -48,10 +46,6 @@ public boolean canWriteDirect(ConstantPool source) { return constantPool().canWriteDirect(source); } - public Optional original() { - return Optional.ofNullable(original); - } - public void setOriginal(M original) { this.original = original; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java index e9a8f2e1e1c..c3a601fa1df 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java @@ -70,11 +70,6 @@ public BufferedCodeBuilder(MethodInfo methodInfo, elements.add(startLabel); } - @Override - public Optional original() { - return Optional.ofNullable(original); - } - @Override public Label newLabel() { return new LabelImpl(this, -1); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java index 2ba7ef14d0d..a92513390b4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, 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 @@ -41,19 +41,16 @@ public final class BufferedFieldBuilder private final Utf8Entry desc; private final List elements = new ArrayList<>(); private AccessFlags flags; - private final FieldModel original; public BufferedFieldBuilder(SplitConstantPool constantPool, ClassFileImpl context, Utf8Entry name, - Utf8Entry type, - FieldModel original) { + Utf8Entry type) { this.constantPool = constantPool; this.context = context; this.name = name; this.desc = type; this.flags = AccessFlags.ofField(); - this.original = original; } @Override @@ -61,11 +58,6 @@ public ConstantPoolBuilder constantPool() { return constantPool; } - @Override - public Optional original() { - return Optional.ofNullable(original); - } - @Override public FieldBuilder with(FieldElement element) { elements.add(element); @@ -91,8 +83,7 @@ public Model() { @Override public Optional parent() { - FieldModel fm = original().orElse(null); - return fm == null? Optional.empty() : fm.parent(); + return Optional.empty(); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java index eaa2e2b710e..f92ee1adf34 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java @@ -91,11 +91,6 @@ public ConstantPoolBuilder constantPool() { return constantPool; } - @Override - public Optional original() { - return Optional.ofNullable(original); - } - @Override public Utf8Entry methodName() { return name; @@ -172,7 +167,7 @@ public AccessFlags flags() { @Override public Optional parent() { - return original().flatMap(MethodModel::parent); + return Optional.empty(); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java index 04565278217..d31debf6f35 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java @@ -24,7 +24,6 @@ */ package jdk.internal.classfile.impl; -import java.util.Optional; import java.util.function.Consumer; import java.lang.classfile.*; @@ -51,15 +50,10 @@ public ClassBuilder with(ClassElement element) { return this; } - @Override - public Optional original() { - return terminal.original(); - } - @Override public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, Consumer handler) { consumer.accept(new BufferedFieldBuilder(terminal.constantPool, terminal.context, - name, descriptor, null) + name, descriptor) .run(handler) .toModel()); return this; @@ -68,8 +62,7 @@ public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, Consumer original() { - return terminal.original(); - } - @Override public FieldBuilder with(FieldElement element) { consumer.accept(element); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java index 866dda2c5bc..a7084116b9b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java @@ -24,7 +24,6 @@ */ package jdk.internal.classfile.impl; -import java.util.Optional; import java.util.function.Consumer; import java.lang.classfile.CodeBuilder; @@ -32,7 +31,6 @@ import java.lang.classfile.CodeTransform; import java.lang.classfile.MethodBuilder; import java.lang.classfile.MethodElement; -import java.lang.classfile.MethodModel; import java.lang.classfile.constantpool.ConstantPoolBuilder; public final class ChainedMethodBuilder implements MethodBuilder { @@ -75,9 +73,4 @@ public ConstantPoolBuilder constantPool() { return terminal.constantPool(); } - @Override - public Optional original() { - return terminal.original(); - } - } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/NonterminalCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/NonterminalCodeBuilder.java index 9c27f0f5f9f..f40da3a2bea 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/NonterminalCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/NonterminalCodeBuilder.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,10 +24,7 @@ */ package jdk.internal.classfile.impl; -import java.util.Optional; - import java.lang.classfile.CodeBuilder; -import java.lang.classfile.CodeModel; import java.lang.classfile.Label; import java.lang.classfile.constantpool.ConstantPoolBuilder; @@ -59,11 +56,6 @@ public ConstantPoolBuilder constantPool() { return terminal.constantPool(); } - @Override - public Optional original() { - return terminal.original(); - } - @Override public Label newLabel() { return terminal.newLabel(); From 0167e42772a03ef6ade36c8f55f2b4a2f9f86da2 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Tue, 23 Jul 2024 05:13:49 +0000 Subject: [PATCH 02/10] 8336339: (se) SelectionKey.interestOps(int) should not throw ClosedSelectorException Reviewed-by: jpai, bpb --- .../classes/sun/nio/ch/EPollSelectorImpl.java | 7 - .../sun/nio/ch/KQueueSelectorImpl.java | 7 - .../spi/AbstractSelectableChannel.java | 6 +- .../classes/sun/nio/ch/SelectorImpl.java | 17 +-- .../classes/sun/nio/ch/PollSelectorImpl.java | 1 - .../sun/nio/ch/WEPollSelectorImpl.java | 7 - .../sun/nio/ch/WindowsSelectorImpl.java | 3 +- .../Selector/RaceUpdatesAndClose.java | 122 ++++++++++++++++++ 8 files changed, 136 insertions(+), 34 deletions(-) create mode 100644 test/jdk/java/nio/channels/Selector/RaceUpdatesAndClose.java diff --git a/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java b/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java index cb55932fd7e..a07a927e635 100644 --- a/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java +++ b/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java @@ -26,7 +26,6 @@ package sun.nio.ch; import java.io.IOException; -import java.nio.channels.ClosedSelectorException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.SelectorProvider; @@ -92,11 +91,6 @@ class EPollSelectorImpl extends SelectorImpl { EPoll.ctl(epfd, EPOLL_CTL_ADD, eventfd.efd(), EPOLLIN); } - private void ensureOpen() { - if (!isOpen()) - throw new ClosedSelectorException(); - } - @Override protected int doSelect(Consumer action, long timeout) throws IOException @@ -243,7 +237,6 @@ protected void implDereg(SelectionKeyImpl ski) throws IOException { @Override public void setEventOps(SelectionKeyImpl ski) { - ensureOpen(); synchronized (updateLock) { updateKeys.addLast(ski); } diff --git a/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java b/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java index 6c84984f515..6abc9e31879 100644 --- a/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java +++ b/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java @@ -26,7 +26,6 @@ package sun.nio.ch; import java.io.IOException; -import java.nio.channels.ClosedSelectorException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.SelectorProvider; @@ -97,11 +96,6 @@ class KQueueSelectorImpl extends SelectorImpl { KQueue.register(kqfd, fd0, EVFILT_READ, EV_ADD); } - private void ensureOpen() { - if (!isOpen()) - throw new ClosedSelectorException(); - } - @Override protected int doSelect(Consumer action, long timeout) throws IOException @@ -285,7 +279,6 @@ protected void implDereg(SelectionKeyImpl ski) throws IOException { @Override public void setEventOps(SelectionKeyImpl ski) { - ensureOpen(); synchronized (updateLock) { updateKeys.addLast(ski); } diff --git a/src/java.base/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java b/src/java.base/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java index 558158cc852..4b342603caf 100644 --- a/src/java.base/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java +++ b/src/java.base/share/classes/java/nio/channels/spi/AbstractSelectableChannel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -137,6 +137,8 @@ private SelectionKey findKey(Selector sel) { void removeKey(SelectionKey k) { // package-private synchronized (keyLock) { + if (keys == null) + return; for (int i = 0; i < keys.length; i++) if (keys[i] == k) { keys[i] = null; @@ -233,7 +235,7 @@ public final SelectionKey register(Selector sel, int ops, Object att) k.interestOps(ops); } else { // New registration - k = ((AbstractSelector)sel).register(this, ops, att); + k = ((AbstractSelector) sel).register(this, ops, att); addKey(k); } return k; diff --git a/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java b/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java index bb0d603790f..de7a1f98daf 100644 --- a/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -188,11 +188,11 @@ public final void implCloseSelector() throws IOException { // Deregister channels Iterator i = keys.iterator(); while (i.hasNext()) { - SelectionKeyImpl ski = (SelectionKeyImpl)i.next(); + SelectionKeyImpl ski = (SelectionKeyImpl) i.next(); deregister(ski); SelectableChannel selch = ski.channel(); if (!selch.isOpen() && !selch.isRegistered()) - ((SelChImpl)selch).kill(); + ((SelChImpl) selch).kill(); selectedKeys.remove(ski); i.remove(); } @@ -221,13 +221,14 @@ protected final SelectionKey register(AbstractSelectableChannel ch, keys.add(k); try { k.interestOps(ops); - } catch (ClosedSelectorException e) { + } catch (CancelledKeyException e) { + // key observed and cancelled. Okay to return a cancelled key. + } + if (!isOpen()) { assert ch.keyFor(this) == null; keys.remove(k); k.cancel(); - throw e; - } catch (CancelledKeyException e) { - // key observed and cancelled. Okay to return a cancelled key. + throw new ClosedSelectorException(); } return k; } @@ -277,7 +278,7 @@ protected final void processDeregisterQueue() throws IOException { SelectableChannel ch = ski.channel(); if (!ch.isOpen() && !ch.isRegistered()) - ((SelChImpl)ch).kill(); + ((SelChImpl) ch).kill(); } } } diff --git a/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java b/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java index a3bff8d1e65..d29eacb81c1 100644 --- a/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java +++ b/src/java.base/unix/classes/sun/nio/ch/PollSelectorImpl.java @@ -231,7 +231,6 @@ protected void implDereg(SelectionKeyImpl ski) throws IOException { @Override public void setEventOps(SelectionKeyImpl ski) { - ensureOpen(); synchronized (updateLock) { updateKeys.addLast(ski); } diff --git a/src/java.base/windows/classes/sun/nio/ch/WEPollSelectorImpl.java b/src/java.base/windows/classes/sun/nio/ch/WEPollSelectorImpl.java index bbcfab9bbf1..f2bff88675f 100644 --- a/src/java.base/windows/classes/sun/nio/ch/WEPollSelectorImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/WEPollSelectorImpl.java @@ -28,7 +28,6 @@ import java.io.FileDescriptor; import java.io.IOException; import java.nio.ByteBuffer; -import java.nio.channels.ClosedSelectorException; import java.nio.channels.Pipe; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; @@ -89,11 +88,6 @@ class WEPollSelectorImpl extends SelectorImpl { WEPoll.ctl(eph, EPOLL_CTL_ADD, fd0Val, WEPoll.EPOLLIN); } - private void ensureOpen() { - if (!isOpen()) - throw new ClosedSelectorException(); - } - @Override protected int doSelect(Consumer action, long timeout) throws IOException @@ -228,7 +222,6 @@ protected void implDereg(SelectionKeyImpl ski) throws IOException { @Override public void setEventOps(SelectionKeyImpl ski) { - ensureOpen(); synchronized (updateLock) { updateKeys.addLast(ski); } diff --git a/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java b/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java index 977a1653fdd..eb681bc5ab9 100644 --- a/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -606,7 +606,6 @@ protected void implDereg(SelectionKeyImpl ski) { @Override public void setEventOps(SelectionKeyImpl ski) { - ensureOpen(); synchronized (updateLock) { updateKeys.addLast(ski); } diff --git a/test/jdk/java/nio/channels/Selector/RaceUpdatesAndClose.java b/test/jdk/java/nio/channels/Selector/RaceUpdatesAndClose.java new file mode 100644 index 00000000000..8173d3d761f --- /dev/null +++ b/test/jdk/java/nio/channels/Selector/RaceUpdatesAndClose.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8336339 + * @summary Race registration and selection key updates with Selector.close + * @run junit RaceUpdatesAndClose + */ + +import java.nio.channels.CancelledKeyException; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Phaser; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.RepeatedTest; + +class RaceUpdatesAndClose { + private static ExecutorService executor; + + @BeforeAll + static void setup() throws Exception { + executor = Executors.newFixedThreadPool(2); + } + + @AfterAll + static void finish() { + executor.shutdown(); + } + + /** + * Race SelectableChannel.register and Selector.close. + */ + @RepeatedTest(100) + void raceRegisterAndClose() throws Exception { + try (Selector sel = Selector.open(); + DatagramChannel dc = DatagramChannel.open()) { + + dc.configureBlocking(false); + + Phaser phaser = new Phaser(2); + + // register + var task1 = executor.submit(() -> { + phaser.arriveAndAwaitAdvance(); + try { + dc.register(sel, SelectionKey.OP_READ); + } catch (ClosedSelectorException e) { } + return null; + }); + + // close selector + var task2 = executor.submit(() -> { + phaser.arriveAndAwaitAdvance(); + sel.close(); + return null; + }); + + task1.get(); + task2.get(); + } + } + + /** + * Race SelectionKey.interestOps and Selector.close. + */ + @RepeatedTest(100) + void raceInterestOpsAndClose() throws Exception { + try (Selector sel = Selector.open(); + DatagramChannel dc = DatagramChannel.open()) { + + dc.configureBlocking(false); + SelectionKey key = dc.register(sel, SelectionKey.OP_READ); + + Phaser phaser = new Phaser(2); + + // interestOps + var task1 = executor.submit(() -> { + phaser.arriveAndAwaitAdvance(); + try { + key.interestOps(0); + } catch (CancelledKeyException e) { } + }); + + // close selector + var task2 = executor.submit(() -> { + phaser.arriveAndAwaitAdvance(); + sel.close(); + return null; + }); + + task1.get(); + task2.get(); + } + } +} From 60b1cfccb8d99359f540103a6ea3413923c8de2e Mon Sep 17 00:00:00 2001 From: Raffaello Giulietti Date: Tue, 23 Jul 2024 07:43:57 +0000 Subject: [PATCH 03/10] 8334758: Incorrect note in Javadoc for a few RandomGenerator methods Reviewed-by: bpb --- .../java/util/random/RandomGenerator.java | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/src/java.base/share/classes/java/util/random/RandomGenerator.java b/src/java.base/share/classes/java/util/random/RandomGenerator.java index b38c4eee8f0..e019e073a2d 100644 --- a/src/java.base/share/classes/java/util/random/RandomGenerator.java +++ b/src/java.base/share/classes/java/util/random/RandomGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -809,12 +809,11 @@ default int nextInt() { * * @throws IllegalArgumentException if {@code bound} is not positive * - * @implSpec The default implementation checks that {@code bound} is a - * positive {@code int}. Then invokes {@code nextInt()}, limiting the result - * to be greater than or equal zero and less than {@code bound}. If {@code bound} - * is a power of two then limiting is a simple masking operation. Otherwise, - * the result is re-calculated by invoking {@code nextInt()} until the - * result is greater than or equal zero and less than {@code bound}. + * @implSpec The default implementation checks that {@code bound} is positive. + * It then invokes {@link #nextInt()} one or more times to ensure a uniform + * distribution in the range 0 (inclusive) + * to {@code bound} (exclusive). + * It assumes the distribution of {@link #nextInt()} to be uniform. */ default int nextInt(int bound) { RandomSupport.checkBound(bound); @@ -835,13 +834,12 @@ default int nextInt(int bound) { * @throws IllegalArgumentException if {@code origin} is greater than * or equal to {@code bound} * - * @implSpec The default implementation checks that {@code origin} and - * {@code bound} are positive {@code ints}. Then invokes {@code nextInt()}, - * limiting the result to be greater that or equal {@code origin} and less - * than {@code bound}. If {@code bound} is a power of two then limiting is a - * simple masking operation. Otherwise, the result is re-calculated by - * invoking {@code nextInt()} until the result is greater than or equal - * {@code origin} and less than {@code bound}. + * @implSpec The default implementation checks that {@code origin} + * is less than {@code bound}. + * It then invokes {@link #nextInt()} one or more times to ensure a uniform + * distribution in the range {@code origin} (inclusive) + * to {@code bound} (exclusive). + * It assumes the distribution of {@link #nextInt()} to be uniform. */ default int nextInt(int origin, int bound) { RandomSupport.checkRange(origin, bound); @@ -868,13 +866,11 @@ default int nextInt(int origin, int bound) { * * @throws IllegalArgumentException if {@code bound} is not positive * - * @implSpec The default implementation checks that {@code bound} is a - * positive {@code long}. Then invokes {@code nextLong()}, limiting the - * result to be greater than or equal zero and less than {@code bound}. If - * {@code bound} is a power of two then limiting is a simple masking - * operation. Otherwise, the result is re-calculated by invoking - * {@code nextLong()} until the result is greater than or equal zero and - * less than {@code bound}. + * @implSpec The default implementation checks that {@code bound} is positive. + * It then invokes {@link #nextLong()} one or more times to ensure a uniform + * distribution in the range 0 (inclusive) + * to {@code bound} (exclusive). + * It assumes the distribution of {@link #nextLong()} to be uniform. */ default long nextLong(long bound) { RandomSupport.checkBound(bound); @@ -895,13 +891,12 @@ default long nextLong(long bound) { * @throws IllegalArgumentException if {@code origin} is greater than * or equal to {@code bound} * - * @implSpec The default implementation checks that {@code origin} and - * {@code bound} are positive {@code longs}. Then invokes {@code nextLong()}, - * limiting the result to be greater than or equal {@code origin} and less - * than {@code bound}. If {@code bound} is a power of two then limiting is a - * simple masking operation. Otherwise, the result is re-calculated by - * invoking {@code nextLong()} until the result is greater than or equal - * {@code origin} and less than {@code bound}. + * @implSpec The default implementation checks that {@code origin} + * is less than {@code bound}. + * It then invokes {@link #nextLong()} one or more times to ensure a uniform + * distribution in the range {@code origin} (inclusive) + * to {@code bound} (exclusive). + * It assumes the distribution of {@link #nextLong()} to be uniform. */ default long nextLong(long origin, long bound) { RandomSupport.checkRange(origin, bound); From 758ebfe23be5168b7ddf3d1c1e0fecf70e8d4f11 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Tue, 23 Jul 2024 11:50:57 +0000 Subject: [PATCH 04/10] 8335182: Consolidate and streamline String concat code shapes Reviewed-by: liach, jvernee --- .../classes/java/lang/StringConcatHelper.java | 196 ++++------ .../share/classes/java/lang/System.java | 4 - .../java/lang/invoke/StringConcatFactory.java | 34 +- .../jdk/internal/access/JavaLangAccess.java | 6 - .../openjdk/bench/java/lang/StringConcat.java | 12 + .../bench/java/lang/StringConcatStartup.java | 354 ++++++++++++++++++ 6 files changed, 452 insertions(+), 154 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index 49f556e5aa6..e47e124ed4d 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -119,91 +119,64 @@ static long mix(long lengthCoder, long value) { */ static long mix(long lengthCoder, String value) { lengthCoder += value.length(); - if (value.coder() == String.UTF16) { + if (!value.isLatin1()) { lengthCoder |= UTF16; } return checkOverflow(lengthCoder); } /** - * Prepends the stringly representation of boolean value into buffer, + * Prepends constant and the stringly representation of value into buffer, * given the coder and final index. Index is measured in chars, not in bytes! * * @param indexCoder final char index in the buffer, along with coder packed * into higher bits. * @param buf buffer to append to * @param value boolean value to encode + * @param prefix a constant to prepend before value * @return updated index (coder value retained) */ - static long prepend(long indexCoder, byte[] buf, boolean value) { + static long prepend(long indexCoder, byte[] buf, boolean value, String prefix) { int index = (int)indexCoder; if (indexCoder < UTF16) { if (value) { - buf[--index] = 'e'; - buf[--index] = 'u'; - buf[--index] = 'r'; - buf[--index] = 't'; + index -= 4; + buf[index] = 't'; + buf[index + 1] = 'r'; + buf[index + 2] = 'u'; + buf[index + 3] = 'e'; } else { - buf[--index] = 'e'; - buf[--index] = 's'; - buf[--index] = 'l'; - buf[--index] = 'a'; - buf[--index] = 'f'; + index -= 5; + buf[index] = 'f'; + buf[index + 1] = 'a'; + buf[index + 2] = 'l'; + buf[index + 3] = 's'; + buf[index + 4] = 'e'; } + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); return index; } else { if (value) { - StringUTF16.putChar(buf, --index, 'e'); - StringUTF16.putChar(buf, --index, 'u'); - StringUTF16.putChar(buf, --index, 'r'); - StringUTF16.putChar(buf, --index, 't'); + index -= 4; + StringUTF16.putChar(buf, index, 't'); + StringUTF16.putChar(buf, index + 1, 'r'); + StringUTF16.putChar(buf, index + 2, 'u'); + StringUTF16.putChar(buf, index + 3, 'e'); } else { - StringUTF16.putChar(buf, --index, 'e'); - StringUTF16.putChar(buf, --index, 's'); - StringUTF16.putChar(buf, --index, 'l'); - StringUTF16.putChar(buf, --index, 'a'); - StringUTF16.putChar(buf, --index, 'f'); + index -= 5; + StringUTF16.putChar(buf, index, 'f'); + StringUTF16.putChar(buf, index + 1, 'a'); + StringUTF16.putChar(buf, index + 2, 'l'); + StringUTF16.putChar(buf, index + 3, 's'); + StringUTF16.putChar(buf, index + 4, 'e'); } + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); return index | UTF16; } } - /** - * Prepends constant and the stringly representation of value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value boolean value to encode - * @param prefix a constant to prepend before value - * @return updated index (coder value retained) - */ - static long prepend(long indexCoder, byte[] buf, boolean value, String prefix) { - indexCoder = prepend(indexCoder, buf, value); - indexCoder = prepend(indexCoder, buf, prefix); - return indexCoder; - } - - /** - * Prepends the stringly representation of char value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value char value to encode - * @return updated index (coder value retained) - */ - static long prepend(long indexCoder, byte[] buf, char value) { - if (indexCoder < UTF16) { - buf[(int)(--indexCoder)] = (byte) (value & 0xFF); - } else { - StringUTF16.putChar(buf, (int)(--indexCoder), value); - } - return indexCoder; - } - /** * Prepends constant and the stringly representation of value into buffer, * given the coder and final index. Index is measured in chars, not in bytes! @@ -216,26 +189,17 @@ static long prepend(long indexCoder, byte[] buf, char value) { * @return updated index (coder value retained) */ static long prepend(long indexCoder, byte[] buf, char value, String prefix) { - indexCoder = prepend(indexCoder, buf, value); - indexCoder = prepend(indexCoder, buf, prefix); - return indexCoder; - } - - /** - * Prepends the stringly representation of integer value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value integer value to encode - * @return updated index (coder value retained) - */ - static long prepend(long indexCoder, byte[] buf, int value) { + int index = (int)indexCoder; if (indexCoder < UTF16) { - return StringLatin1.getChars(value, (int)indexCoder, buf); + buf[--index] = (byte) (value & 0xFF); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + return index; } else { - return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16; + StringUTF16.putChar(buf, --index, value); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + return index | UTF16; } } @@ -251,26 +215,17 @@ static long prepend(long indexCoder, byte[] buf, int value) { * @return updated index (coder value retained) */ static long prepend(long indexCoder, byte[] buf, int value, String prefix) { - indexCoder = prepend(indexCoder, buf, value); - indexCoder = prepend(indexCoder, buf, prefix); - return indexCoder; - } - - /** - * Prepends the stringly representation of long value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value long value to encode - * @return updated index (coder value retained) - */ - static long prepend(long indexCoder, byte[] buf, long value) { + int index = (int)indexCoder; if (indexCoder < UTF16) { - return StringLatin1.getChars(value, (int)indexCoder, buf); + index = StringLatin1.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + return index; } else { - return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16; + index = StringUTF16.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + return index | UTF16; } } @@ -286,29 +241,18 @@ static long prepend(long indexCoder, byte[] buf, long value) { * @return updated index (coder value retained) */ static long prepend(long indexCoder, byte[] buf, long value, String prefix) { - indexCoder = prepend(indexCoder, buf, value); - indexCoder = prepend(indexCoder, buf, prefix); - return indexCoder; - } - - /** - * Prepends the stringly representation of String value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value String value to encode - * @return updated index (coder value retained) - */ - static long prepend(long indexCoder, byte[] buf, String value) { - indexCoder -= value.length(); + int index = (int)indexCoder; if (indexCoder < UTF16) { - value.getBytes(buf, (int)indexCoder, String.LATIN1); + index = StringLatin1.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + return index; } else { - value.getBytes(buf, (int)indexCoder, String.UTF16); + index = StringUTF16.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + return index | UTF16; } - return indexCoder; } /** @@ -323,9 +267,18 @@ static long prepend(long indexCoder, byte[] buf, String value) { * @return updated index (coder value retained) */ static long prepend(long indexCoder, byte[] buf, String value, String prefix) { - indexCoder = prepend(indexCoder, buf, value); - indexCoder = prepend(indexCoder, buf, prefix); - return indexCoder; + int index = ((int)indexCoder) - value.length(); + if (indexCoder < UTF16) { + value.getBytes(buf, index, String.LATIN1); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + return index; + } else { + value.getBytes(buf, index, String.UTF16); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + return index | UTF16; + } } /** @@ -375,8 +328,7 @@ static String simpleConcat(Object first, Object second) { byte[] buf = newArray(indexCoder); // prepend each argument in reverse order, since we prepending // from the end of the byte array - indexCoder = prepend(indexCoder, buf, s2); - indexCoder = prepend(indexCoder, buf, s1); + indexCoder = prepend(indexCoder, buf, s2, s1); return newString(buf, indexCoder); } @@ -443,8 +395,10 @@ static byte[] newArrayWithSuffix(String suffix, long indexCoder) { */ @ForceInline static byte[] newArray(long indexCoder) { - byte coder = (byte)(indexCoder >> 32); - int index = ((int)indexCoder) << coder; + int index = (int)indexCoder; + if (indexCoder >= UTF16) { + index <<= 1; + } if (index < 0) { throw new OutOfMemoryError("Overflow: String length out of range"); } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 5e28b9ce95b..3157a200278 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2611,10 +2611,6 @@ public MethodHandle stringConcatHelper(String name, MethodType methodType) { return StringConcatHelper.lookupStatic(name, methodType); } - public long stringConcatHelperPrepend(long indexCoder, byte[] buf, String value) { - return StringConcatHelper.prepend(indexCoder, buf, value); - } - public long stringConcatInitialCoder() { return StringConcatHelper.initialCoder(); } diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 29896fd8f93..cf552c434be 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -565,17 +565,17 @@ private static MethodHandle generateMHInlineCopy(MethodType mt, String[] constan // Fold in byte[] instantiation at argument 0 MethodHandle newArrayCombinator; - if (suffix != null) { - // newArray variant that deals with prepending any trailing constant - // - // initialLengthCoder is adjusted to have the correct coder - // and length: The newArrayWithSuffix method expects only the coder of the - // suffix to be encoded into indexCoder - initialLengthCoder -= suffix.length(); - newArrayCombinator = newArrayWithSuffix(suffix); - } else { - newArrayCombinator = newArray(); + if (suffix == null || suffix.isEmpty()) { + suffix = ""; } + // newArray variant that deals with prepending any trailing constant + // + // initialLengthCoder is adjusted to have the correct coder + // and length: The newArrayWithSuffix method expects only the coder of the + // suffix to be encoded into indexCoder + initialLengthCoder -= suffix.length(); + newArrayCombinator = newArrayWithSuffix(suffix); + mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, newArrayCombinator, 1 // index ); @@ -738,9 +738,7 @@ private static MethodHandle noPrefixPrepender(Class cl) { int idx = classIndex(cl); MethodHandle prepend = NO_PREFIX_PREPENDERS[idx]; if (prepend == null) { - NO_PREFIX_PREPENDERS[idx] = prepend = JLA.stringConcatHelper("prepend", - methodType(long.class, long.class, byte[].class, - Wrapper.asPrimitiveType(cl))).rebind(); + NO_PREFIX_PREPENDERS[idx] = prepend = MethodHandles.insertArguments(prepender(cl), 3, ""); } return prepend; } @@ -902,16 +900,6 @@ private static MethodHandle newArrayWithSuffix(String suffix) { return MethodHandles.insertArguments(mh, 0, suffix); } - private @Stable static MethodHandle NEW_ARRAY; - private static MethodHandle newArray() { - MethodHandle mh = NEW_ARRAY; - if (mh == null) { - NEW_ARRAY = mh = - JLA.stringConcatHelper("newArray", methodType(byte[].class, long.class)); - } - return mh; - } - /** * Public gateways to public "stringify" methods. These methods have the * form String apply(T obj), and normally delegate to {@code String.valueOf}, diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index c31e745cd89..2254c065e2e 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -432,12 +432,6 @@ public interface JavaLangAccess { */ MethodHandle stringConcatHelper(String name, MethodType methodType); - /** - * Prepends constant and the stringly representation of value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - */ - long stringConcatHelperPrepend(long indexCoder, byte[] buf, String value); - /** * Get the string concat initial coder */ diff --git a/test/micro/org/openjdk/bench/java/lang/StringConcat.java b/test/micro/org/openjdk/bench/java/lang/StringConcat.java index c4d2d1bfe11..015ad224631 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringConcat.java +++ b/test/micro/org/openjdk/bench/java/lang/StringConcat.java @@ -219,4 +219,16 @@ public String concat23StringConst() { * questions. """; } + + public static void main(String... args) { + StringConcat concat = new StringConcat(); + concat.concat4String(); + concat.concat123String(); + concat.concat6String(); + concat.concat13String(); + concat.concat23String(); + concat.concatConstInt(); + } + + } diff --git a/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java b/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java new file mode 100644 index 00000000000..d146fbf9885 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java @@ -0,0 +1,354 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + +import java.util.concurrent.TimeUnit; + +/** + * Benchmarks stressing String concat startup. Provides a main method that takes names of the sub-benchmarks + * of choice as arguments to work well as a standalone startup test/diagnostic + * + * StringSingle + * MixedSmall - small number of mixed expressions + * StringLarge - large number of expressions with a mix of String arguments and constants + * MixedLarge - large number of expressions with a mix of constants, Strings and primivitive arguments + */ +public class StringConcatStartup { + + public static void main(String... args) { + String[] selection = new String[] { "StringLarge", "MixedSmall", "StringSingle", "MixedLarge" }; + if (args.length > 0) { + selection = args; + } + for (String select : selection) { + switch (select) { + case "StringSingle" -> new StringSingle().run(); + case "MixedSmall" -> new MixedSmall().run(); + case "StringLarge" -> new StringLarge().run(); + case "MixedLarge" -> new MixedLarge().run(); + } + } + } + + @BenchmarkMode(Mode.SingleShotTime) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @State(Scope.Thread) + @Fork(value = 40, warmups = 2) + public static class StringSingle { + + public String s = "foo"; + + @Benchmark + public String run() { + return "" + s; + } + } + + + @BenchmarkMode(Mode.SingleShotTime) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @State(Scope.Thread) + @Fork(value = 20, warmups = 2) + public static class MixedSmall { + + public String s = "foo"; + public int i = 17; + public long l = 21L; + public char c = 'a'; + public boolean z = true; + + @Benchmark + public String run() { + String concat; + concat = "foo" + s + "bar" + i + "baz" + l + "bur" + c + "dub" + z + "foo"; + concat = "bar" + i + "baz" + l + c + "dub" + z + "foo"; + concat = "bar" + i + "baz" + l + "dub" + z; + concat = s + "bar" + i + s + "bur" + c + "dub" + s + "foo"; + return concat; + } + } + + @BenchmarkMode(Mode.SingleShotTime) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @State(Scope.Thread) + @Fork(value = 10, warmups = 2) + public static class StringLarge { + + public String i = "1"; + public String l = "2"; + public String b = "3"; + public String s = "4"; + public String c = "5"; + public String S = "6"; + public String z = "7"; + public String f = "8"; + public String d = "9"; + + @Benchmark + public void run() { + String concat; + concat = "" + "S" + f + l + z + f + "S" + d + S + d + S; + concat = "" + "S" + S + i + b + b + z + i + s + S + b + "S"; + concat = "" + S + f + f + f + b + f + "S" + S + S + i + b; + concat = "" + b + l + i + l + b + S + i + i + f + z; + concat = "" + f + z + d + b + "S" + c + S + f + s + s + d; + concat = "" + f + b + d + d + l + s + s + b + l + c + z; + concat = "" + S + z + l + s + s + i + f + c + i + i + d; + concat = "" + b + "S" + c + d + "S" + d + s + "S" + f + c + l + "S" + i + z + d + "S"; + concat = "" + S + "S" + S + i + c + z + i + i + S + b; + concat = "" + S + S + d + s + z + f + z + i + b + s + s + "S"; + concat = "" + i + z + f + d + f + S + c + "S" + i; + concat = "" + c + c + c + "S" + S + l; + concat = "" + z + d + s + i + l + i + z + c + i + f + l + s + b + S + S + s + z + "S" + c + z; + concat = "" + d + b + l + S + s + b + "S" + c + d + c + c + l + d + S + b + l + b + S + d + "S"; + concat = "" + c + z + c + d + b + S + c + b + S + "S" + d + s + c + s + b + c + b + z + s + i; + concat = "" + l + S + "S"; + concat = "" + s + i + f + S + f + i + s + d + S + l + i + "S" + i + S + d + i + l + c + i + d; + concat = "" + S + l + s + i + b + f + z + c + S + d + s + f + l + i + s + b + f + s + d + l; + concat = "" + i + d + b + d + S + b + d + "S" + "S" + i + l + i + b + "S" + "S" + s + "S" + i + b + c; + concat = "" + "S" + l + "S" + s + d + l + i + l + z + s + i + z + b + b + c + S + d + d + s + i; + concat = "" + b + c + i + b + z + d + z + z + d + z + l + b + z + f + b + c + d + c + z + c; + concat = "" + b + z + f + b + z + f + s + z + f + "S" + l + f + l + z + b + z + i + l + i + S; + concat = "" + c + b + "S" + z; + concat = "" + b + "S" + i + "S" + S + i + l + c + i + c + z + z + d + "S" + z + z + c + z + z + i; + concat = "" + f + c + c + "S" + c + s + i + z + b + s + f + b + i + i + z + f + d + f + i + i; + concat = "" + d + s + z + l + s + d + S + i + S + s + i + c + b + c + s + "S" + d + S + f + s; + concat = "" + S + f + s + z + d + d + S + s + s + z + f + z + "S" + i + d + d + S + c + S + "S"; + concat = "" + c + c + b + S + "S" + "S" + d + S + s + b + c + d + z + c + b + i + S + z + i + s; + concat = "" + l + l + d + z + s + s + i + i + l + c + f + z + i + f + l + z + s + d + f + l; + concat = "" + f + d + "S" + s; + concat = "" + d + S + "S" + S + f + "S" + c + i + s + b + c + b + l + f + S + c + c + i + z + s; + concat = "" + z + "S" + s + S + s + d + d + s + f + "S" + f + "S" + i + S + "S" + c + l + b + f + f; + concat = "" + l + f + d + b + s + f + d + "S" + l + s + "S" + b + b + s + S + S + "S" + "S" + d + b; + concat = "" + b + l + f + b + S + f + z + s + S + f + b + b + s + s + b + s + l + d + l; + concat = "" + b + b + S + S + S + z + z + d + "S" + l + "S" + s + i + "S" + c + f + S + f + i; + concat = "" + l + l + f + i + S + s + "S" + "S" + z + d + "S" + l + d + b + f + f + l + b + b; + concat = "" + l + f + "S" + f + f + i + l + l + i + S + b + f + d + i + c + c + d + d + i; + concat = "" + l + b + s + d + i + i + d + c + "S" + s + f + d + z + d + S + c; + concat = "" + f + s + "S" + z + s + "S" + b + b + b + d + d + b + z + l + c + b; + concat = "" + l + d + "S" + b + z + z + f + c + z + c + c + c + c + d; + concat = "" + z + d + l + "S" + i + s + b + b + d + s + s; + concat = "" + f + i + d + S + f + f + i + s + d + S + c + l + d + s + c + i; + concat = "" + f + c + i + "S" + "S" + c + f + b + l + i + s + c + i + S + S + i; + concat = "" + z + S + z + d + d + S + "S" + f + d + s + s + "S" + l + z + l + c; + concat = "" + b + c + s + f + S + l + b + f + "S" + l + "S" + c + c + z + b + b; + concat = "" + c + b + z + s + d + l + l + S + l + "S" + f + S + c + f + s + f; + concat = "" + z + z + d + i + z + s + z + S + f + S + "S" + "S" + l + d + c + d; + concat = "" + c + S + s + f + c + i + b + l + S + c + l + f + f + l + i + l; + concat = "" + "S" + i + f + d + s + S + S + l + s + S + l + "S" + b + l + s + l + d + d + f + S; + concat = "" + l + z + c + l + f + f + d + s + l + b + d + f + S + S + "S" + i + i + s + f + i; + concat = "" + S + S + l + S + z + d + s + c + "S" + d + f + d + f + f + z + i + f + l + S + s; + concat = "" + z + d + z + l + f + s + d + z + i + S + S + d + i + z + c + i + i + f + b + "S"; + concat = "" + b + d + "S" + f + f + d + s + i + b + l + i + b + f + f + b + f + l + i + z + l; + concat = "" + c + z + s + "S" + z + f + "S" + i + f + s + l + i + "S" + d + i + b + i + S + b + l; + concat = "" + d + l + s + c + l + d + "S" + "S" + s + S + f + z + b + s + b + f + z + z + l + l; + concat = "" + f + b + "S" + s + i + "S" + s + f + c + f + c + f + i + i + b + i + i + b + S + S; + concat = "" + i + i + s + i + s + S + s + "S" + c + c + f + s + d + l + l + d + f + l + i + S; + concat = "" + z + d + z + "S" + c + i + f + s + b + S + i + c + s + b + c + f + s + z + f + c; + concat = "" + f + s + f + b + l + z + f + f + f + c + z + S + b + s + z + i + s + S + i + b; + concat = "" + d + i + S + b + i + "S" + l + S + S + S + z + i + z + b; + concat = "" + "S" + S + s + l + f + i + l + b + f + S + d + c + b + d; + concat = "" + c + i + i + d + S + z + c + i + c + S + f + i + c + c; + concat = "" + "S" + "S" + c + d + z + l + d + z + f + b + d + z + S + f; + concat = "" + b + d + z + d + i + z + d + b + d + "S" + c + f + d; + concat = "" + d + s + f + c + i + "S" + b + b + S + i + s + d + "S" + f; + concat = "" + l + S + d + b + S + s + "S" + s + s + l + S + "S" + c + d; + concat = "" + c + s + z + c + S + S + "S" + l + S + f + f + c + S + f; + concat = "" + d + i + s + c + z + "S" + d + f + "S" + S + c + b + "S" + c; + concat = "" + i + b + "S" + l + S + d + "S" + c + b + s + f + l + f + "S"; + concat = "" + c + b + f + "S" + S + s + i + l + s + z + z + f + l + b; + concat = "" + S + s + "S" + d + s + z + "S" + i + i + z + S + b + f + i; + concat = "" + z + S + S + "S" + S + S + z + b + S + z + b + f + s + l; + concat = "" + s + z + d + "S" + z + l + f + z + s + z + d + l + s + l; + concat = "" + l + d + i + s + i + c + i + f + b + f + s + b + s + s; + concat = "" + z + "S" + S + "S" + "S" + i + "S" + s + d + z + l; + concat = "" + i + S + S + "S" + f + "S" + "S" + z + S + z + b + z + c + b; + concat = "" + i + f + f + d + z + f + z + b + "S" + c + l + l + z + s + S + s; + concat = "" + b + b + z + "S" + f + s + "S" + l +c + S + i + i + b + "S" + S; + concat = "" + i + "S" + d + d + d + "S" + f + "S" + b + s + S + i + "S" + d + b; + concat = "" + s + f + b + d + c + d + c + S + S + b + i + b + z + c; + concat = "" + l + l + S + l + f + s + i + c + z + f + d + l + f + b + l + f + f + i + i + z; + concat = "" + l + l + l + l + s + s + f + i + i + f + z + c + S + s + f + "S" + "S" + s + z + s; + concat = "" + S + z + f + b + l + c + i + l; + concat = "" + c + z + b + f + i + i + f + d + f + f + d + d + l + d + S + "S" + i + c + b + f; + concat = "" + s + d + S + d + b + l + l + f + b + "S" + i + z + b + S + S + c + S + f + S + z; + concat = "" + l + S + S + i + l + s + d + f + z + i + "S" + b + f + c + z + c + S + c + i + s; + concat = "" + l + S + S + s + f + S + s + "S" + c + c + c; + concat = "" + s + "S" + c + d + z + c + l + c + z + S + i + f + c + c + s + "S" + S + z + s + "S"; + concat = "" + c + i + z + s + b + s + s + b + "S" + d + "S" + z + f + "S" + c + S + s + S + b + i; + concat = "" + s + c + d + d + "S" + "S" + l + s + i + l + l + f + S + f + f + i + S + d + l + c; + concat = "" + "S" + S + b + c + i + "S" + c + c + s + i + "S" + b + i + b + b + S + f + l + s + "S"; + concat = "" + l + l + b + f + i + i + f + z + c + S + b + f + z + "S" + s + z + "S" + f + S + s; + concat = "" + i + c + b + i + b + z + "S" + i + c + i + l + "S" + z + b + b + i + i + c + i + f; + concat = "" + "S" + c + d + z + d + f + c + c + b + "S" + l + f + d + "S" + s + s + S + i + s + i; + concat = "" + S + "S" + d + c + "S" + S + "S" + b + f + z + "S" + l + d + f + "S" + S + d + b + c + c; + concat = "" + f + S + l + s + l + z + S + d + S + b + f + c + s + b + "S" + z + "S" + "S" + b + z; + concat = "" + f + s + c + i + S + b + s + S + i + S + c + b + s + d + i + "S" + s + l + c + s; + concat = "" + l + f + s + b + d + b + i + c + c + b + s + f + i + z + s + i + s + "S" + l + z; + concat = "" + d + z + z + c + b + b + s + b + S + l + d + i + S + d + "S" + i + S + i + b + S; + concat = "" + c + d + "S" + f + i + b + d + c + z + f + "S" + i + d + b + f + s + "S" + c + S + i; + concat = "" + i + z + "S" + b + S + s + c + s + f + S + S + f + z + s + b + d + z + i + s + z; + concat = "" + z + s + z + l + "S" + S + s + "S" + i + b + c + s + l + l + s + i + c + i + i + d; + concat = "" + "S" + b + l + z + c + f + l + S + "S" + l + i + z + z + l + S + "S" + z + S + z + c + "S"; + concat = "" + "S" + f + S + i + i + i + "S" + i + i + l + c + l + S + S + z + b + i + c + f + S; + concat = "" + c + z + S + S + b + i + c; + concat = "" + S + s + S + c; + } + } + + @BenchmarkMode(Mode.SingleShotTime) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @State(Scope.Thread) + @Fork(value = 10, warmups = 2) + public static class MixedLarge { + + public int i = 17; + public long l = 21L; + public byte b = (byte)17; + public short s = (short)17; + public char c = 'a'; + public String S = "S"; + public float f = 1.0f; + public double d = 2.0; + public boolean z = true; + + @Benchmark + public void run() { + String concat; + concat = "" + "S" + f + l + z + f + "S" + d + S + d + S; + concat = "" + "S" + S + i + b + b + z + i + s + S + b + "S"; + concat = "" + S + f + f + f + b + f + "S" + S + S + i + b; + concat = "" + b + l + i + l + b + S + i + i + f + z; + concat = "" + f + z + d + b + "S" + c + S + f + s + s + d; + concat = "" + f + b + d + d + l + s + s + b + l + c + z; + concat = "" + S + z + l + s + s + i + f + c + i + i + d; + concat = "" + b + "S" + c + d + "S" + d + s + "S" + f + c + l + "S" + i + z + d + "S"; + concat = "" + S + "S" + S + i + c + z + i + i + S + b; + concat = "" + S + S + d + s + z + f + z + i + b + s + s + "S"; + concat = "" + i + z + f + d + f + S + c + "S" + i; + concat = "" + c + c + c + "S" + S + l; + concat = "" + z + d + s + i + l + i + z + c + i + f + l + s + b + S + S + s + z + "S" + c + z; + concat = "" + d + b + l + S + s + b + "S" + c + d + c + c + l + d + S + b + l + b + S + d + "S"; + concat = "" + c + z + c + d + b + S + c + b + S + "S" + d + s + c + s + b + c + b + z + s + i; + concat = "" + l + S + "S"; + concat = "" + s + i + f + S + f + i + s + d + S + l + i + "S" + i + S + d + i + l + c + i + d; + concat = "" + S + l + s + i + b + f + z + c + S + d + s + f + l + i + s + b + f + s + d + l; + concat = "" + i + d + b + d + S + b + d + "S" + "S" + i + l + i + b + "S" + "S" + s + "S" + i + b + c; + concat = "" + "S" + l + "S" + s + d + l + i + l + z + s + i + z + b + b + c + S + d + d + s + i; + concat = "" + b + c + i + b + z + d + z + z + d + z + l + b + z + f + b + c + d + c + z + c; + concat = "" + b + z + f + b + z + f + s + z + f + "S" + l + f + l + z + b + z + i + l + i + S; + concat = "" + c + b + "S" + z; + concat = "" + b + "S" + i + "S" + S + i + l + c + i + c + z + z + d + "S" + z + z + c + z + z + i; + concat = "" + f + c + c + "S" + c + s + i + z + b + s + f + b + i + i + z + f + d + f + i + i; + concat = "" + d + s + z + l + s + d + S + i + S + s + i + c + b + c + s + "S" + d + S + f + s; + concat = "" + S + f + s + z + d + d + S + s + s + z + f + z + "S" + i + d + d + S + c + S + "S"; + concat = "" + c + c + b + S + "S" + "S" + d + S + s + b + c + d + z + c + b + i + S + z + i + s; + concat = "" + l + l + d + z + s + s + i + i + l + c + f + z + i + f + l + z + s + d + f + l; + concat = "" + f + d + "S" + s; + concat = "" + d + S + "S" + S + f + "S" + c + i + s + b + c + b + l + f + S + c + c + i + z + s; + concat = "" + z + "S" + s + S + s + d + d + s + f + "S" + f + "S" + i + S + "S" + c + l + b + f + f; + concat = "" + l + f + d + b + s + f + d + "S" + l + s + "S" + b + b + s + S + S + "S" + "S" + d + b; + concat = "" + b + l + f + b + S + f + z + s + S + f + b + b + s + s + b + s + l + d + l; + concat = "" + b + b + S + S + S + z + z + d + "S" + l + "S" + s + i + "S" + c + f + S + f + i; + concat = "" + l + l + f + i + S + s + "S" + "S" + z + d + "S" + l + d + b + f + f + l + b + b; + concat = "" + l + f + "S" + f + f + i + l + l + i + S + b + f + d + i + c + c + d + d + i; + concat = "" + l + b + s + d + i + i + d + c + "S" + s + f + d + z + d + S + c; + concat = "" + f + s + "S" + z + s + "S" + b + b + b + d + d + b + z + l + c + b; + concat = "" + l + d + "S" + b + z + z + f + c + z + c + c + c + c + d; + concat = "" + z + d + l + "S" + i + s + b + b + d + s + s; + concat = "" + f + i + d + S + f + f + i + s + d + S + c + l + d + s + c + i; + concat = "" + f + c + i + "S" + "S" + c + f + b + l + i + s + c + i + S + S + i; + concat = "" + z + S + z + d + d + S + "S" + f + d + s + s + "S" + l + z + l + c; + concat = "" + b + c + s + f + S + l + b + f + "S" + l + "S" + c + c + z + b + b; + concat = "" + c + b + z + s + d + l + l + S + l + "S" + f + S + c + f + s + f; + concat = "" + z + z + d + i + z + s + z + S + f + S + "S" + "S" + l + d + c + d; + concat = "" + c + S + s + f + c + i + b + l + S + c + l + f + f + l + i + l; + concat = "" + "S" + i + f + d + s + S + S + l + s + S + l + "S" + b + l + s + l + d + d + f + S; + concat = "" + l + z + c + l + f + f + d + s + l + b + d + f + S + S + "S" + i + i + s + f + i; + concat = "" + S + S + l + S + z + d + s + c + "S" + d + f + d + f + f + z + i + f + l + S + s; + concat = "" + z + d + z + l + f + s + d + z + i + S + S + d + i + z + c + i + i + f + b + "S"; + concat = "" + b + d + "S" + f + f + d + s + i + b + l + i + b + f + f + b + f + l + i + z + l; + concat = "" + c + z + s + "S" + z + f + "S" + i + f + s + l + i + "S" + d + i + b + i + S + b + l; + concat = "" + d + l + s + c + l + d + "S" + "S" + s + S + f + z + b + s + b + f + z + z + l + l; + concat = "" + f + b + "S" + s + i + "S" + s + f + c + f + c + f + i + i + b + i + i + b + S + S; + concat = "" + i + i + s + i + s + S + s + "S" + c + c + f + s + d + l + l + d + f + l + i + S; + concat = "" + z + d + z + "S" + c + i + f + s + b + S + i + c + s + b + c + f + s + z + f + c; + concat = "" + f + s + f + b + l + z + f + f + f + c + z + S + b + s + z + i + s + S + i + b; + concat = "" + d + i + S + b + i + "S" + l + S + S + S + z + i + z + b; + concat = "" + "S" + S + s + l + f + i + l + b + f + S + d + c + b + d; + concat = "" + c + i + i + d + S + z + c + i + c + S + f + i + c + c; + concat = "" + "S" + "S" + c + d + z + l + d + z + f + b + d + z + S + f; + concat = "" + b + d + z + d + i + z + d + b + d + "S" + c + f + d; + concat = "" + d + s + f + c + i + "S" + b + b + S + i + s + d + "S" + f; + concat = "" + l + S + d + b + S + s + "S" + s + s + l + S + "S" + c + d; + concat = "" + c + s + z + c + S + S + "S" + l + S + f + f + c + S + f; + concat = "" + d + i + s + c + z + "S" + d + f + "S" + S + c + b + "S" + c; + concat = "" + i + b + "S" + l + S + d + "S" + c + b + s + f + l + f + "S"; + concat = "" + c + b + f + "S" + S + s + i + l + s + z + z + f + l + b; + concat = "" + S + s + "S" + d + s + z + "S" + i + i + z + S + b + f + i; + concat = "" + z + S + S + "S" + S + S + z + b + S + z + b + f + s + l; + concat = "" + s + z + d + "S" + z + l + f + z + s + z + d + l + s + l; + concat = "" + l + d + i + s + i + c + i + f + b + f + s + b + s + s; + concat = "" + z + "S" + S + "S" + "S" + i + "S" + s + d + z + l; + concat = "" + i + S + S + "S" + f + "S" + "S" + z + S + z + b + z + c + b; + concat = "" + i + f + f + d + z + f + z + b + "S" + c + l + l + z + s + S + s; + concat = "" + b + b + z + "S" + f + s + "S" + l +c + S + i + i + b + "S" + S; + concat = "" + i + "S" + d + d + d + "S" + f + "S" + b + s + S + i + "S" + d + b; + concat = "" + s + f + b + d + c + d + c + S + S + b + i + b + z + c; + concat = "" + l + l + S + l + f + s + i + c + z + f + d + l + f + b + l + f + f + i + i + z; + concat = "" + l + l + l + l + s + s + f + i + i + f + z + c + S + s + f + "S" + "S" + s + z + s; + concat = "" + S + z + f + b + l + c + i + l; + concat = "" + c + z + b + f + i + i + f + d + f + f + d + d + l + d + S + "S" + i + c + b + f; + concat = "" + s + d + S + d + b + l + l + f + b + "S" + i + z + b + S + S + c + S + f + S + z; + concat = "" + l + S + S + i + l + s + d + f + z + i + "S" + b + f + c + z + c + S + c + i + s; + concat = "" + l + S + S + s + f + S + s + "S" + c + c + c; + concat = "" + s + "S" + c + d + z + c + l + c + z + S + i + f + c + c + s + "S" + S + z + s + "S"; + concat = "" + c + i + z + s + b + s + s + b + "S" + d + "S" + z + f + "S" + c + S + s + S + b + i; + concat = "" + s + c + d + d + "S" + "S" + l + s + i + l + l + f + S + f + f + i + S + d + l + c; + concat = "" + "S" + S + b + c + i + "S" + c + c + s + i + "S" + b + i + b + b + S + f + l + s + "S"; + concat = "" + l + l + b + f + i + i + f + z + c + S + b + f + z + "S" + s + z + "S" + f + S + s; + concat = "" + i + c + b + i + b + z + "S" + i + c + i + l + "S" + z + b + b + i + i + c + i + f; + concat = "" + "S" + c + d + z + d + f + c + c + b + "S" + l + f + d + "S" + s + s + S + i + s + i; + concat = "" + S + "S" + d + c + "S" + S + "S" + b + f + z + "S" + l + d + f + "S" + S + d + b + c + c; + concat = "" + f + S + l + s + l + z + S + d + S + b + f + c + s + b + "S" + z + "S" + "S" + b + z; + concat = "" + f + s + c + i + S + b + s + S + i + S + c + b + s + d + i + "S" + s + l + c + s; + concat = "" + l + f + s + b + d + b + i + c + c + b + s + f + i + z + s + i + s + "S" + l + z; + concat = "" + d + z + z + c + b + b + s + b + S + l + d + i + S + d + "S" + i + S + i + b + S; + concat = "" + c + d + "S" + f + i + b + d + c + z + f + "S" + i + d + b + f + s + "S" + c + S + i; + concat = "" + i + z + "S" + b + S + s + c + s + f + S + S + f + z + s + b + d + z + i + s + z; + concat = "" + z + s + z + l + "S" + S + s + "S" + i + b + c + s + l + l + s + i + c + i + i + d; + concat = "" + "S" + b + l + z + c + f + l + S + "S" + l + i + z + z + l + S + "S" + z + S + z + c + "S"; + concat = "" + "S" + f + S + i + i + i + "S" + i + i + l + c + l + S + S + z + b + i + c + f + S; + concat = "" + c + z + S + S + b + i + c; + concat = "" + S + s + S + c; + } + } +} From abbd847476e46dc5a0811ba526db0d5e87212f53 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 23 Jul 2024 12:11:47 +0000 Subject: [PATCH 05/10] 8335939: Hide element writing across the ClassFile API Reviewed-by: asotona --- .../java/lang/classfile/Annotation.java | 3 +- .../lang/classfile/AnnotationElement.java | 3 +- .../java/lang/classfile/AnnotationValue.java | 4 +- .../java/lang/classfile/Attribute.java | 2 +- .../lang/classfile/BootstrapMethodEntry.java | 3 +- .../java/lang/classfile/BufWriter.java | 39 ------------- .../java/lang/classfile/ClassFileElement.java | 4 +- .../java/lang/classfile/ClassReader.java | 15 ----- .../java/lang/classfile/CustomAttribute.java | 8 +-- .../java/lang/classfile/FieldModel.java | 2 +- .../java/lang/classfile/MethodModel.java | 2 +- .../java/lang/classfile/WritableElement.java | 53 ------------------ .../constantpool/ConstantPoolBuilder.java | 4 +- .../classfile/constantpool/PoolEntry.java | 5 +- .../classfile/instruction/LocalVariable.java | 15 +---- .../instruction/LocalVariableType.java | 12 +--- .../impl/AbstractAttributeMapper.java | 40 ++++++++------ .../impl/AbstractBoundLocalVariable.java | 8 +-- .../classfile/impl/AbstractPoolEntry.java | 21 +++---- .../impl/AbstractPseudoInstruction.java | 10 ++-- .../classfile/impl/AbstractUnboundModel.java | 2 +- .../classfile/impl/AnnotationImpl.java | 45 ++++++++------- .../classfile/impl/AnnotationReader.java | 23 +++++++- .../classfile/impl/AttributeHolder.java | 9 +-- .../impl/BootstrapMethodEntryImpl.java | 6 +- .../classfile/impl/BoundAttribute.java | 4 +- .../classfile/impl/BufWriterImpl.java | 25 +-------- .../classfile/impl/BufferedCodeBuilder.java | 4 +- .../classfile/impl/BufferedFieldBuilder.java | 2 +- .../classfile/impl/BufferedMethodBuilder.java | 3 +- .../classfile/impl/ClassReaderImpl.java | 10 ++-- .../jdk/internal/classfile/impl/CodeImpl.java | 6 +- .../classfile/impl/DirectClassBuilder.java | 22 ++++---- .../classfile/impl/DirectCodeBuilder.java | 37 ++++++------- .../classfile/impl/DirectFieldBuilder.java | 10 ++-- .../classfile/impl/DirectMethodBuilder.java | 9 +-- .../internal/classfile/impl/FieldImpl.java | 6 +- .../internal/classfile/impl/MethodImpl.java | 7 +-- .../classfile/impl/SplitConstantPool.java | 13 ++--- .../internal/classfile/impl/StackCounter.java | 2 +- .../classfile/impl/StackMapGenerator.java | 4 +- .../classfile/impl/TemporaryConstantPool.java | 5 -- .../classfile/impl/UnboundAttribute.java | 19 +++---- .../jdk/internal/classfile/impl/Util.java | 55 ++++++++++++++++++- .../jdk/jdk/classfile/BoundAttributeTest.java | 4 +- test/jdk/jdk/classfile/CorpusTest.java | 12 ++-- test/jdk/jdk/classfile/LimitsTest.java | 9 +-- test/jdk/jdk/classfile/LowAdaptTest.java | 7 +-- test/jdk/jdk/classfile/VerifierSelfTest.java | 4 +- .../AnnotationDefaultVerifier.java | 6 +- 50 files changed, 263 insertions(+), 360 deletions(-) delete mode 100644 src/java.base/share/classes/java/lang/classfile/WritableElement.java diff --git a/src/java.base/share/classes/java/lang/classfile/Annotation.java b/src/java.base/share/classes/java/lang/classfile/Annotation.java index 3e7548d0859..28c3672bf91 100644 --- a/src/java.base/share/classes/java/lang/classfile/Annotation.java +++ b/src/java.base/share/classes/java/lang/classfile/Annotation.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 @@ -51,7 +51,6 @@ */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface Annotation - extends WritableElement permits TypeAnnotation, AnnotationImpl { /** diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java index 41acb18e788..80adb07ec4b 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.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 @@ -41,7 +41,6 @@ */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface AnnotationElement - extends WritableElement permits AnnotationImpl.AnnotationElementImpl { /** diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index 2882296b6bc..919c8a0441d 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.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 @@ -49,7 +49,7 @@ * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) -public sealed interface AnnotationValue extends WritableElement +public sealed interface AnnotationValue permits AnnotationValue.OfAnnotation, AnnotationValue.OfArray, AnnotationValue.OfConstant, AnnotationValue.OfClass, AnnotationValue.OfEnum { diff --git a/src/java.base/share/classes/java/lang/classfile/Attribute.java b/src/java.base/share/classes/java/lang/classfile/Attribute.java index ad67bdf5365..718f164e8ef 100644 --- a/src/java.base/share/classes/java/lang/classfile/Attribute.java +++ b/src/java.base/share/classes/java/lang/classfile/Attribute.java @@ -80,7 +80,7 @@ */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface Attribute> - extends WritableElement + extends ClassFileElement permits AnnotationDefaultAttribute, BootstrapMethodsAttribute, CharacterRangeTableAttribute, CodeAttribute, CompilationIDAttribute, ConstantValueAttribute, DeprecatedAttribute, EnclosingMethodAttribute, diff --git a/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java b/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java index c472dca8530..5ff3c449fe9 100644 --- a/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/BootstrapMethodEntry.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 @@ -43,7 +43,6 @@ */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface BootstrapMethodEntry - extends WritableElement permits BootstrapMethodEntryImpl { /** diff --git a/src/java.base/share/classes/java/lang/classfile/BufWriter.java b/src/java.base/share/classes/java/lang/classfile/BufWriter.java index 11d6a4501f0..c71b44e7c02 100644 --- a/src/java.base/share/classes/java/lang/classfile/BufWriter.java +++ b/src/java.base/share/classes/java/lang/classfile/BufWriter.java @@ -24,8 +24,6 @@ */ package java.lang.classfile; -import java.util.List; - import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.PoolEntry; @@ -110,13 +108,6 @@ public sealed interface BufWriter */ void writeBytes(byte[] arr); - /** - * Write the contents of another {@link BufWriter} to the buffer - * - * @param other the other {@linkplain BufWriter} - */ - void writeBytes(BufWriter other); - /** * Write a range of a byte array to the buffer * @@ -166,38 +157,8 @@ public sealed interface BufWriter */ void writeIndexOrZero(PoolEntry entry); - /** - * Write a list of entities to the buffer. The length of the list is - * written as a {@code u2}, followed by the bytes corresponding to each - * element in the list. Writing of the entities is delegated to the entry. - * - * @param list the entities - * @param the type of entity - */ - > void writeList(List list); - - /** - * Write a list of constant pool entry indexes to the buffer. The length - * of the list is written as a {@code u2}, followed by a {@code u2} for each - * entry in the list. - * - * @param list the list of entries - * @throws IllegalArgumentException if any entry has invalid index - */ - void writeListIndices(List list); - /** * {@return the number of bytes that have been written to the buffer} */ int size(); - - /** - * Copy the contents of the buffer into a byte array. - * - * @param array the byte array - * @param bufferOffset the offset into the array at which to write the - * contents of the buffer - * @throws IndexOutOfBoundsException if copying outside of the array bounds - */ - void copyTo(byte[] array, int bufferOffset); } diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFileElement.java b/src/java.base/share/classes/java/lang/classfile/ClassFileElement.java index 6452f52e042..a4a8203038f 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFileElement.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFileElement.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 @@ -39,6 +39,6 @@ */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface ClassFileElement - permits AttributedElement, CompoundElement, WritableElement, + permits AttributedElement, CompoundElement, Attribute, ClassElement, CodeElement, FieldElement, MethodElement { } diff --git a/src/java.base/share/classes/java/lang/classfile/ClassReader.java b/src/java.base/share/classes/java/lang/classfile/ClassReader.java index ef4a36729e6..735aae444fc 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassReader.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassReader.java @@ -189,19 +189,4 @@ public sealed interface ClassReader extends ConstantPool * @param len the length of the range */ void copyBytesTo(BufWriter buf, int offset, int len); - - /** - * Compare a range of bytes from the classfile to a range of bytes within - * a {@link BufWriter}. - * - * @param bufWriter the {@linkplain BufWriter} - * @param bufWriterOffset the offset within the {@linkplain BufWriter} - * @param classReaderOffset the offset within the classfile - * @param length the length of the range - * @return whether the two ranges were identical - */ - boolean compare(BufWriter bufWriter, - int bufWriterOffset, - int classReaderOffset, - int length); } diff --git a/src/java.base/share/classes/java/lang/classfile/CustomAttribute.java b/src/java.base/share/classes/java/lang/classfile/CustomAttribute.java index 31544a0ba92..9fe492dc22c 100644 --- a/src/java.base/share/classes/java/lang/classfile/CustomAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/CustomAttribute.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 @@ -59,12 +59,6 @@ public final String attributeName() { return mapper.name(); } - @Override - @SuppressWarnings("unchecked") - public final void writeTo(BufWriter buf) { - mapper.writeAttribute(buf, (T) this); - } - @Override public String toString() { return String.format("CustomAttribute[name=%s]", mapper.name()); diff --git a/src/java.base/share/classes/java/lang/classfile/FieldModel.java b/src/java.base/share/classes/java/lang/classfile/FieldModel.java index 35465dfe97d..e14f264ca2a 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldModel.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldModel.java @@ -42,7 +42,7 @@ */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface FieldModel - extends WritableElement, CompoundElement, AttributedElement, ClassElement + extends CompoundElement, AttributedElement, ClassElement permits BufferedFieldBuilder.Model, FieldImpl { /** {@return the access flags} */ diff --git a/src/java.base/share/classes/java/lang/classfile/MethodModel.java b/src/java.base/share/classes/java/lang/classfile/MethodModel.java index 3d91683e218..651bc194ee3 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodModel.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodModel.java @@ -42,7 +42,7 @@ */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface MethodModel - extends WritableElement, CompoundElement, AttributedElement, ClassElement + extends CompoundElement, AttributedElement, ClassElement permits BufferedMethodBuilder.Model, MethodImpl { /** {@return the access flags} */ diff --git a/src/java.base/share/classes/java/lang/classfile/WritableElement.java b/src/java.base/share/classes/java/lang/classfile/WritableElement.java deleted file mode 100644 index 9a4db4e370f..00000000000 --- a/src/java.base/share/classes/java/lang/classfile/WritableElement.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2022, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.lang.classfile; - -import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.constantpool.PoolEntry; -import jdk.internal.classfile.impl.DirectFieldBuilder; -import jdk.internal.classfile.impl.DirectMethodBuilder; -import jdk.internal.javac.PreviewFeature; - -/** - * A classfile element that can encode itself as a stream of bytes in the - * encoding expected by the classfile format. - * - * @param the type of the entity - * - * @sealedGraph - * @since 22 - */ -@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) -public sealed interface WritableElement extends ClassFileElement - permits Annotation, AnnotationElement, AnnotationValue, Attribute, - PoolEntry, BootstrapMethodEntry, FieldModel, MethodModel, - ConstantPoolBuilder, DirectFieldBuilder, DirectMethodBuilder { - /** - * Writes the element to the specified writer - * - * @param buf the writer - */ - void writeTo(BufWriter buf); -} diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index a43e6f102ed..c0927175476 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -33,13 +33,11 @@ import java.util.List; import java.lang.classfile.BootstrapMethodEntry; -import java.lang.classfile.BufWriter; import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassModel; import jdk.internal.classfile.impl.ClassReaderImpl; import java.lang.constant.ModuleDesc; import java.lang.constant.PackageDesc; -import java.lang.classfile.WritableElement; import jdk.internal.classfile.impl.AbstractPoolEntry.ClassEntryImpl; import jdk.internal.classfile.impl.AbstractPoolEntry.NameAndTypeEntryImpl; import jdk.internal.classfile.impl.SplitConstantPool; @@ -61,7 +59,7 @@ */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface ConstantPoolBuilder - extends ConstantPool, WritableElement + extends ConstantPool permits SplitConstantPool, TemporaryConstantPool { /** diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java index 49bd978e56a..c8b74a13928 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.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.constantpool; -import java.lang.classfile.WritableElement; import jdk.internal.javac.PreviewFeature; /** @@ -34,7 +33,7 @@ * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) -public sealed interface PoolEntry extends WritableElement +public sealed interface PoolEntry permits AnnotationConstantValueEntry, DynamicConstantPoolEntry, LoadableConstantEntry, MemberRefEntry, ModuleEntry, NameAndTypeEntry, PackageEntry { diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java index cd37ab94992..4d3d7553867 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.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,9 +24,6 @@ */ package java.lang.classfile.instruction; -import java.lang.constant.ClassDesc; - -import java.lang.classfile.BufWriter; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; @@ -34,6 +31,8 @@ import java.lang.classfile.PseudoInstruction; import java.lang.classfile.attribute.LocalVariableTableAttribute; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.constant.ClassDesc; + import jdk.internal.classfile.impl.AbstractPseudoInstruction; import jdk.internal.classfile.impl.BoundLocalVariable; import jdk.internal.classfile.impl.TemporaryConstantPool; @@ -84,14 +83,6 @@ default ClassDesc typeSymbol() { */ Label endScope(); - /** - * Writes the local variable to the specified writer - * - * @param buf the writer - * @return true if the variable has been written - */ - boolean writeTo(BufWriter buf); - /** * {@return a local variable pseudo-instruction} * diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java index 1415d0bb57c..4409abe6db2 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.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.instruction; -import java.lang.classfile.BufWriter; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; @@ -33,6 +32,7 @@ import java.lang.classfile.Signature; import java.lang.classfile.attribute.LocalVariableTypeTableAttribute; import java.lang.classfile.constantpool.Utf8Entry; + import jdk.internal.classfile.impl.AbstractPseudoInstruction; import jdk.internal.classfile.impl.BoundLocalVariableType; import jdk.internal.classfile.impl.TemporaryConstantPool; @@ -81,14 +81,6 @@ default Signature signatureSymbol() { */ Label endScope(); - /** - * Writes the local variable to the specified writer - * - * @param buf the writer - * @return true if the variable has been written - */ - boolean writeTo(BufWriter buf); - /** * {@return a local variable type pseudo-instruction} * diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java index 9bb3f275ba1..0029b503d7a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.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 @@ -101,7 +101,7 @@ public AnnotationDefaultAttribute readAttribute(AttributedElement e, ClassReader @Override protected void writeBody(BufWriter buf, AnnotationDefaultAttribute attr) { - attr.defaultValue().writeTo(buf); + AnnotationReader.writeAnnotationValue((BufWriterImpl) buf, attr.defaultValue()); } } @@ -119,7 +119,11 @@ public BootstrapMethodsAttribute readAttribute(AttributedElement e, ClassReader @Override protected void writeBody(BufWriter buf, BootstrapMethodsAttribute attr) { - buf.writeList(attr.bootstrapMethods()); + var b = (BufWriterImpl) buf; + b.writeU2(attr.bootstrapMethodsSize()); + for (var bsm : attr.bootstrapMethods()) { + ((BootstrapMethodEntryImpl) bsm).writeTo(b); + } } } @@ -254,7 +258,7 @@ public ExceptionsAttribute readAttribute(AttributedElement e, ClassReader cf, in @Override protected void writeBody(BufWriter buf, ExceptionsAttribute attr) { - buf.writeListIndices(attr.exceptions()); + Util.writeListIndices(buf, attr.exceptions()); } } @@ -408,19 +412,19 @@ protected void writeBody(BufWriter buf, ModuleAttribute attr) { for (ModuleExportInfo export : attr.exports()) { buf.writeIndex(export.exportedPackage()); buf.writeU2(export.exportsFlagsMask()); - buf.writeListIndices(export.exportsTo()); + Util.writeListIndices(buf, export.exportsTo()); } buf.writeU2(attr.opens().size()); for (ModuleOpenInfo open : attr.opens()) { buf.writeIndex(open.openedPackage()); buf.writeU2(open.opensFlagsMask()); - buf.writeListIndices(open.opensTo()); + Util.writeListIndices(buf, open.opensTo()); } - buf.writeListIndices(attr.uses()); + Util.writeListIndices(buf, attr.uses()); buf.writeU2(attr.provides().size()); for (ModuleProvideInfo provide : attr.provides()) { buf.writeIndex(provide.provides()); - buf.writeListIndices(provide.providesWith()); + Util.writeListIndices(buf, provide.providesWith()); } } } @@ -482,7 +486,7 @@ public ModulePackagesAttribute readAttribute(AttributedElement e, ClassReader cf @Override protected void writeBody(BufWriter buf, ModulePackagesAttribute attr) { - buf.writeListIndices(attr.packages()); + Util.writeListIndices(buf, attr.packages()); } } @@ -554,7 +558,7 @@ public NestMembersAttribute readAttribute(AttributedElement e, ClassReader cf, i @Override protected void writeBody(BufWriter buf, NestMembersAttribute attr) { - buf.writeListIndices(attr.nestMembers()); + Util.writeListIndices(buf, attr.nestMembers()); } } @@ -572,7 +576,7 @@ public PermittedSubclassesAttribute readAttribute(AttributedElement e, ClassRead @Override protected void writeBody(BufWriter buf, PermittedSubclassesAttribute attr) { - buf.writeListIndices(attr.permittedSubclasses()); + Util.writeListIndices(buf, attr.permittedSubclasses()); } } @@ -595,7 +599,7 @@ protected void writeBody(BufWriter buf, RecordAttribute attr) { for (RecordComponentInfo info : components) { buf.writeIndex(info.name()); buf.writeIndex(info.descriptor()); - buf.writeList(info.attributes()); + Util.writeAttributes((BufWriterImpl) buf, info.attributes()); } } } @@ -614,7 +618,7 @@ public RuntimeInvisibleAnnotationsAttribute readAttribute(AttributedElement encl @Override protected void writeBody(BufWriter buf, RuntimeInvisibleAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); + AnnotationReader.writeAnnotations(buf, attr.annotations()); } } @@ -635,7 +639,7 @@ protected void writeBody(BufWriter buf, RuntimeInvisibleParameterAnnotationsAttr List> lists = attr.parameterAnnotations(); buf.writeU1(lists.size()); for (List list : lists) - buf.writeList(list); + AnnotationReader.writeAnnotations(buf, list); } } @@ -653,7 +657,7 @@ public RuntimeInvisibleTypeAnnotationsAttribute readAttribute(AttributedElement @Override protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); + AnnotationReader.writeAnnotations(buf, attr.annotations()); } } @@ -671,7 +675,7 @@ public RuntimeVisibleAnnotationsAttribute readAttribute(AttributedElement enclos @Override protected void writeBody(BufWriter buf, RuntimeVisibleAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); + AnnotationReader.writeAnnotations(buf, attr.annotations()); } } @@ -692,7 +696,7 @@ protected void writeBody(BufWriter buf, RuntimeVisibleParameterAnnotationsAttrib List> lists = attr.parameterAnnotations(); buf.writeU1(lists.size()); for (List list : lists) - buf.writeList(list); + AnnotationReader.writeAnnotations(buf, list); } } @@ -710,7 +714,7 @@ public RuntimeVisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, @Override protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); + AnnotationReader.writeAnnotations(buf, attr.annotations()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java index d3f49e3168a..dcbd8c8fee8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractBoundLocalVariable.java @@ -24,12 +24,11 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.BufWriter; import java.lang.classfile.Label; import java.lang.classfile.constantpool.Utf8Entry; public class AbstractBoundLocalVariable - extends AbstractElement { + extends AbstractElement implements Util.WritableLocalVariable { protected final CodeImpl code; protected final int offset; private Utf8Entry nameEntry; @@ -80,8 +79,9 @@ public int slot() { return code.classReader.readU2(offset + 8); } - public boolean writeTo(BufWriter b) { - var lc = ((BufWriterImpl)b).labelContext(); + @Override + public boolean writeLocalTo(BufWriterImpl b) { + var lc = b.labelContext(); int startBci = lc.labelToBci(startScope()); int endBci = lc.labelToBci(endScope()); if (startBci == -1 || endBci == -1) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index f846ca6fa90..c6e6c4dce57 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -34,7 +34,6 @@ import java.lang.classfile.constantpool.ConstantDynamicEntry; import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.classfile.BufWriter; import java.lang.classfile.constantpool.DoubleEntry; import java.lang.classfile.constantpool.FieldRefEntry; import java.lang.classfile.constantpool.FloatEntry; @@ -123,6 +122,8 @@ public int width() { return (tag == ClassFile.TAG_LONG || tag == ClassFile.TAG_DOUBLE) ? 2 : 1; } + abstract void writeTo(BufWriterImpl buf); + abstract PoolEntry clone(ConstantPoolBuilder cp); public static final class Utf8EntryImpl extends AbstractPoolEntry implements Utf8Entry { @@ -407,7 +408,7 @@ public boolean equalsString(String s) { } @Override - public void writeTo(BufWriter pool) { + void writeTo(BufWriterImpl pool) { if (rawBytes != null) { pool.writeU1(tag); pool.writeU2(rawLen); @@ -478,7 +479,7 @@ public T ref1() { return ref1; } - public void writeTo(BufWriter pool) { + void writeTo(BufWriterImpl pool) { pool.writeU1(tag); pool.writeU2(ref1.index()); } @@ -508,7 +509,7 @@ public U ref2() { return ref2; } - public void writeTo(BufWriter pool) { + void writeTo(BufWriterImpl pool) { pool.writeU1(tag); pool.writeU2(ref1.index()); pool.writeU2(ref2.index()); @@ -814,7 +815,7 @@ public NameAndTypeEntryImpl nameAndType() { return nameAndType; } - public void writeTo(BufWriter pool) { + void writeTo(BufWriterImpl pool) { pool.writeU1(tag); pool.writeU2(bsmIndex); pool.writeU2(nameAndType.index()); @@ -919,7 +920,7 @@ public DirectMethodHandleDesc asSymbol() { } @Override - public void writeTo(BufWriter pool) { + void writeTo(BufWriterImpl pool) { pool.writeU1(tag); pool.writeU1(refKind); pool.writeU2(reference.index()); @@ -1069,7 +1070,7 @@ public static final class IntegerEntryImpl extends PrimitiveEntry } @Override - public void writeTo(BufWriter pool) { + void writeTo(BufWriterImpl pool) { pool.writeU1(tag); pool.writeInt(val); } @@ -1102,7 +1103,7 @@ public static final class FloatEntryImpl extends PrimitiveEntry } @Override - public void writeTo(BufWriter pool) { + void writeTo(BufWriterImpl pool) { pool.writeU1(tag); pool.writeFloat(val); } @@ -1134,7 +1135,7 @@ public static final class LongEntryImpl extends PrimitiveEntry implements } @Override - public void writeTo(BufWriter pool) { + void writeTo(BufWriterImpl pool) { pool.writeU1(tag); pool.writeLong(val); } @@ -1166,7 +1167,7 @@ public static final class DoubleEntryImpl extends PrimitiveEntry impleme } @Override - public void writeTo(BufWriter pool) { + void writeTo(BufWriterImpl pool) { pool.writeU1(tag); pool.writeDouble(val); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java index ffc36037905..00d817b8cb0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.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 @@ -154,7 +154,8 @@ public void writeTo(DirectCodeBuilder writer) { } - private abstract static sealed class AbstractLocalPseudo extends AbstractPseudoInstruction { + private abstract static sealed class AbstractLocalPseudo extends AbstractPseudoInstruction + implements Util.WritableLocalVariable { protected final int slot; protected final Utf8Entry name; protected final Utf8Entry descriptor; @@ -189,8 +190,9 @@ public Label endScope() { return endScope; } - public boolean writeTo(BufWriter b) { - var lc = ((BufWriterImpl)b).labelContext(); + @Override + public boolean writeLocalTo(BufWriterImpl b) { + var lc = b.labelContext(); int startBci = lc.labelToBci(startScope()); int endBci = lc.labelToBci(endScope()); if (startBci == -1 || endBci == -1) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java index 5aebec8ab40..788bdffe1cd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java @@ -35,7 +35,7 @@ public abstract sealed class AbstractUnboundModel extends AbstractElement - implements CompoundElement, AttributedElement + implements CompoundElement, AttributedElement, Util.Writable permits BufferedCodeBuilder.Model, BufferedFieldBuilder.Model, BufferedMethodBuilder.Model { private final List elements; private List> attributes; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java index 4fc2d5cf63b..8290fcd286e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.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 @@ -32,7 +32,7 @@ import static java.lang.classfile.ClassFile.*; -public final class AnnotationImpl implements Annotation { +public final class AnnotationImpl implements Annotation, Util.Writable { private final Utf8Entry className; private final List elements; @@ -53,9 +53,13 @@ public List elements() { } @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { buf.writeIndex(className()); - buf.writeList(elements()); + buf.writeU2(elements().size()); + for (var e : elements) { + buf.writeIndex(e.name()); + AnnotationReader.writeAnnotationValue(buf, e.value()); + } } @Override @@ -81,16 +85,16 @@ public String toString() { public record AnnotationElementImpl(Utf8Entry name, AnnotationValue value) - implements AnnotationElement { + implements AnnotationElement, Util.Writable { @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { buf.writeIndex(name()); - value().writeTo(buf); + AnnotationReader.writeAnnotationValue(buf, value()); } } - public sealed interface OfConstantImpl extends AnnotationValue.OfConstant + public sealed interface OfConstantImpl extends AnnotationValue.OfConstant, Util.Writable permits AnnotationImpl.OfStringImpl, AnnotationImpl.OfDoubleImpl, AnnotationImpl.OfFloatImpl, AnnotationImpl.OfLongImpl, AnnotationImpl.OfIntegerImpl, AnnotationImpl.OfShortImpl, @@ -98,7 +102,7 @@ public sealed interface OfConstantImpl extends AnnotationValue.OfConstant AnnotationImpl.OfBooleanImpl { @Override - default void writeTo(BufWriter buf) { + default void writeTo(BufWriterImpl buf) { buf.writeU1(tag()); buf.writeIndex(constant()); } @@ -237,7 +241,7 @@ public boolean booleanValue() { } public record OfArrayImpl(List values) - implements AnnotationValue.OfArray { + implements AnnotationValue.OfArray, Util.Writable { public OfArrayImpl(List values) { this.values = List.copyOf(values); @@ -249,22 +253,25 @@ public char tag() { } @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { buf.writeU1(tag()); - buf.writeList(values); + buf.writeU2(values.size()); + for (var e : values) { + AnnotationReader.writeAnnotationValue(buf, e); + } } } public record OfEnumImpl(Utf8Entry className, Utf8Entry constantName) - implements AnnotationValue.OfEnum { + implements AnnotationValue.OfEnum, Util.Writable { @Override public char tag() { return AEV_ENUM; } @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { buf.writeU1(tag()); buf.writeIndex(className); buf.writeIndex(constantName); @@ -273,29 +280,29 @@ public void writeTo(BufWriter buf) { } public record OfAnnotationImpl(Annotation annotation) - implements AnnotationValue.OfAnnotation { + implements AnnotationValue.OfAnnotation, Util.Writable { @Override public char tag() { return AEV_ANNOTATION; } @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { buf.writeU1(tag()); - annotation.writeTo(buf); + AnnotationReader.writeAnnotation(buf, annotation); } } public record OfClassImpl(Utf8Entry className) - implements AnnotationValue.OfClass { + implements AnnotationValue.OfClass, Util.Writable { @Override public char tag() { return AEV_CLASS; } @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { buf.writeU1(tag()); buf.writeIndex(className); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index 7b5920b3e78..2ada13aaba8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -28,6 +28,7 @@ import java.lang.classfile.Annotation; import java.lang.classfile.AnnotationElement; import java.lang.classfile.AnnotationValue; +import java.lang.classfile.BufWriter; import java.lang.classfile.ClassReader; import java.lang.classfile.constantpool.*; import java.lang.classfile.TypeAnnotation; @@ -39,7 +40,7 @@ import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.access.SharedSecrets; -class AnnotationReader { +public final class AnnotationReader { private AnnotationReader() { } public static List readAnnotations(ClassReader classReader, int p) { @@ -280,4 +281,24 @@ private static int skipTypeAnnotation(ClassReader classReader, int p) { p = skipElementValuePairs(classReader, p); return p; } + + public static void writeAnnotation(BufWriterImpl buf, Annotation annotation) { + // handles annotations and type annotations + // TODO annotation cleanup later + ((Util.Writable) annotation).writeTo(buf); + } + + public static void writeAnnotations(BufWriter buf, List list) { + // handles annotations and type annotations + var internalBuf = (BufWriterImpl) buf; + internalBuf.writeU2(list.size()); + for (var e : list) { + writeAnnotation(internalBuf, e); + } + } + + public static void writeAnnotationValue(BufWriterImpl buf, AnnotationValue value) { + // TODO annotation cleanup later + ((Util.Writable) value).writeTo(buf); + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java index be5176ad1df..ba51474c131 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.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 @@ -29,7 +29,6 @@ import java.lang.classfile.Attribute; import java.lang.classfile.AttributeMapper; -import java.lang.classfile.BufWriter; public class AttributeHolder { private final List> attributes = new ArrayList<>(); @@ -50,10 +49,8 @@ public int size() { return attributes.size(); } - public void writeTo(BufWriter buf) { - buf.writeU2(attributes.size()); - for (Attribute a : attributes) - a.writeTo(buf); + public void writeTo(BufWriterImpl buf) { + Util.writeAttributes(buf, attributes); } boolean isPresent(AttributeMapper am) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java index d6876a82a9c..267c11c5845 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BootstrapMethodEntryImpl.java @@ -28,7 +28,6 @@ import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.BootstrapMethodEntry; -import java.lang.classfile.BufWriter; import java.lang.classfile.constantpool.LoadableConstantEntry; import java.lang.classfile.constantpool.MethodHandleEntry; @@ -87,9 +86,8 @@ public int hashCode() { return hash; } - @Override - public void writeTo(BufWriter writer) { + void writeTo(BufWriterImpl writer) { writer.writeIndex(bootstrapMethod()); - writer.writeListIndices(arguments()); + Util.writeListIndices(writer, arguments()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java index 6a23be54f48..a0428d9d09d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java @@ -48,7 +48,7 @@ public abstract sealed class BoundAttribute> extends AbstractElement - implements Attribute { + implements Attribute, Util.Writable { static final int NAME_AND_LENGTH_PREFIX = 6; private final AttributeMapper mapper; @@ -101,7 +101,7 @@ public void writeTo(DirectFieldBuilder builder) { @Override @SuppressWarnings("unchecked") - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { if (!buf.canWriteDirect(classReader)) attributeMapper().writeAttribute(buf, (T) this); else diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java index 87161588203..ac34d78e0e5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java @@ -27,10 +27,8 @@ import java.nio.ByteBuffer; import java.util.Arrays; -import java.util.List; import java.lang.classfile.BufWriter; -import java.lang.classfile.WritableElement; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.constantpool.ConstantPoolBuilder; @@ -126,10 +124,8 @@ public void writeBytes(byte[] arr) { writeBytes(arr, 0, arr.length); } - @Override - public void writeBytes(BufWriter other) { - BufWriterImpl o = (BufWriterImpl) other; - writeBytes(o.elems, 0, o.offset); + public void writeBytes(BufWriterImpl other) { + writeBytes(other.elems, 0, other.offset); } @Override @@ -175,7 +171,6 @@ public ByteBuffer asByteBuffer() { return ByteBuffer.wrap(elems, 0, offset).slice(); } - @Override public void copyTo(byte[] array, int bufferOffset) { System.arraycopy(elems, 0, array, bufferOffset, size()); } @@ -198,20 +193,4 @@ public void writeIndexOrZero(PoolEntry entry) { else writeIndex(entry); } - - @Override - public> void writeList(List list) { - writeU2(list.size()); - for (T t : list) { - t.writeTo(this); - } - } - - @Override - public void writeListIndices(List list) { - writeU2(list.size()); - for (PoolEntry info : list) { - writeIndex(info); - } - } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java index c3a601fa1df..4743c58607c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java @@ -24,7 +24,6 @@ */ package jdk.internal.classfile.impl; -import java.lang.classfile.BufWriter; import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; @@ -201,7 +200,8 @@ public void accept(CodeBuilder cb) { }); } - public void writeTo(BufWriter buf) { + @Override + public void writeTo(BufWriterImpl buf) { DirectCodeBuilder.build(methodInfo, cb -> elements.forEach(cb), constantPool, context, null).writeTo(buf); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java index a92513390b4..660a999f2a3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java @@ -112,7 +112,7 @@ public void accept(FieldBuilder fieldBuilder) { } @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { DirectFieldBuilder fb = new DirectFieldBuilder(constantPool, context, name, desc, null); elements.forEach(fb); fb.writeTo(buf); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java index f92ee1adf34..880c6717db8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java @@ -33,7 +33,6 @@ import java.lang.classfile.AccessFlags; -import java.lang.classfile.BufWriter; import java.lang.classfile.ClassModel; import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeModel; @@ -211,7 +210,7 @@ public void accept(MethodBuilder mb) { } @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { DirectMethodBuilder mb = new DirectMethodBuilder(constantPool, context, name, desc, methodFlags(), null); elements.forEach(mb); mb.writeTo(buf); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java index 25d4e2e68e8..9695b16ad51 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java @@ -321,12 +321,13 @@ ClassModel getContainedClass() { return containedClass; } - boolean writeBootstrapMethods(BufWriter buf) { + boolean writeBootstrapMethods(BufWriterImpl buf) { Optional a = containedClass.findAttribute(Attributes.bootstrapMethods()); if (a.isEmpty()) return false; - a.get().writeTo(buf); + // BootstrapMethodAttribute implementations are all internal writable + ((Util.Writable) a.get()).writeTo(buf); return true; } @@ -465,13 +466,12 @@ public T readEntryOrNull(int offset, Class cls) { return entryByIndex(index, cls); } - @Override - public boolean compare(BufWriter bufWriter, + public boolean compare(BufWriterImpl bufWriter, int bufWriterOffset, int classReaderOffset, int length) { try { - return Arrays.equals(((BufWriterImpl) bufWriter).elems, + return Arrays.equals(bufWriter.elems, bufWriterOffset, bufWriterOffset + length, buffer, classReaderOffset, classReaderOffset + length); } catch (IndexOutOfBoundsException e) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index 4b2a21072f0..7669cbfdd30 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -141,7 +141,7 @@ public List> attributes() { } @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { if (buf.canWriteDirect(classReader)) { super.writeTo(buf); } @@ -154,7 +154,7 @@ public void accept(CodeBuilder cb) { } }, (SplitConstantPool)buf.constantPool(), - ((BufWriterImpl)buf).context(), + buf.context(), null).writeTo(buf); } } @@ -210,7 +210,7 @@ public void accept(int s, int e, int h, int c) { return exceptionTable; } - public boolean compareCodeBytes(BufWriter buf, int offset, int len) { + public boolean compareCodeBytes(BufWriterImpl buf, int offset, int len) { return codeLength == len && classReader.compare(buf, offset, codeStart, codeLength); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 915c3ad8cf4..21fde0f6002 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.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 @@ -31,7 +31,6 @@ import java.util.List; import java.util.function.Consumer; -import java.lang.classfile.BufWriter; import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassElement; import java.lang.classfile.ClassModel; @@ -44,7 +43,6 @@ import java.lang.classfile.MethodBuilder; import java.lang.classfile.MethodModel; import java.lang.classfile.MethodTransform; -import java.lang.classfile.WritableElement; import java.lang.classfile.constantpool.Utf8Entry; public final class DirectClassBuilder @@ -52,8 +50,8 @@ public final class DirectClassBuilder implements ClassBuilder { final ClassEntry thisClassEntry; - private final List> fields = new ArrayList<>(); - private final List> methods = new ArrayList<>(); + private final List fields = new ArrayList<>(); + private final List methods = new ArrayList<>(); private ClassEntry superclassEntry; private List interfaceEntries; private int majorVersion; @@ -78,7 +76,7 @@ public ClassBuilder with(ClassElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute)element); + writeAttribute((CustomAttribute) element); } return this; } @@ -120,12 +118,12 @@ public ClassBuilder transformMethod(MethodModel method, MethodTransform transfor // internal / for use by elements - public ClassBuilder withField(WritableElement field) { + ClassBuilder withField(Util.Writable field) { fields.add(field); return this; } - public ClassBuilder withMethod(WritableElement method) { + ClassBuilder withMethod(Util.Writable method) { methods.add(method); return this; } @@ -172,13 +170,13 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC // We maintain two writers, and then we join them at the end int size = sizeHint == 0 ? 256 : sizeHint; - BufWriter head = new BufWriterImpl(constantPool, context, size); + BufWriterImpl head = new BufWriterImpl(constantPool, context, size); BufWriterImpl tail = new BufWriterImpl(constantPool, context, size, thisClassEntry, majorVersion); // The tail consists of fields and methods, and attributes // This should trigger all the CP/BSM mutation - tail.writeList(fields); - tail.writeList(methods); + Util.writeList(tail, fields); + Util.writeList(tail, methods); int attributesOffset = tail.size(); attributes.writeTo(tail); @@ -197,7 +195,7 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC head.writeU2(flags); head.writeIndex(thisClassEntry); head.writeIndexOrZero(superclass); - head.writeListIndices(ies); + Util.writeListIndices(head, ies); // Join head and tail into an exact-size buffer byte[] result = new byte[head.size() + tail.size()]; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index 0b6549a82da..536750ebd2f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -24,7 +24,6 @@ */ package jdk.internal.classfile.impl; -import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; @@ -36,20 +35,17 @@ import java.lang.classfile.Attribute; import java.lang.classfile.Attributes; -import java.lang.classfile.BufWriter; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeElement; import java.lang.classfile.CodeModel; import java.lang.classfile.CustomAttribute; -import java.lang.classfile.Instruction; import java.lang.classfile.Label; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; import java.lang.classfile.instruction.SwitchCase; import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.attribute.LineNumberTableAttribute; -import java.lang.classfile.attribute.StackMapTableAttribute; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.DoubleEntry; @@ -83,7 +79,7 @@ public final class DirectCodeBuilder private final boolean transformFwdJumps, transformBackJumps; private final Label startLabel, endLabel; final MethodInfo methodInfo; - final BufWriter bytecodesBufWriter; + final BufWriterImpl bytecodesBufWriter; private CodeAttribute mruParent; private int[] mruParentTable; private Map parentMap; @@ -100,7 +96,7 @@ or model maxLocals (for transformation) allocLocal(TypeKind) bumps by nSlots */ - public static Attribute build(MethodInfo methodInfo, + public static UnboundAttribute build(MethodInfo methodInfo, Consumer handler, SplitConstantPool constantPool, ClassFileImpl context, @@ -144,7 +140,7 @@ public CodeBuilder with(CodeElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute)element); + writeAttribute((CustomAttribute) element); } return this; } @@ -193,9 +189,9 @@ public MethodInfo methodInfo() { return methodInfo; } - private Attribute content = null; + private UnboundAttribute content = null; - private void writeExceptionHandlers(BufWriter buf) { + private void writeExceptionHandlers(BufWriterImpl buf) { int pos = buf.size(); int handlersSize = handlers.size(); buf.writeU2(handlersSize); @@ -233,7 +229,7 @@ private void buildContent() { Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.characterRangeTable()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { int pos = b.size(); int crSize = characterRanges.size(); b.writeU2(crSize); @@ -264,12 +260,12 @@ public void writeBody(BufWriter b) { if (!localVariables.isEmpty()) { Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTable()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { int pos = b.size(); int lvSize = localVariables.size(); b.writeU2(lvSize); for (LocalVariable l : localVariables) { - if (!l.writeTo(b)) { + if (!Util.writeLocalVariable(b, l)) { if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) { lvSize--; } else { @@ -287,12 +283,12 @@ public void writeBody(BufWriter b) { if (!localVariableTypes.isEmpty()) { Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTypeTable()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { int pos = b.size(); int lvtSize = localVariableTypes.size(); b.writeU2(localVariableTypes.size()); for (LocalVariableType l : localVariableTypes) { - if (!l.writeTo(b)) { + if (!Util.writeLocalVariable(b, l)) { if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) { lvtSize--; } else { @@ -352,8 +348,7 @@ private void tryGenerateStackMaps(boolean codeMatch, BufWriterImpl buf) { } @Override - public void writeBody(BufWriter b) { - BufWriterImpl buf = (BufWriterImpl) b; + public void writeBody(BufWriterImpl buf) { buf.setLabelContext(DirectCodeBuilder.this); int codeLength = curPc(); @@ -389,8 +384,8 @@ public void writeBody(BufWriter b) { buf.writeInt(codeLength); buf.writeBytes(bytecodesBufWriter); - writeExceptionHandlers(b); - attributes.writeTo(b); + writeExceptionHandlers(buf); + attributes.writeTo(buf); buf.setLabelContext(null); } }; @@ -427,12 +422,12 @@ public void writeLineNumber(int pc, int lineNo) { } @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { throw new UnsupportedOperationException(); } @Override - public void writeTo(BufWriter b) { + public void writeTo(BufWriterImpl b) { b.writeIndex(b.constantPool().utf8Entry(Attributes.NAME_LINE_NUMBER_TABLE)); push(); b.writeInt(buf.size() + 2); @@ -447,7 +442,7 @@ private boolean codeAndExceptionsMatch(int codeLength) { codeAttributesMatch = cai.codeLength == curPc() && cai.compareCodeBytes(bytecodesBufWriter, 0, codeLength); if (codeAttributesMatch) { - BufWriter bw = new BufWriterImpl(constantPool, context); + var bw = new BufWriterImpl(constantPool, context); writeExceptionHandlers(bw); codeAttributesMatch = cai.classReader.compare(bw, 0, cai.exceptionHandlerPos, bw.size()); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java index 7bdab531e44..ce51bb1d26b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectFieldBuilder.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 @@ -27,17 +27,15 @@ import java.util.function.Consumer; -import java.lang.classfile.BufWriter; import java.lang.classfile.CustomAttribute; import java.lang.classfile.FieldBuilder; import java.lang.classfile.FieldElement; import java.lang.classfile.FieldModel; -import java.lang.classfile.WritableElement; import java.lang.classfile.constantpool.Utf8Entry; public final class DirectFieldBuilder extends AbstractDirectBuilder - implements TerminalFieldBuilder, WritableElement { + implements TerminalFieldBuilder, Util.Writable { private final Utf8Entry name; private final Utf8Entry desc; private int flags; @@ -59,7 +57,7 @@ public FieldBuilder with(FieldElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute)element); + writeAttribute((CustomAttribute) element); } return this; } @@ -74,7 +72,7 @@ void setFlags(int flags) { } @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { buf.writeU2(flags); buf.writeIndex(name); buf.writeIndex(desc); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java index a4b3bbe1b84..f79eb0af0cb 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectMethodBuilder.java @@ -28,7 +28,6 @@ import java.lang.constant.MethodTypeDesc; import java.util.function.Consumer; -import java.lang.classfile.BufWriter; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeModel; @@ -37,12 +36,11 @@ import java.lang.classfile.MethodBuilder; import java.lang.classfile.MethodElement; import java.lang.classfile.MethodModel; -import java.lang.classfile.WritableElement; import java.lang.classfile.constantpool.Utf8Entry; public final class DirectMethodBuilder extends AbstractDirectBuilder - implements TerminalMethodBuilder, WritableElement { + implements TerminalMethodBuilder, Util.Writable { final Utf8Entry name; final Utf8Entry desc; @@ -115,7 +113,7 @@ public MethodBuilder with(MethodElement element) { if (element instanceof AbstractElement ae) { ae.writeTo(this); } else { - writeAttribute((CustomAttribute)element); + writeAttribute((CustomAttribute) element); } return this; } @@ -148,8 +146,7 @@ public DirectMethodBuilder run(Consumer handler) { } @Override - public void writeTo(BufWriter b) { - BufWriterImpl buf = (BufWriterImpl) b; + public void writeTo(BufWriterImpl buf) { buf.writeU2(flags); buf.writeIndex(name); buf.writeIndex(desc); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java index ba424c862fd..ab42b96084a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java @@ -33,7 +33,7 @@ public final class FieldImpl extends AbstractElement - implements FieldModel { + implements FieldModel, Util.Writable { private final ClassReader reader; private final int startPos, endPos, attributesPos; @@ -78,7 +78,7 @@ public List> attributes() { } @Override - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { if (buf.canWriteDirect(reader)) { reader.copyBytesTo(buf, startPos, endPos - startPos); } @@ -86,7 +86,7 @@ public void writeTo(BufWriter buf) { buf.writeU2(flags().flagsMask()); buf.writeIndex(fieldName()); buf.writeIndex(fieldType()); - buf.writeList(attributes()); + Util.writeAttributes(buf, attributes()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java index 62a83dffc6e..40223d58d6b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java @@ -34,7 +34,7 @@ public final class MethodImpl extends AbstractElement - implements MethodModel, MethodInfo { + implements MethodModel, MethodInfo, Util.Writable { private final ClassReader reader; private final int startPos, endPos, attributesPos; @@ -101,8 +101,7 @@ public List> attributes() { } @Override - public void writeTo(BufWriter b) { - BufWriterImpl buf = (BufWriterImpl) b; + public void writeTo(BufWriterImpl buf) { if (buf.canWriteDirect(reader)) { reader.copyBytesTo(buf, startPos, endPos - startPos); } @@ -110,7 +109,7 @@ public void writeTo(BufWriter b) { buf.writeU2(flags().flagsMask()); buf.writeIndex(methodName()); buf.writeIndex(methodType()); - buf.writeList(attributes()); + Util.writeAttributes(buf, attributes()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index 6c5a8a266c0..f7905712b18 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -29,12 +29,10 @@ import java.util.Arrays; import java.util.List; -import java.lang.classfile.Attribute; import java.lang.classfile.Attributes; import java.lang.classfile.ClassReader; import java.lang.classfile.ClassFile; import java.lang.classfile.BootstrapMethodEntry; -import java.lang.classfile.BufWriter; import java.lang.classfile.attribute.BootstrapMethodsAttribute; import java.lang.classfile.constantpool.*; import java.util.Objects; @@ -135,7 +133,7 @@ public boolean canWriteDirect(ConstantPool other) { return this == other || parent == other; } - public boolean writeBootstrapMethods(BufWriter buf) { + public boolean writeBootstrapMethods(BufWriterImpl buf) { if (bsmSize == 0) return false; int pos = buf.size(); @@ -148,11 +146,11 @@ public boolean writeBootstrapMethods(BufWriter buf) { buf.patchInt(pos + 6, 2, bsmSize); } else { - Attribute a + UnboundAttribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.bootstrapMethods()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { buf.writeU2(bsmSize); for (int i = 0; i < bsmSize; i++) bootstrapMethodEntry(i).writeTo(buf); @@ -163,8 +161,7 @@ public void writeBody(BufWriter b) { return true; } - @Override - public void writeTo(BufWriter buf) { + void writeTo(BufWriterImpl buf) { int writeFrom = 1; if (size() >= 65536) { throw new IllegalArgumentException(String.format("Constant pool is too large %d", size())); @@ -175,7 +172,7 @@ public void writeTo(BufWriter buf) { writeFrom = parent.size(); } for (int i = writeFrom; i < size(); ) { - PoolEntry info = entryByIndex(i); + var info = (AbstractPoolEntry) entryByIndex(i); info.writeTo(buf); i += info.width(); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java index 899a43571a3..876cb201b79 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java @@ -51,7 +51,7 @@ static StackCounter of(DirectCodeBuilder dcb, BufWriterImpl buf) { dcb.methodInfo.methodName().stringValue(), dcb.methodInfo.methodTypeSymbol(), (dcb.methodInfo.methodFlags() & ACC_STATIC) != 0, - ((BufWriterImpl) dcb.bytecodesBufWriter).asByteBuffer(), + dcb.bytecodesBufWriter.asByteBuffer(), dcb.constantPool, dcb.handlers); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 5b103a21f8a..514c1d32f41 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -152,7 +152,7 @@ static StackMapGenerator of(DirectCodeBuilder dcb, BufWriterImpl buf) { dcb.methodInfo.methodName().stringValue(), dcb.methodInfo.methodTypeSymbol(), (dcb.methodInfo.methodFlags() & ACC_STATIC) != 0, - ((BufWriterImpl) dcb.bytecodesBufWriter).asByteBuffer(), + dcb.bytecodesBufWriter.asByteBuffer(), dcb.constantPool, dcb.context, dcb.handlers); @@ -383,7 +383,7 @@ private void removeRangeFromExcTable(int rangeStart, int rangeEnd) { public Attribute stackMapTableAttribute() { return frames.isEmpty() ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { b.writeU2(frames.size()); Frame prevFrame = new Frame(classHierarchy); prevFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java index e5f7d9cca79..784e844b712 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TemporaryConstantPool.java @@ -189,9 +189,4 @@ public int bootstrapMethodCount() { public boolean canWriteDirect(ConstantPool constantPool) { return false; } - - @Override - public void writeTo(BufWriter buf) { - throw new UnsupportedOperationException(); - } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 70b58e423f6..6d71497f693 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.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 @@ -35,7 +35,6 @@ import java.lang.classfile.AttributeMapper; import java.lang.classfile.Attributes; import java.lang.classfile.BootstrapMethodEntry; -import java.lang.classfile.BufWriter; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.Label; import java.lang.classfile.TypeAnnotation; @@ -95,7 +94,7 @@ public abstract sealed class UnboundAttribute> extends AbstractElement - implements Attribute { + implements Attribute, Util.Writable { protected final AttributeMapper mapper; public UnboundAttribute(AttributeMapper mapper) { @@ -114,7 +113,7 @@ public String attributeName() { @Override @SuppressWarnings("unchecked") - public void writeTo(BufWriter buf) { + public void writeTo(BufWriterImpl buf) { mapper.writeAttribute(buf, (T) this); } @@ -752,7 +751,7 @@ public UnboundRecordComponentInfo(Utf8Entry name, Utf8Entry descriptor, List targetPath, Utf8Entry className, - List elements) implements TypeAnnotation { + List elements) implements TypeAnnotation, Util.Writable { public UnboundTypeAnnotation(TargetInfo targetInfo, List targetPath, Utf8Entry className, List elements) { @@ -769,8 +768,8 @@ private int labelToBci(LabelContext lr, Label label) { } @Override - public void writeTo(BufWriter buf) { - LabelContext lr = ((BufWriterImpl) buf).labelContext(); + public void writeTo(BufWriterImpl buf) { + LabelContext lr = buf.labelContext(); // target_type buf.writeU1(targetInfo.targetType().targetTypeValue()); @@ -818,7 +817,7 @@ public void writeTo(BufWriter buf) { buf.writeU2(elements.size()); for (AnnotationElement pair : elements()) { buf.writeIndex(pair.name()); - pair.value().writeTo(buf); + AnnotationReader.writeAnnotationValue(buf, pair.value()); } } } @@ -904,10 +903,10 @@ public AdHocAttribute(AttributeMapper mapper) { super(mapper); } - public abstract void writeBody(BufWriter b); + public abstract void writeBody(BufWriterImpl b); @Override - public void writeTo(BufWriter b) { + public void writeTo(BufWriterImpl b) { b.writeIndex(b.constantPool().utf8Entry(mapper.name())); b.writeInt(0); int start = b.size(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 0e969272c40..079ac9551ab 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -24,6 +24,9 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.CustomAttribute; +import java.lang.classfile.PseudoInstruction; +import java.lang.classfile.constantpool.PoolEntry; import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; import java.util.AbstractList; @@ -47,7 +50,6 @@ import static java.lang.classfile.ClassFile.ACC_STATIC; import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.components.ClassPrinter; -import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.nio.ByteBuffer; import java.util.function.Consumer; @@ -188,6 +190,31 @@ public static MethodTypeDesc methodTypeSymbol(NameAndTypeEntry nat) { return ((AbstractPoolEntry.NameAndTypeEntryImpl)nat).methodTypeSymbol(); } + @SuppressWarnings("unchecked") + private static void writeAttribute(BufWriterImpl writer, Attribute attr) { + if (attr instanceof CustomAttribute ca) { + var mapper = (AttributeMapper) ca.attributeMapper(); + mapper.writeAttribute(writer, (T) ca); + } else { + assert attr instanceof BoundAttribute || attr instanceof UnboundAttribute; + ((Writable) attr).writeTo(writer); + } + } + + public static void writeAttributes(BufWriterImpl buf, List> list) { + buf.writeU2(list.size()); + for (var e : list) { + writeAttribute(buf, e); + } + } + + static void writeList(BufWriterImpl buf, List list) { + buf.writeU2(list.size()); + for (var e : list) { + e.writeTo(buf); + } + } + public static int slotSize(ClassDesc desc) { return switch (desc.descriptorString().charAt(0)) { case 'V' -> 0; @@ -216,7 +243,7 @@ public static void dumpMethod(SplitConstantPool cp, clb.withMethod(methodName, methodDesc, acc, mb -> ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { b.writeU2(-1);//max stack b.writeU2(-1);//max locals b.writeInt(bytecode.limit()); @@ -237,4 +264,28 @@ public void writeBody(BufWriter b) { } } } + + public static void writeListIndices(BufWriter writer, List list) { + writer.writeU2(list.size()); + for (PoolEntry info : list) { + writer.writeIndex(info); + } + } + + public static boolean writeLocalVariable(BufWriterImpl buf, PseudoInstruction lvOrLvt) { + return ((WritableLocalVariable) lvOrLvt).writeLocalTo(buf); + } + + /** + * A generic interface for objects to write to a + * buf writer. Do not implement unless necessary, + * as this writeTo is public, which can be troublesome. + */ + interface Writable { + void writeTo(BufWriterImpl writer); + } + + interface WritableLocalVariable { + boolean writeLocalTo(BufWriterImpl buf); + } } diff --git a/test/jdk/jdk/classfile/BoundAttributeTest.java b/test/jdk/jdk/classfile/BoundAttributeTest.java index f6d2d0e9010..6a164bec2f9 100644 --- a/test/jdk/jdk/classfile/BoundAttributeTest.java +++ b/test/jdk/jdk/classfile/BoundAttributeTest.java @@ -27,6 +27,7 @@ * @summary Testing BoundAttributes * @run junit BoundAttributeTest */ +import jdk.internal.classfile.impl.BufWriterImpl; import jdk.internal.classfile.impl.DirectClassBuilder; import jdk.internal.classfile.impl.UnboundAttribute; import org.junit.jupiter.api.Assertions; @@ -34,7 +35,6 @@ import org.opentest4j.AssertionFailedError; import java.lang.classfile.Attributes; -import java.lang.classfile.BufWriter; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; @@ -84,7 +84,7 @@ void testBadEntryTypeInList() { var oneClass = cp.classEntry(oneClassString); ((DirectClassBuilder) clb).writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.nestMembers()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { b.writeU2(2); b.writeIndex(oneClass); b.writeIndex(oneClassString); diff --git a/test/jdk/jdk/classfile/CorpusTest.java b/test/jdk/jdk/classfile/CorpusTest.java index 2dfbef10d67..a2af1667978 100644 --- a/test/jdk/jdk/classfile/CorpusTest.java +++ b/test/jdk/jdk/classfile/CorpusTest.java @@ -31,6 +31,8 @@ import helpers.ClassRecord; import helpers.ClassRecord.CompatibilityFilter; import helpers.Transforms; +import jdk.internal.classfile.impl.BufWriterImpl; +import jdk.internal.classfile.impl.Util; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.api.parallel.Execution; @@ -85,7 +87,7 @@ static void splitTableAttributes(String sourceClassFile, String targetClassFile) switch (coe) { case LineNumber ln -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.lineNumberTable()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { b.writeU2(1); b.writeU2(curPc); b.writeU2(ln.line()); @@ -93,16 +95,16 @@ public void writeBody(BufWriter b) { }); case LocalVariable lv -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTable()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { b.writeU2(1); - lv.writeTo(b); + Util.writeLocalVariable(b, lv); } }); case LocalVariableType lvt -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTypeTable()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { b.writeU2(1); - lvt.writeTo(b); + Util.writeLocalVariable(b, lvt); } }); default -> cob.with(coe); diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index b1914e6d024..9c7b8d9e72d 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -28,7 +28,6 @@ * @run junit LimitsTest */ import java.lang.classfile.Attributes; -import java.lang.classfile.BufWriter; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; @@ -44,6 +43,8 @@ import java.lang.classfile.constantpool.IntegerEntry; import java.lang.classfile.instruction.LocalVariable; import java.util.List; + +import jdk.internal.classfile.impl.BufWriterImpl; import jdk.internal.classfile.impl.DirectCodeBuilder; import jdk.internal.classfile.impl.DirectMethodBuilder; import jdk.internal.classfile.impl.LabelContext; @@ -130,7 +131,7 @@ void testInvalidLookupSwitch() { "lookupSwitchMethod", MethodTypeDesc.of(ConstantDescs.CD_void), 0, mb -> ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { b.writeU2(-1);//max stack b.writeU2(-1);//max locals b.writeInt(16); @@ -155,7 +156,7 @@ void testInvalidTableSwitch() { "tableSwitchMethod", MethodTypeDesc.of(ConstantDescs.CD_void), 0, mb -> ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { b.writeU2(-1);//max stack b.writeU2(-1);//max locals b.writeInt(16); @@ -173,7 +174,7 @@ public void writeBody(BufWriter b) { "tableSwitchMethod", MethodTypeDesc.of(ConstantDescs.CD_void), 0, mb -> ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { b.writeU2(-1);//max stack b.writeU2(-1);//max locals b.writeInt(20); diff --git a/test/jdk/jdk/classfile/LowAdaptTest.java b/test/jdk/jdk/classfile/LowAdaptTest.java index 46d033a8676..9fa2620913b 100644 --- a/test/jdk/jdk/classfile/LowAdaptTest.java +++ b/test/jdk/jdk/classfile/LowAdaptTest.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 @@ -39,11 +39,8 @@ import java.lang.reflect.AccessFlag; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; -import java.lang.classfile.Opcode; -import java.lang.classfile.TypeKind; import helpers.ByteArrayClassLoader; import java.lang.classfile.attribute.SourceFileAttribute; -import jdk.internal.classfile.impl.DirectClassBuilder; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -75,7 +72,7 @@ void testAdapt() throws Exception { byte[] clazz = cc.build(ClassDesc.of(test), cb -> { cb.withFlags(AccessFlag.PUBLIC); cb.with(SourceFileAttribute.of("/some/madeup/TestClass.java")); - cl.methods().forEach(m -> ((DirectClassBuilder) cb).withMethod(m)); + cl.methods().forEach(cb::with); cb.withMethod("doit", MethodTypeDesc.of(CD_int, CD_int), AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), diff --git a/test/jdk/jdk/classfile/VerifierSelfTest.java b/test/jdk/jdk/classfile/VerifierSelfTest.java index 84a5ded1610..d0943d2eee9 100644 --- a/test/jdk/jdk/classfile/VerifierSelfTest.java +++ b/test/jdk/jdk/classfile/VerifierSelfTest.java @@ -47,6 +47,8 @@ import java.lang.classfile.attribute.*; import java.lang.classfile.components.ClassPrinter; import java.lang.constant.ModuleDesc; + +import jdk.internal.classfile.impl.BufWriterImpl; import jdk.internal.classfile.impl.DirectClassBuilder; import jdk.internal.classfile.impl.UnboundAttribute; import org.junit.jupiter.api.Test; @@ -103,7 +105,7 @@ void testInvalidAttrLocation() { var bytes = cc.build(ClassDesc.of("InvalidAttrLocationClass"), cb -> ((DirectClassBuilder)cb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.localVariableTable()) { @Override - public void writeBody(BufWriter b) { + public void writeBody(BufWriterImpl b) { b.writeU2(0); } })); diff --git a/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java b/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java index a5598d1f242..d85b37aa3a3 100644 --- a/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java +++ b/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -70,8 +70,8 @@ private TestElementValue get(int tag) { private abstract class TestElementValue { public void testLength(TestResult testCase, AnnotationDefaultAttribute attr) { - BufWriter buf = new BufWriterImpl(ConstantPoolBuilder.of(), (ClassFileImpl) ClassFile.of()); - attr.defaultValue().writeTo(buf); + var buf = new BufWriterImpl(ConstantPoolBuilder.of(), (ClassFileImpl) ClassFile.of()); + AnnotationReader.writeAnnotationValue(buf, attr.defaultValue()); testCase.checkEquals(((BoundAttribute)attr).payloadLen(), buf.size(), "attribute_length"); } From cae7d160b430c588e0dede510ebd83789508ce84 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Tue, 23 Jul 2024 12:22:53 +0000 Subject: [PATCH 06/10] 8204582: Extra spaces in jlink documentation make it incorrect. Reviewed-by: alanb --- src/jdk.jlink/share/man/jlink.1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jdk.jlink/share/man/jlink.1 b/src/jdk.jlink/share/man/jlink.1 index 9f4bf38ffa5..5cadc153a37 100644 --- a/src/jdk.jlink/share/man/jlink.1 +++ b/src/jdk.jlink/share/man/jlink.1 @@ -44,8 +44,8 @@ into a custom runtime image .SH SYNOPSIS .PP \f[V]jlink\f[R] [\f[I]options\f[R]] \f[V]--module-path\f[R] -\f[I]modulepath\f[R] \f[V]--add-modules\f[R] \f[I]module\f[R] [, -\f[I]module\f[R]...] +\f[I]modulepath\f[R] \f[V]--add-modules\f[R] +\f[I]module\f[R][,\f[I]module\f[R]...] .TP \f[I]options\f[R] Command-line options separated by spaces. @@ -69,7 +69,7 @@ transitive dependences, to create a custom runtime image. Developers are responsible for updating their custom runtime images. .SH JLINK OPTIONS .TP -\f[V]--add-modules\f[R] \f[I]mod\f[R] [\f[V],\f[R] \f[I]mod\f[R]...] +\f[V]--add-modules\f[R] \f[I]mod\f[R][\f[V],\f[R]\f[I]mod\f[R]...] Adds the named modules, \f[I]mod\f[R], to the default set of root modules. The default set of root modules is empty. @@ -110,7 +110,7 @@ Specifies the launcher command name for the module or the command name for the module and main class (the module and the main class names are separated by a slash (\f[V]/\f[R])). .TP -\f[V]--limit-modules\f[R] \f[I]mod\f[R] [\f[V],\f[R] \f[I]mod\f[R]...] +\f[V]--limit-modules\f[R] \f[I]mod\f[R][\f[V],\f[R]\f[I]mod\f[R]...] Limits the universe of observable modules to those in the transitive closure of the named modules, \f[V]mod\f[R], plus the main module, if any, plus any further modules specified in the \f[V]--add-modules\f[R] From d686b777f30400bc4411a92991941734a3d18d83 Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Tue, 23 Jul 2024 15:49:34 +0000 Subject: [PATCH 07/10] 8327054: DiagnosticCommand Compiler.perfmap does not log on output() Reviewed-by: lmesnik, stuefe, kevinw, cjplummer --- .../serviceability/dcmd/compiler/PerfMapTest.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java b/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java index 6bbe62044d0..7a72efd68ba 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2023, Arm Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -113,4 +113,16 @@ public void specifiedDefaultMapFile() throws IOException { run(new JMXExecutor(), "Compiler.perfmap " + path.toString(), path); Files.deleteIfExists(path); } + + @Test + public void logErrorsDcmdOutputStream() throws IOException { + String test_dir = System.getProperty("test.dir", "."); + Path path = Paths.get("nonexistent", test_dir); + try { + OutputAnalyzer output = new JMXExecutor().execute("Compiler.perfmap %s".formatted(path)); + output.shouldContain("Warning: Failed to create nonexistent/%s for perf map".formatted(test_dir)); + } finally { + Files.deleteIfExists(path); + } + } } From 1c20e85564fbdb5045634cb59573e80f02653c27 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 23 Jul 2024 16:27:09 +0000 Subject: [PATCH 08/10] 8335823: Update --release 23 symbol information for JDK 23 build 33 Reviewed-by: iris, liach --- .../share/data/symbols/java.base-N.sym.txt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/jdk.compiler/share/data/symbols/java.base-N.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-N.sym.txt index 8fab1f56765..fd1bd11f6b9 100644 --- a/src/jdk.compiler/share/data/symbols/java.base-N.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.base-N.sym.txt @@ -707,6 +707,7 @@ innerclass innerClass jdk/internal/classfile/impl/AbstractPoolEntry$ClassEntryIm innerclass innerClass jdk/internal/classfile/impl/AbstractPoolEntry$AbstractNamedEntry outerClass jdk/internal/classfile/impl/AbstractPoolEntry innerClassName AbstractNamedEntry flags 408 innerclass innerClass jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefsEntry outerClass jdk/internal/classfile/impl/AbstractPoolEntry innerClassName AbstractRefsEntry flags 408 innerclass innerClass jdk/internal/classfile/impl/AbstractPoolEntry$AbstractRefEntry outerClass jdk/internal/classfile/impl/AbstractPoolEntry innerClassName AbstractRefEntry flags 408 +-method name phiMix descriptor (I)I class name jdk/internal/classfile/impl/AbstractPoolEntry$AbstractDynamicConstantPoolEntry header extends jdk/internal/classfile/impl/AbstractPoolEntry nestHost jdk/internal/classfile/impl/AbstractPoolEntry sealed true permittedSubclasses jdk/internal/classfile/impl/AbstractPoolEntry$InvokeDynamicEntryImpl,jdk/internal/classfile/impl/AbstractPoolEntry$ConstantDynamicEntryImpl flags 421 @@ -799,6 +800,10 @@ innerclass innerClass jdk/internal/classfile/impl/BoundAttribute$BoundSyntheticA innerclass innerClass jdk/internal/classfile/impl/BoundAttribute$BoundStackMapTableAttribute outerClass jdk/internal/classfile/impl/BoundAttribute innerClassName BoundStackMapTableAttribute flags 19 method name standardAttribute descriptor (Ljava/lang/classfile/constantpool/Utf8Entry;)Ljava/lang/classfile/AttributeMapper; flags 9 signature (Ljava/lang/classfile/constantpool/Utf8Entry;)Ljava/lang/classfile/AttributeMapper<*>; +class name jdk/internal/classfile/impl/BufferedCodeBuilder +header extends java/lang/Object implements jdk/internal/classfile/impl/TerminalCodeBuilder nestMembers jdk/internal/classfile/impl/BufferedCodeBuilder$Model flags 31 +innerclass innerClass jdk/internal/classfile/impl/BufferedCodeBuilder$Model outerClass jdk/internal/classfile/impl/BufferedCodeBuilder innerClassName Model flags 11 + class name jdk/internal/classfile/impl/ClassPrinterImpl header extends java/lang/Object nestMembers jdk/internal/classfile/impl/ClassPrinterImpl$MapNodeImpl,jdk/internal/classfile/impl/ClassPrinterImpl$MapNodeImpl$PrivateListNodeImpl,jdk/internal/classfile/impl/ClassPrinterImpl$ListNodeImpl,jdk/internal/classfile/impl/ClassPrinterImpl$LeafNodeImpl flags 31 innerclass innerClass jdk/internal/classfile/impl/ClassPrinterImpl$LeafNodeImpl outerClass jdk/internal/classfile/impl/ClassPrinterImpl innerClassName LeafNodeImpl flags 19 @@ -914,6 +919,16 @@ innerclass innerClass java/lang/classfile/ClassFileTransform$ResolvedTransform o innerclass innerClass java/lang/classfile/Signature$ThrowableSig outerClass java/lang/classfile/Signature innerClassName ThrowableSig flags 609 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +class name jdk/internal/classfile/impl/DirectCodeBuilder +header extends jdk/internal/classfile/impl/AbstractDirectBuilder implements jdk/internal/classfile/impl/TerminalCodeBuilder flags 31 signature Ljdk/internal/classfile/impl/AbstractDirectBuilder;Ljdk/internal/classfile/impl/TerminalCodeBuilder; +innerclass innerClass java/lang/classfile/ClassFile$ShortJumpsOption outerClass java/lang/classfile/ClassFile innerClassName ShortJumpsOption flags 4019 +innerclass innerClass jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl outerClass jdk/internal/classfile/impl/AbstractPseudoInstruction innerClassName ExceptionCatchImpl flags 19 +innerclass innerClass java/lang/classfile/ClassFile$DeadLabelsOption outerClass java/lang/classfile/ClassFile innerClassName DeadLabelsOption flags 4019 +innerclass innerClass java/lang/classfile/ClassFile$DebugElementsOption outerClass java/lang/classfile/ClassFile innerClassName DebugElementsOption flags 4019 + +class name jdk/internal/classfile/impl/LabelContext +header extends java/lang/Object sealed true permittedSubclasses jdk/internal/classfile/impl/TerminalCodeBuilder,jdk/internal/classfile/impl/CodeImpl flags 601 + class name jdk/internal/classfile/impl/SignaturesImpl header extends java/lang/Object nestMembers jdk/internal/classfile/impl/SignaturesImpl$MethodSignatureImpl,jdk/internal/classfile/impl/SignaturesImpl$ClassSignatureImpl,jdk/internal/classfile/impl/SignaturesImpl$TypeParamImpl,jdk/internal/classfile/impl/SignaturesImpl$TypeArgImpl,jdk/internal/classfile/impl/SignaturesImpl$UnboundedTypeArgImpl,jdk/internal/classfile/impl/SignaturesImpl$ClassTypeSigImpl,jdk/internal/classfile/impl/SignaturesImpl$ArrayTypeSigImpl,jdk/internal/classfile/impl/SignaturesImpl$TypeVarSigImpl,jdk/internal/classfile/impl/SignaturesImpl$BaseTypeSigImpl flags 31 innerclass innerClass java/lang/classfile/Signature$ClassTypeSig outerClass java/lang/classfile/Signature innerClassName ClassTypeSig flags 609 @@ -1017,6 +1032,12 @@ method name hashCode descriptor ()I flags 1 class name jdk/internal/classfile/impl/TemporaryConstantPool method name entryByIndex descriptor (ILjava/lang/Class;)Ljava/lang/classfile/constantpool/PoolEntry; flags 1 signature (ILjava/lang/Class;)TT; +class name jdk/internal/classfile/impl/TerminalCodeBuilder +header extends java/lang/Object implements java/lang/classfile/CodeBuilder,jdk/internal/classfile/impl/LabelContext sealed true permittedSubclasses jdk/internal/classfile/impl/DirectCodeBuilder,jdk/internal/classfile/impl/BufferedCodeBuilder flags 601 +method name curTopLocal descriptor ()I flags 401 + +-class name jdk/internal/classfile/impl/TransformingCodeBuilder + class name jdk/internal/classfile/impl/UnboundAttribute header extends jdk/internal/classfile/impl/AbstractElement implements java/lang/classfile/Attribute nestMembers jdk/internal/classfile/impl/UnboundAttribute$EmptyBootstrapAttribute,jdk/internal/classfile/impl/UnboundAttribute$AdHocAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleAttribute,jdk/internal/classfile/impl/UnboundAttribute$TypePathComponentImpl,jdk/internal/classfile/impl/UnboundAttribute$UnboundTypeAnnotation,jdk/internal/classfile/impl/UnboundAttribute$UnboundRecordComponentInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleRequiresInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleProvideInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleOpenInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleHashInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleExportInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundMethodParameterInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableTypeInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundLineNumberInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundInnerClassInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundCharacterRangeInfo,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleTypeAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleTypeAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleParameterAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleParameterAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableTypeTableAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableTableAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundLineNumberTableAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundCharacterRangeTableAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceDebugExtensionAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceIDAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundCompilationIDAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundNestHostAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundNestMembersAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundPermittedSubclassesAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleResolutionAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModulePackagesAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleHashesAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleMainClassAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleTargetAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundMethodParametersAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundEnclosingMethodAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRecordAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundInnerClassesAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundStackMapTableAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceFileAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundAnnotationDefaultAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundExceptionsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundSignatureAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundSyntheticAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundDeprecatedAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundConstantValueAttribute sealed true permittedSubclasses jdk/internal/classfile/impl/UnboundAttribute$UnboundConstantValueAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundDeprecatedAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundSyntheticAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundSignatureAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundExceptionsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundAnnotationDefaultAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceFileAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundStackMapTableAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundInnerClassesAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRecordAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundEnclosingMethodAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundMethodParametersAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleTargetAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleMainClassAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleHashesAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModulePackagesAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleResolutionAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundPermittedSubclassesAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundNestMembersAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundNestHostAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundCompilationIDAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceIDAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundSourceDebugExtensionAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundCharacterRangeTableAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundLineNumberTableAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableTableAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundLocalVariableTypeTableAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleParameterAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleParameterAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeVisibleTypeAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundRuntimeInvisibleTypeAnnotationsAttribute,jdk/internal/classfile/impl/UnboundAttribute$UnboundModuleAttribute,jdk/internal/classfile/impl/UnboundAttribute$AdHocAttribute,jdk/internal/classfile/impl/UnboundAttribute$EmptyBootstrapAttribute flags 421 signature ;>Ljdk/internal/classfile/impl/AbstractElement;Ljava/lang/classfile/Attribute; innerclass innerClass jdk/internal/classfile/impl/UnboundAttribute$EmptyBootstrapAttribute outerClass jdk/internal/classfile/impl/UnboundAttribute innerClassName EmptyBootstrapAttribute flags 19 From e40128d0c95b025b87b4366966b0667067cd26fa Mon Sep 17 00:00:00 2001 From: Ben Perez Date: Tue, 23 Jul 2024 19:35:11 +0000 Subject: [PATCH 09/10] 8322133: getParameterSpec(ECGenParameterSpec.class) on EC AlgorithmParameters does not return standard names Reviewed-by: mullan --- .../sun/security/util/ECParameters.java | 5 +- .../EC/CurveGetParameterSpec.java | 47 +++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 test/jdk/com/sun/crypto/provider/AlgorithmParameters/EC/CurveGetParameterSpec.java diff --git a/src/java.base/share/classes/sun/security/util/ECParameters.java b/src/java.base/share/classes/sun/security/util/ECParameters.java index 429b022cc1b..79b38ead6fa 100644 --- a/src/java.base/share/classes/sun/security/util/ECParameters.java +++ b/src/java.base/share/classes/sun/security/util/ECParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -203,8 +203,7 @@ protected void engineInit(byte[] params, String decodingMethod) } if (spec.isAssignableFrom(ECGenParameterSpec.class)) { - // Ensure the name is the Object ID - String name = namedCurve.getObjectId(); + String name = namedCurve.getNameAndAliases()[0]; return spec.cast(new ECGenParameterSpec(name)); } diff --git a/test/jdk/com/sun/crypto/provider/AlgorithmParameters/EC/CurveGetParameterSpec.java b/test/jdk/com/sun/crypto/provider/AlgorithmParameters/EC/CurveGetParameterSpec.java new file mode 100644 index 00000000000..ba4d64c2902 --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/AlgorithmParameters/EC/CurveGetParameterSpec.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8322133 + * @summary Make sure getParameterSpec returns std name for EC AlgorithmParameters + * @modules java.base/sun.security.util + */ + +import java.security.AlgorithmParameters; +import java.security.KeyPairGenerator; +import java.security.spec.ECGenParameterSpec; + +public class CurveGetParameterSpec { + public static void main(String[] args) throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); + kpg.initialize(new ECGenParameterSpec("secp384r1")); + var k = kpg.generateKeyPair().getPublic(); + var a = AlgorithmParameters.getInstance("EC"); + a.init(k.getParams()); + String name = a.getParameterSpec(ECGenParameterSpec.class).getName(); + if (!name.equals("secp384r1")) { + throw new Exception("EC getParameterSpec does not return std name secp384r1. Instead returns: " + name); + } + } +} From 285c7e87b4e3c999409496c070e132e7a1ed1a7a Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Tue, 23 Jul 2024 20:21:08 +0000 Subject: [PATCH 10/10] 8336831: Optimize StringConcatHelper.simpleConcat Reviewed-by: liach, redestad, rriggs --- .../share/classes/java/lang/String.java | 2 +- .../classes/java/lang/StringConcatHelper.java | 47 +++++++++++++------ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 68c16c93e4b..3d8481be1c3 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -2987,7 +2987,7 @@ public String concat(String str) { if (str.isEmpty()) { return this; } - return StringConcatHelper.simpleConcat(this, str); + return StringConcatHelper.doConcat(this, str); } /** diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index e47e124ed4d..bcd9c65890f 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -321,15 +321,24 @@ static String simpleConcat(Object first, Object second) { // newly created string required, see JLS 15.18.1 return new String(s1); } - // start "mixing" in length and coder or arguments, order is not - // important - long indexCoder = mix(initialCoder(), s1); - indexCoder = mix(indexCoder, s2); - byte[] buf = newArray(indexCoder); - // prepend each argument in reverse order, since we prepending - // from the end of the byte array - indexCoder = prepend(indexCoder, buf, s2, s1); - return newString(buf, indexCoder); + return doConcat(s1, s2); + } + + /** + * Perform a simple concatenation between two non-empty strings. + * + * @param s1 first argument + * @param s2 second argument + * @return String resulting string + */ + @ForceInline + static String doConcat(String s1, String s2) { + byte coder = (byte) (s1.coder() | s2.coder()); + int newLength = (s1.length() + s2.length()) << coder; + byte[] buf = newArray(newLength); + s1.getBytes(buf, 0, coder); + s2.getBytes(buf, s1.length(), coder); + return new String(buf, coder); } /** @@ -395,14 +404,22 @@ static byte[] newArrayWithSuffix(String suffix, long indexCoder) { */ @ForceInline static byte[] newArray(long indexCoder) { - int index = (int)indexCoder; - if (indexCoder >= UTF16) { - index <<= 1; - } - if (index < 0) { + byte coder = (byte)(indexCoder >> 32); + int index = ((int)indexCoder) << coder; + return newArray(index); + } + + /** + * Allocates an uninitialized byte array based on the length + * @param length + * @return the newly allocated byte array + */ + @ForceInline + static byte[] newArray(int length) { + if (length < 0) { throw new OutOfMemoryError("Overflow: String length out of range"); } - return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index); + return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, length); } /**