From 265ba2e766e1ce17a93e900abe75bcac0394a114 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 24 Sep 2025 15:38:59 -0500 Subject: [PATCH 1/3] Pass class file versions --- .../java/lang/classfile/AccessFlags.java | 16 +++-- .../java/lang/classfile/ClassBuilder.java | 5 +- .../java/lang/classfile/FieldBuilder.java | 5 +- .../java/lang/classfile/MethodBuilder.java | 5 +- .../classfile/attribute/InnerClassInfo.java | 4 +- .../attribute/MethodParameterInfo.java | 4 +- .../classfile/attribute/ModuleAttribute.java | 10 ++-- .../classfile/attribute/ModuleExportInfo.java | 10 ++-- .../classfile/attribute/ModuleOpenInfo.java | 10 ++-- .../attribute/ModuleRequireInfo.java | 6 +- .../classfile/impl/AccessFlagsImpl.java | 14 +++-- .../classfile/impl/BufWriterImpl.java | 13 ++-- .../classfile/impl/BufferedFieldBuilder.java | 12 +++- .../classfile/impl/BufferedMethodBuilder.java | 12 +++- .../classfile/impl/ChainedClassBuilder.java | 14 +++-- .../classfile/impl/ChainedFieldBuilder.java | 6 +- .../classfile/impl/ChainedMethodBuilder.java | 6 +- .../classfile/impl/ClassFileVersionAware.java | 34 +++++++++++ .../internal/classfile/impl/ClassImpl.java | 11 +++- .../classfile/impl/ClassReaderImpl.java | 9 ++- .../classfile/impl/DirectClassBuilder.java | 38 ++++++------ .../classfile/impl/DirectCodeBuilder.java | 5 +- .../classfile/impl/DirectFieldBuilder.java | 8 +++ .../classfile/impl/DirectMethodBuilder.java | 10 +++- .../internal/classfile/impl/FieldImpl.java | 11 +++- .../internal/classfile/impl/MethodImpl.java | 13 ++-- .../classfile/impl/TerminalFieldBuilder.java | 4 +- .../classfile/impl/TerminalMethodBuilder.java | 4 +- .../jdk/internal/classfile/impl/Util.java | 60 +++++++++++++++++-- .../classfile/impl/WritableField.java | 2 +- test/jdk/ProblemList.txt | 1 - test/jdk/jdk/classfile/AccessFlagsTest.java | 6 +- 32 files changed, 266 insertions(+), 102 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionAware.java diff --git a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java index 33db731efc8..852d91e9dc0 100644 --- a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java +++ b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java @@ -25,6 +25,7 @@ package java.lang.classfile; import java.lang.reflect.AccessFlag; +import java.lang.reflect.ClassFileFormatVersion; import java.util.Set; import jdk.internal.classfile.impl.AccessFlagsImpl; @@ -39,6 +40,10 @@ * {@code AccessFlags} cannot be created via a factory method directly; it can * be created with {@code withFlags} methods on the respective builders. *

+ * The interpretation of access flags is version dependent. Flags defined in + * some versions of the {@code class} file format may be undefined in another + * version, and all flags are considered undefined if the version is erroneous. + *

* A {@link MethodBuilder} throws an {@link IllegalArgumentException} if it is * supplied an {@code AccessFlags} object that changes the preexisting * {@link ClassFile#ACC_STATIC ACC_STATIC} flag of the builder, because the @@ -72,15 +77,18 @@ public sealed interface AccessFlags /** * {@return the access flags, as a set of flag enums} * - * @throws IllegalArgumentException if the flags mask has any undefined bit set + * @throws IllegalArgumentException if the class file version of this flag + * is unsupported, or if in the class file version, the flags mask + * has any undefined bit set * @see #location() */ Set flags(); /** - * {@return whether the specified flag is set} If the specified flag - * is not available to this {@linkplain #location() location}, returns - * {@code false}. + * {@return whether the specified flag is set} If the class file version + * of this flag is unsupported, or if in the class file version, the + * specified flag is not {@linkplain AccessFlag#locations(ClassFileFormatVersion) + * available} to this {@linkplain #location() location}, returns {@code false}. * * @param flag the flag to test * @see #location() 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 6efd240d8af..27059cdc46c 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java @@ -37,6 +37,7 @@ import jdk.internal.classfile.impl.AccessFlagsImpl; import jdk.internal.classfile.impl.ChainedClassBuilder; +import jdk.internal.classfile.impl.ClassFileVersionAware; import jdk.internal.classfile.impl.DirectClassBuilder; import jdk.internal.classfile.impl.Util; @@ -81,7 +82,7 @@ default ClassBuilder withVersion(int major, int minor) { * @see AccessFlag.Location#CLASS */ default ClassBuilder withFlags(int flags) { - return with(new AccessFlagsImpl(AccessFlag.Location.CLASS, flags)); + return with(new AccessFlagsImpl((ClassFileVersionAware) this, AccessFlag.Location.CLASS, flags)); } /** @@ -95,7 +96,7 @@ default ClassBuilder withFlags(int flags) { * @see AccessFlag.Location#CLASS */ default ClassBuilder withFlags(AccessFlag... flags) { - return with(new AccessFlagsImpl(AccessFlag.Location.CLASS, flags)); + return with(new AccessFlagsImpl((ClassFileVersionAware) this, AccessFlag.Location.CLASS, flags)); } /** 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 477aa6984a2..843480c2aa2 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java @@ -31,6 +31,7 @@ import jdk.internal.classfile.impl.AccessFlagsImpl; import jdk.internal.classfile.impl.ChainedFieldBuilder; +import jdk.internal.classfile.impl.ClassFileVersionAware; import jdk.internal.classfile.impl.TerminalFieldBuilder; /** @@ -61,7 +62,7 @@ public sealed interface FieldBuilder * @see ClassBuilder#withField(String, ClassDesc, int) */ default FieldBuilder withFlags(int flags) { - return with(new AccessFlagsImpl(AccessFlag.Location.FIELD, flags)); + return with(new AccessFlagsImpl((ClassFileVersionAware) this, AccessFlag.Location.FIELD, flags)); } /** @@ -74,7 +75,7 @@ default FieldBuilder withFlags(int flags) { * @see ClassBuilder#withField(String, ClassDesc, int) */ default FieldBuilder withFlags(AccessFlag... flags) { - return with(new AccessFlagsImpl(AccessFlag.Location.FIELD, flags)); + return with(new AccessFlagsImpl((ClassFileVersionAware) this, AccessFlag.Location.FIELD, flags)); } } 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 ff777246fde..44283922e6c 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java @@ -31,6 +31,7 @@ import jdk.internal.classfile.impl.AccessFlagsImpl; import jdk.internal.classfile.impl.ChainedMethodBuilder; +import jdk.internal.classfile.impl.ClassFileVersionAware; import jdk.internal.classfile.impl.TerminalMethodBuilder; /** @@ -64,7 +65,7 @@ public sealed interface MethodBuilder * @see AccessFlag.Location#METHOD */ default MethodBuilder withFlags(int flags) { - return with(new AccessFlagsImpl(AccessFlag.Location.METHOD, flags)); + return with(new AccessFlagsImpl((ClassFileVersionAware) this, AccessFlag.Location.METHOD, flags)); } /** @@ -79,7 +80,7 @@ default MethodBuilder withFlags(int flags) { * @see AccessFlag.Location#METHOD */ default MethodBuilder withFlags(AccessFlag... flags) { - return with(new AccessFlagsImpl(AccessFlag.Location.METHOD, flags)); + return with(new AccessFlagsImpl((ClassFileVersionAware) this, AccessFlag.Location.METHOD, flags)); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java index 343315e7f55..2a3f78653a0 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassInfo.java @@ -96,7 +96,7 @@ default Set flags() { * @see AccessFlag.Location#INNER_CLASS */ default boolean has(AccessFlag flag) { - return Util.has(AccessFlag.Location.INNER_CLASS, flagsMask(), flag); + return Util.hasFlagVersionAgnostic(AccessFlag.Location.INNER_CLASS, flagsMask(), flag); } /** @@ -137,6 +137,6 @@ static InnerClassInfo of(ClassDesc innerClass, Optional outerClass, O * the {@link AccessFlag.Location#INNER_CLASS} location */ static InnerClassInfo of(ClassDesc innerClass, Optional outerClass, Optional innerName, AccessFlag... flags) { - return of(innerClass, outerClass, innerName, Util.flagsToBits(AccessFlag.Location.INNER_CLASS, flags)); + return of(innerClass, outerClass, innerName, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.INNER_CLASS, flags)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java index 636c671f25a..8c8bb4ad10c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParameterInfo.java @@ -78,7 +78,7 @@ default Set flags() { * @see AccessFlag.Location#METHOD_PARAMETER */ default boolean has(AccessFlag flag) { - return Util.has(AccessFlag.Location.METHOD_PARAMETER, flagsMask(), flag); + return Util.hasFlagVersionAgnostic(AccessFlag.Location.METHOD_PARAMETER, flagsMask(), flag); } /** @@ -98,7 +98,7 @@ static MethodParameterInfo of(Optional name, int flags) { * {@link AccessFlag.Location#METHOD_PARAMETER} location */ static MethodParameterInfo of(Optional name, AccessFlag... flags) { - return of(name.map(TemporaryConstantPool.INSTANCE::utf8Entry), Util.flagsToBits(AccessFlag.Location.METHOD_PARAMETER, flags)); + return of(name.map(TemporaryConstantPool.INSTANCE::utf8Entry), Util.flagsToBitsVersionAgnostic(AccessFlag.Location.METHOD_PARAMETER, flags)); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java index ad564913d84..4afddf91651 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java @@ -108,7 +108,7 @@ default Set moduleFlags() { * @see AccessFlag.Location#MODULE */ default boolean has(AccessFlag flag) { - return Util.has(AccessFlag.Location.MODULE, moduleFlagsMask(), flag); + return Util.hasFlagVersionAgnostic(AccessFlag.Location.MODULE, moduleFlagsMask(), flag); } /** @@ -242,7 +242,7 @@ public sealed interface ModuleAttributeBuilder * {@link AccessFlag.Location#MODULE} location */ default ModuleAttributeBuilder moduleFlags(AccessFlag... moduleFlags) { - return moduleFlags(Util.flagsToBits(AccessFlag.Location.MODULE, moduleFlags)); + return moduleFlags(Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE, moduleFlags)); } /** @@ -274,7 +274,7 @@ default ModuleAttributeBuilder moduleFlags(AccessFlag... moduleFlags) { * {@link AccessFlag.Location#MODULE_REQUIRES} location */ default ModuleAttributeBuilder requires(ModuleDesc module, Collection requiresFlags, String version) { - return requires(module, Util.flagsToBits(AccessFlag.Location.MODULE_REQUIRES, requiresFlags), version); + return requires(module, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_REQUIRES, requiresFlags), version); } /** @@ -306,7 +306,7 @@ default ModuleAttributeBuilder requires(ModuleDesc module, Collection exportsFlags, ModuleDesc... exportsToModules) { - return exports(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_EXPORTS, exportsFlags), exportsToModules); + return exports(pkge, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_EXPORTS, exportsFlags), exportsToModules); } /** @@ -348,7 +348,7 @@ default ModuleAttributeBuilder exports(PackageDesc pkge, Collection * {@link AccessFlag.Location#MODULE_OPENS} location */ default ModuleAttributeBuilder opens(PackageDesc pkge, Collection opensFlags, ModuleDesc... opensToModules) { - return opens(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_OPENS, opensFlags), opensToModules); + return opens(pkge, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_OPENS, opensFlags), opensToModules); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java index e498b8bc036..3eb1ee8f0c0 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleExportInfo.java @@ -84,7 +84,7 @@ default Set exportsFlags() { * @see AccessFlag.Location#MODULE_EXPORTS */ default boolean has(AccessFlag flag) { - return Util.has(AccessFlag.Location.MODULE_EXPORTS, exportsFlagsMask(), flag); + return Util.hasFlagVersionAgnostic(AccessFlag.Location.MODULE_EXPORTS, exportsFlagsMask(), flag); } /** @@ -121,7 +121,7 @@ static ModuleExportInfo of(PackageEntry exports, int exportFlags, */ static ModuleExportInfo of(PackageEntry exports, Collection exportFlags, List exportsTo) { - return of(exports, Util.flagsToBits(AccessFlag.Location.MODULE_EXPORTS, exportFlags), exportsTo); + return of(exports, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_EXPORTS, exportFlags), exportsTo); } /** @@ -151,7 +151,7 @@ static ModuleExportInfo of(PackageEntry exports, static ModuleExportInfo of(PackageEntry exports, Collection exportFlags, ModuleEntry... exportsTo) { - return of(exports, Util.flagsToBits(AccessFlag.Location.MODULE_EXPORTS, exportFlags), exportsTo); + return of(exports, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_EXPORTS, exportFlags), exportsTo); } /** @@ -181,7 +181,7 @@ static ModuleExportInfo of(PackageDesc exports, int exportFlags, */ static ModuleExportInfo of(PackageDesc exports, Collection exportFlags, List exportsTo) { - return of(exports, Util.flagsToBits(AccessFlag.Location.MODULE_EXPORTS, exportFlags), exportsTo); + return of(exports, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_EXPORTS, exportFlags), exportsTo); } /** @@ -211,6 +211,6 @@ static ModuleExportInfo of(PackageDesc exports, static ModuleExportInfo of(PackageDesc exports, Collection exportFlags, ModuleDesc... exportsTo) { - return of(exports, Util.flagsToBits(AccessFlag.Location.MODULE_EXPORTS, exportFlags), exportsTo); + return of(exports, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_EXPORTS, exportFlags), exportsTo); } } diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java index d183a0b4985..808063d6975 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleOpenInfo.java @@ -90,7 +90,7 @@ default Set opensFlags() { * @see AccessFlag.Location#MODULE_OPENS */ default boolean has(AccessFlag flag) { - return Util.has(AccessFlag.Location.MODULE_OPENS, opensFlagsMask(), flag); + return Util.hasFlagVersionAgnostic(AccessFlag.Location.MODULE_OPENS, opensFlagsMask(), flag); } /** @@ -127,7 +127,7 @@ static ModuleOpenInfo of(PackageEntry opens, int opensFlags, */ static ModuleOpenInfo of(PackageEntry opens, Collection opensFlags, List opensTo) { - return of(opens, Util.flagsToBits(AccessFlag.Location.MODULE_OPENS, opensFlags), opensTo); + return of(opens, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_OPENS, opensFlags), opensTo); } /** @@ -157,7 +157,7 @@ static ModuleOpenInfo of(PackageEntry opens, static ModuleOpenInfo of(PackageEntry opens, Collection opensFlags, ModuleEntry... opensTo) { - return of(opens, Util.flagsToBits(AccessFlag.Location.MODULE_OPENS, opensFlags), opensTo); + return of(opens, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_OPENS, opensFlags), opensTo); } /** @@ -185,7 +185,7 @@ static ModuleOpenInfo of(PackageDesc opens, int opensFlags, */ static ModuleOpenInfo of(PackageDesc opens, Collection opensFlags, List opensTo) { - return of(opens, Util.flagsToBits(AccessFlag.Location.MODULE_OPENS, opensFlags), opensTo); + return of(opens, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_OPENS, opensFlags), opensTo); } /** @@ -213,6 +213,6 @@ static ModuleOpenInfo of(PackageDesc opens, static ModuleOpenInfo of(PackageDesc opens, Collection opensFlags, ModuleDesc... opensTo) { - return of(opens, Util.flagsToBits(AccessFlag.Location.MODULE_OPENS, opensFlags), opensTo); + return of(opens, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_OPENS, opensFlags), opensTo); } } diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java index 49544554090..88a649ef3c3 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleRequireInfo.java @@ -88,7 +88,7 @@ default Set requiresFlags() { * @see AccessFlag.Location#MODULE_REQUIRES */ default boolean has(AccessFlag flag) { - return Util.has(AccessFlag.Location.MODULE_REQUIRES, requiresFlagsMask(), flag); + return Util.hasFlagVersionAgnostic(AccessFlag.Location.MODULE_REQUIRES, requiresFlagsMask(), flag); } /** @@ -112,7 +112,7 @@ static ModuleRequireInfo of(ModuleEntry requires, int requiresFlags, Utf8Entry r * {@link AccessFlag.Location#MODULE_REQUIRES} location */ static ModuleRequireInfo of(ModuleEntry requires, Collection requiresFlags, Utf8Entry requiresVersion) { - return of(requires, Util.flagsToBits(AccessFlag.Location.MODULE_REQUIRES, requiresFlags), requiresVersion); + return of(requires, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_REQUIRES, requiresFlags), requiresVersion); } /** @@ -136,6 +136,6 @@ static ModuleRequireInfo of(ModuleDesc requires, int requiresFlags, String requi * {@link AccessFlag.Location#MODULE_REQUIRES} location */ static ModuleRequireInfo of(ModuleDesc requires, Collection requiresFlags, String requiresVersion) { - return of(requires, Util.flagsToBits(AccessFlag.Location.MODULE_REQUIRES, requiresFlags), requiresVersion); + return of(requires, Util.flagsToBitsVersionAgnostic(AccessFlag.Location.MODULE_REQUIRES, requiresFlags), requiresVersion); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java index 25bcec42b60..b51ef8d7b19 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AccessFlagsImpl.java @@ -32,17 +32,20 @@ public final class AccessFlagsImpl extends AbstractElement implements AccessFlags { + private final ClassFileVersionAware versionContext; private final AccessFlag.Location location; private final int flagsMask; private Set flags; - public AccessFlagsImpl(AccessFlag.Location location, AccessFlag... flags) { + public AccessFlagsImpl(ClassFileVersionAware versionContext, AccessFlag.Location location, AccessFlag... flags) { + this.versionContext = versionContext; this.location = location; - this.flagsMask = Util.flagsToBits(location, flags); + this.flagsMask = Util.flagsToBits(location, flags, Util.requireFormatVersion(versionContext.classFileVersion())); this.flags = Set.of(flags); } - public AccessFlagsImpl(AccessFlag.Location location, int mask) { + public AccessFlagsImpl(ClassFileVersionAware versionContext, AccessFlag.Location location, int mask) { + this.versionContext = versionContext; this.location = location; this.flagsMask = mask; } @@ -55,7 +58,7 @@ public int flagsMask() { @Override public Set flags() { if (flags == null) - flags = AccessFlag.maskToAccessFlags(flagsMask, location, ClassFileFormatVersion.CURRENT_PREVIEW_FEATURES); + flags = AccessFlag.maskToAccessFlags(flagsMask, location, Util.requireFormatVersion(versionContext.classFileVersion())); return flags; } @@ -81,7 +84,8 @@ public AccessFlag.Location location() { @Override public boolean has(AccessFlag flag) { - return Util.has(location, flagsMask, flag); + var cffv = Util.findFormatVersion(versionContext.classFileVersion()); + return cffv != null && Util.hasFlag(location, flagsMask, flag, cffv); } @Override 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 f683e259d3d..2dbd6c306d1 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 @@ -43,7 +43,7 @@ import static jdk.internal.util.ModifiedUtf.putChar; import static jdk.internal.util.ModifiedUtf.utfLen; -public final class BufWriterImpl implements BufWriter { +public final class BufWriterImpl implements BufWriter, ClassFileVersionAware { private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private final ConstantPoolBuilder constantPool; @@ -54,7 +54,7 @@ public final class BufWriterImpl implements BufWriter { private boolean lastStrictCheckResult; private boolean labelsMatch; private final ClassEntry thisClass; - private final int majorVersion; + private final int classFileVersion; byte[] elems; int offset = 0; @@ -66,12 +66,12 @@ public BufWriterImpl(ConstantPoolBuilder constantPool, ClassFileImpl context, in this(constantPool, context, initialSize, null, 0); } - public BufWriterImpl(ConstantPoolBuilder constantPool, ClassFileImpl context, int initialSize, ClassEntry thisClass, int majorVersion) { + public BufWriterImpl(ConstantPoolBuilder constantPool, ClassFileImpl context, int initialSize, ClassEntry thisClass, int classFileVersion) { this.constantPool = constantPool; this.context = context; elems = new byte[initialSize]; this.thisClass = thisClass; - this.majorVersion = majorVersion; + this.classFileVersion = classFileVersion; } public boolean strictFieldsMatch(ClassModel cm) { @@ -140,8 +140,9 @@ public ClassEntry thisClass() { return thisClass; } - public int getMajorVersion() { - return majorVersion; + @Override + public int classFileVersion() { + return classFileVersion; } public ClassFileImpl context() { 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 bd42d66dd3e..6cdcc0c98c3 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,6 +43,7 @@ public final class BufferedFieldBuilder implements TerminalFieldBuilder { private final SplitConstantPool constantPool; private final ClassFileImpl context; + private final ClassFileVersionAware versionSource; private final Utf8Entry name; private final Utf8Entry desc; private final List elements = new ArrayList<>(); @@ -50,13 +51,15 @@ public final class BufferedFieldBuilder public BufferedFieldBuilder(SplitConstantPool constantPool, ClassFileImpl context, + ClassFileVersionAware versionSource, Utf8Entry name, Utf8Entry type) { this.constantPool = constantPool; this.context = context; + this.versionSource = versionSource; this.name = requireNonNull(name); this.desc = requireNonNull(type); - this.flags = new AccessFlagsImpl(AccessFlag.Location.FIELD); + this.flags = new AccessFlagsImpl(this, AccessFlag.Location.FIELD); } @Override @@ -117,4 +120,9 @@ public String toString() { return String.format("FieldModel[fieldName=%s, fieldType=%s, flags=%d]", name.stringValue(), desc.stringValue(), flags.flagsMask()); } } + + @Override + public int classFileVersion() { + return versionSource.classFileVersion(); + } } 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 747fd876fbf..472bef568ad 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -40,6 +40,7 @@ public final class BufferedMethodBuilder implements TerminalMethodBuilder { private final List elements; private final SplitConstantPool constantPool; + private final ClassFileVersionAware versionSource; private final ClassFileImpl context; private final Utf8Entry name; private final Utf8Entry desc; @@ -49,6 +50,7 @@ public final class BufferedMethodBuilder public BufferedMethodBuilder(SplitConstantPool constantPool, ClassFileImpl context, + ClassFileVersionAware versionSource, Utf8Entry nameInfo, Utf8Entry typeInfo, int flags, @@ -56,9 +58,10 @@ public BufferedMethodBuilder(SplitConstantPool constantPool, this.elements = new ArrayList<>(); this.constantPool = constantPool; this.context = context; + this.versionSource = versionSource; this.name = requireNonNull(nameInfo); this.desc = requireNonNull(typeInfo); - this.flags = new AccessFlagsImpl(AccessFlag.Location.METHOD, flags); + this.flags = new AccessFlagsImpl(this, AccessFlag.Location.METHOD, flags); this.original = original; } @@ -199,4 +202,9 @@ public String toString() { name.stringValue(), desc.stringValue(), flags.flagsMask()); } } + + @Override + public int classFileVersion() { + return versionSource.classFileVersion(); + } } 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 b4c8ad58705..7ad54e94884 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 @@ -32,7 +32,7 @@ import static java.util.Objects.requireNonNull; public final class ChainedClassBuilder - implements ClassBuilder, Consumer { + implements ClassBuilder, Consumer, ClassFileVersionAware { private final DirectClassBuilder terminal; private final Consumer consumer; @@ -51,7 +51,7 @@ public ClassBuilder with(ClassElement element) { @Override public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, Consumer handler) { - consumer.accept(new BufferedFieldBuilder(terminal.constantPool, terminal.context, + consumer.accept(new BufferedFieldBuilder(terminal.constantPool, terminal.context, terminal, name, descriptor) .run(handler) .toModel()); @@ -60,7 +60,7 @@ public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, Consumer handler) { - consumer.accept(new BufferedMethodBuilder(terminal.constantPool, terminal.context, + consumer.accept(new BufferedMethodBuilder(terminal.constantPool, terminal.context, terminal, name, descriptor, flags, null) .run(handler) .toModel()); @@ -79,7 +79,7 @@ public ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int flags, @Override public ClassBuilder transformMethod(MethodModel method, MethodTransform transform) { - BufferedMethodBuilder builder = new BufferedMethodBuilder(terminal.constantPool, terminal.context, + BufferedMethodBuilder builder = new BufferedMethodBuilder(terminal.constantPool, terminal.context, terminal, method.methodName(), method.methodType(), method.flags().flagsMask(), method); builder.transform(method, transform); consumer.accept(builder.toModel()); @@ -91,4 +91,8 @@ public ConstantPoolBuilder constantPool() { return terminal.constantPool(); } + @Override + public int classFileVersion() { + return terminal.classFileVersion(); + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java index 9eac25d567c..aed3e693d55 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java @@ -31,7 +31,7 @@ import static java.util.Objects.requireNonNull; -public final class ChainedFieldBuilder implements FieldBuilder { +public final class ChainedFieldBuilder implements FieldBuilder, ClassFileVersionAware { private final TerminalFieldBuilder terminal; private final Consumer consumer; @@ -53,5 +53,9 @@ public FieldBuilder with(FieldElement element) { return this; } + @Override + public int classFileVersion() { + return terminal.classFileVersion(); + } } 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 e96351b8856..8a69d10a72b 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 @@ -34,7 +34,7 @@ import static java.util.Objects.requireNonNull; -public final class ChainedMethodBuilder implements MethodBuilder { +public final class ChainedMethodBuilder implements MethodBuilder, ClassFileVersionAware { final TerminalMethodBuilder terminal; final Consumer consumer; @@ -72,4 +72,8 @@ public ConstantPoolBuilder constantPool() { return terminal.constantPool(); } + @Override + public int classFileVersion() { + return terminal.classFileVersion(); + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionAware.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionAware.java new file mode 100644 index 00000000000..96fd7decc7b --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileVersionAware.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, 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 jdk.internal.classfile.impl; + +/// A model that knows its class file version for version-specific handling. +/// Implemented by raw class, field, method models, and builders for access flags. +/// Only [ClassReaderImpl], [DirectClassBuilder], and [BufWriterImpl] store the versions. +/// Other implementations ultimately delegate to them. +public interface ClassFileVersionAware { + int classFileVersion(); +} diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java index 2e5c2c24651..c0961c6a861 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -37,7 +37,7 @@ public final class ClassImpl extends AbstractElement - implements ClassModel { + implements ClassModel, ClassFileVersionAware { final ClassReaderImpl reader; private final int attributesPos; private final List methods; @@ -80,7 +80,7 @@ public int classfileLength() { @Override public AccessFlags flags() { - return new AccessFlagsImpl(AccessFlag.Location.CLASS, reader.flags()); + return new AccessFlagsImpl(this, AccessFlag.Location.CLASS, reader.flags()); } @Override @@ -93,6 +93,11 @@ public int minorVersion() { return reader.readU2(4); } + @Override + public int classFileVersion() { + return reader.classFileVersion(); + } + @Override public ConstantPool constantPool() { return reader; 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 d325100febf..7ba057e3d59 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -42,7 +42,7 @@ import static java.lang.classfile.constantpool.PoolEntry.*; public final class ClassReaderImpl - implements ClassReader { + implements ClassReader, ClassFileVersionAware { static final int CP_ITEM_START = 10; private final byte[] buffer; @@ -469,4 +469,9 @@ public boolean compare(BufWriterImpl bufWriter, throw outOfBoundsError(e); } } + + @Override + public int classFileVersion() { + return readInt(4); + } } 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 e2fb899d4fe..a332c3e6c5f 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 @@ -35,13 +35,12 @@ import java.util.List; import java.util.function.Consumer; -import static java.lang.classfile.ClassFile.PREVIEW_MINOR_VERSION; -import static java.lang.classfile.ClassFile.latestMajorVersion; +import static java.lang.classfile.ClassFile.*; import static java.util.Objects.requireNonNull; public final class DirectClassBuilder extends AbstractDirectBuilder - implements ClassBuilder { + implements ClassBuilder, ClassFileVersionAware { /** The value of default class access flags */ static final int DEFAULT_CLASS_FLAGS = ClassFile.ACC_PUBLIC | ClassFile.ACC_SUPER; @@ -55,8 +54,7 @@ public final class DirectClassBuilder private int methodsCount = 0; private ClassEntry superclassEntry; private List interfaceEntries; - private int majorVersion; - private int minorVersion; + private int classFileVersion; private int flags; private int sizeHint; @@ -68,8 +66,7 @@ public DirectClassBuilder(SplitConstantPool constantPool, this.flags = DEFAULT_CLASS_FLAGS; this.superclassEntry = null; this.interfaceEntries = Collections.emptyList(); - this.majorVersion = ClassFile.latestMajorVersion(); - this.minorVersion = ClassFile.latestMinorVersion(); + this.classFileVersion = Util.toClassFileVersion(latestMajorVersion(), latestMinorVersion()); } @Override @@ -92,21 +89,21 @@ public ClassBuilder withFlags(int flags) { public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, int flags) { - return withField(new DirectFieldBuilder(constantPool, context, name, descriptor, flags, null)); + return withField(new DirectFieldBuilder(constantPool, context, this, name, descriptor, flags, null)); } @Override public ClassBuilder withField(Utf8Entry name, Utf8Entry descriptor, Consumer handler) { - return withField(new DirectFieldBuilder(constantPool, context, name, descriptor, 0, null) + return withField(new DirectFieldBuilder(constantPool, context, this, name, descriptor, 0, null) .run(handler)); } @Override public ClassBuilder transformField(FieldModel field, FieldTransform transform) { - DirectFieldBuilder builder = new DirectFieldBuilder(constantPool, context, field.fieldName(), - field.fieldType(), 0, field); + DirectFieldBuilder builder = new DirectFieldBuilder(constantPool, context, this, + field.fieldName(), field.fieldType(), 0, field); builder.transform(field, transform); return withField(builder); } @@ -116,13 +113,14 @@ public ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int flags, Consumer handler) { - return withMethod(new DirectMethodBuilder(constantPool, context, name, descriptor, flags, null) + return withMethod(new DirectMethodBuilder(constantPool, context, this, name, descriptor, flags, null) .run(handler)); } @Override public ClassBuilder transformMethod(MethodModel method, MethodTransform transform) { - DirectMethodBuilder builder = new DirectMethodBuilder(constantPool, context, method.methodName(), + DirectMethodBuilder builder = new DirectMethodBuilder(constantPool, context, this, + method.methodName(), method.methodType(), method.flags().flagsMask(), method); @@ -159,8 +157,12 @@ void setInterfaces(List interfaces) { } void setVersion(int major, int minor) { - this.majorVersion = major; - this.minorVersion = minor; + this.classFileVersion = Util.toClassFileVersion(major, minor); + } + + @Override + public int classFileVersion() { + return this.classFileVersion; } void setFlags(int flags) { @@ -192,13 +194,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; BufWriterImpl head = new BufWriterImpl(constantPool, context, size); - BufWriterImpl tail = new BufWriterImpl(constantPool, context, size, thisClassEntry, majorVersion); + BufWriterImpl tail = new BufWriterImpl(constantPool, context, size, thisClassEntry, classFileVersion); // The tail consists of fields and methods, and attributes // This should trigger all the CP/BSM mutation Util.writeList(tail, fields, fieldsCount); WritableField.UnsetField[] strictInstanceFields; - if (minorVersion == PREVIEW_MINOR_VERSION && majorVersion >= Util.VALUE_OBJECTS_MAJOR) { + if (Util.extractMinorVersion(classFileVersion) == PREVIEW_MINOR_VERSION && Util.extractMajorVersion(classFileVersion) >= Util.VALUE_OBJECTS_MAJOR) { strictInstanceFields = WritableField.filterStrictInstanceFields(constantPool, fields, fieldsCount); } else { strictInstanceFields = WritableField.UnsetField.EMPTY_ARRAY; @@ -216,7 +218,7 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC // Now we can make the head head.writeInt(ClassFile.MAGIC_NUMBER); - head.writeU2U2(minorVersion, majorVersion); + head.writeInt(classFileVersion); constantPool.writeTo(head); head.writeU2U2U2(flags, head.cpIndex(thisClassEntry), head.cpIndexOrZero(superclass)); head.writeU2(interfaceEntriesSize); 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 32b26d54d6d..47a8e8f465f 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 @@ -344,12 +344,13 @@ private void generateStackMaps(BufWriterImpl buf) throws IllegalArgumentExceptio } private void tryGenerateStackMaps(boolean codeMatch, BufWriterImpl buf) { - if (buf.getMajorVersion() >= ClassFile.JAVA_6_VERSION) { + int majorVersion = Util.extractMajorVersion(buf.classFileVersion()); + if (majorVersion >= ClassFile.JAVA_6_VERSION) { try { generateStackMaps(buf); } catch (IllegalArgumentException e) { //failover following JVMS-4.10 - if (buf.getMajorVersion() == ClassFile.JAVA_6_VERSION) { + if (majorVersion == ClassFile.JAVA_6_VERSION) { writeCounters(codeMatch, buf); } else { throw e; 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 4fae767ff06..eee35e38271 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 @@ -37,17 +37,20 @@ public final class DirectFieldBuilder extends AbstractDirectBuilder implements TerminalFieldBuilder, WritableField { + private final ClassFileVersionAware versionSource; private final Utf8Entry name; private final Utf8Entry desc; private int flags; public DirectFieldBuilder(SplitConstantPool constantPool, ClassFileImpl context, + ClassFileVersionAware versionSource, Utf8Entry name, Utf8Entry type, int flags, FieldModel original) { super(constantPool, context); + this.versionSource = versionSource; setOriginal(original); this.name = requireNonNull(name); this.desc = requireNonNull(type); @@ -100,4 +103,9 @@ public Utf8Entry fieldType() { public int fieldFlags() { return flags; } + + @Override + public int classFileVersion() { + return versionSource.classFileVersion(); + } } 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 938d6c088b7..2a1fd37cb87 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -36,6 +36,7 @@ public final class DirectMethodBuilder extends AbstractDirectBuilder implements TerminalMethodBuilder, Util.Writable { + final ClassFileVersionAware versionSource; final Utf8Entry name; final Utf8Entry desc; int flags; @@ -43,11 +44,13 @@ public final class DirectMethodBuilder public DirectMethodBuilder(SplitConstantPool constantPool, ClassFileImpl context, + ClassFileVersionAware versionSource, Utf8Entry nameInfo, Utf8Entry typeInfo, int flags, MethodModel original) { super(constantPool, context); + this.versionSource = versionSource; setOriginal(original); this.name = requireNonNull(nameInfo); this.desc = requireNonNull(typeInfo); @@ -145,4 +148,9 @@ public void writeTo(BufWriterImpl buf) { buf.writeU2U2U2(flags, buf.cpIndex(name), buf.cpIndex(desc)); attributes.writeTo(buf); } + + @Override + public int classFileVersion() { + return versionSource.classFileVersion(); + } } 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 c4179ba0b66..a2f8c0ab578 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 @@ -40,11 +40,11 @@ public final class FieldImpl extends AbstractElement implements FieldModel, WritableField { - private final ClassReader reader; + private final ClassReaderImpl reader; private final int startPos, endPos, attributesPos; private List> attributes; - public FieldImpl(ClassReader reader, int startPos, int endPos, int attributesPos) { + public FieldImpl(ClassReaderImpl reader, int startPos, int endPos, int attributesPos) { this.reader = reader; this.startPos = startPos; this.endPos = endPos; @@ -53,7 +53,7 @@ public FieldImpl(ClassReader reader, int startPos, int endPos, int attributesPos @Override public AccessFlags flags() { - return new AccessFlagsImpl(AccessFlag.Location.FIELD, fieldFlags()); + return new AccessFlagsImpl(this, AccessFlag.Location.FIELD, fieldFlags()); } @Override @@ -121,6 +121,11 @@ public void forEach(Consumer consumer) { } } + @Override + public int classFileVersion() { + return reader.classFileVersion(); + } + @Override public String toString() { return String.format("FieldModel[fieldName=%s, fieldType=%s, flags=%d]", 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 cfb59829863..39da421ace7 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,14 +34,14 @@ public final class MethodImpl extends AbstractElement - implements MethodModel, MethodInfo, Util.Writable { + implements MethodModel, MethodInfo, Util.Writable, ClassFileVersionAware { - private final ClassReader reader; + private final ClassReaderImpl reader; private final int startPos, endPos, attributesPos; private List> attributes; private int[] parameterSlots; - public MethodImpl(ClassReader reader, int startPos, int endPos, int attrStart) { + public MethodImpl(ClassReaderImpl reader, int startPos, int endPos, int attrStart) { this.reader = reader; this.startPos = startPos; this.endPos = endPos; @@ -50,7 +50,7 @@ public MethodImpl(ClassReader reader, int startPos, int endPos, int attrStart) { @Override public AccessFlags flags() { - return new AccessFlagsImpl(AccessFlag.Location.METHOD, reader.readU2(startPos)); + return new AccessFlagsImpl(this, AccessFlag.Location.METHOD, reader.readU2(startPos)); } @Override @@ -135,6 +135,11 @@ public void writeTo(DirectClassBuilder builder) { } } + @Override + public int classFileVersion() { + return reader.classFileVersion(); + } + @Override public String toString() { return String.format("MethodModel[methodName=%s, methodType=%s, flags=%d]", diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalFieldBuilder.java index b9fbf7fe652..2804ac14f60 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalFieldBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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,6 +27,6 @@ import java.lang.classfile.FieldBuilder; public sealed interface TerminalFieldBuilder - extends FieldBuilder + extends FieldBuilder, ClassFileVersionAware permits DirectFieldBuilder, BufferedFieldBuilder { } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalMethodBuilder.java index e1c66bec503..ab1319c1914 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalMethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, 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 @@ -28,7 +28,7 @@ import java.lang.classfile.MethodBuilder; public sealed interface TerminalMethodBuilder - extends MethodBuilder, MethodInfo + extends MethodBuilder, MethodInfo, ClassFileVersionAware permits BufferedMethodBuilder, DirectMethodBuilder { BufferedCodeBuilder bufferedCodeBuilder(CodeModel original); } 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 c82588c6cfc..bdb77f665c9 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 @@ -39,6 +39,7 @@ import java.lang.reflect.AccessFlag; import java.lang.reflect.ClassFileFormatVersion; import java.util.AbstractList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.function.Consumer; @@ -67,6 +68,45 @@ public class Util { private Util() { } + public static ClassFileFormatVersion findFormatVersion(int classfileVersion) { + int major = extractMajorVersion(classfileVersion); + int minor = extractMinorVersion(classfileVersion); + if (major < ClassFile.JAVA_1_VERSION || major > ClassFile.latestMajorVersion()) + return null; + if (major == ClassFile.JAVA_1_VERSION) { + return minor <= 3 ? ClassFileFormatVersion.RELEASE_0 : ClassFileFormatVersion.RELEASE_1; + } + // for major version is between 45 and 55 inclusive, the minor version may be any value + if (major < ClassFile.JAVA_12_VERSION || minor == 0) + return ClassFileFormatVersion.fromMajor(major); + + return (major == ClassFile.latestMajorVersion() && minor == ClassFile.PREVIEW_MINOR_VERSION) ? + ClassFileFormatVersion.CURRENT_PREVIEW_FEATURES : null; + } + + public static ClassFileFormatVersion requireFormatVersion(int classFileVersion) { + var ret = findFormatVersion(classFileVersion); + if (ret == null) + throw new IllegalArgumentException("Unsupported class file version: " + classFileVersionString(classFileVersion)); + return ret; + } + + public static String classFileVersionString(int classFileVersion) { + return extractMajorVersion(classFileVersion) + "." + extractMinorVersion(classFileVersion); + } + + public static int toClassFileVersion(int majorVersion, int minorVersion) { + return majorVersion | minorVersion << Character.SIZE; + } + + public static int extractMajorVersion(int classfileVersion) { + return (char) classfileVersion; + } + + public static int extractMinorVersion(int classfileVersion) { + return classfileVersion >>> Character.SIZE; + } + public static Consumer> writingAll(Iterable container) { record ForEachConsumer(Iterable container) implements Consumer> { @Override @@ -192,10 +232,10 @@ public static IllegalArgumentException badOpcodeKindException(Opcode op, Opcode. String.format("Wrong opcode kind specified; found %s(%s), expected %s", op, op.kind(), k)); } - public static int flagsToBits(AccessFlag.Location location, Collection flags) { + public static int flagsToBitsVersionAgnostic(AccessFlag.Location location, Collection flags) { int i = 0; for (AccessFlag f : flags) { - if (!f.locations().contains(location)) { + if (!f.locations().contains(location) && !f.locations(ClassFileFormatVersion.CURRENT_PREVIEW_FEATURES).contains(location)) { throw new IllegalArgumentException("unexpected flag: " + f + " use in target location: " + location); } i |= f.mask(); @@ -203,22 +243,30 @@ public static int flagsToBits(AccessFlag.Location location, Collection r.nextBoolean()).toArray(AccessFlag[]::new); - assertEquals(intFactory.apply(flagsFactory.apply(randomFlags).flagsMask()).flags(), Set.of(randomFlags)); + assertEquals(Set.of(randomFlags), intFactory.apply(flagsFactory.apply(randomFlags).flagsMask()).flags()); - var randomMask = r.nextInt(Short.MAX_VALUE); + var randomMask = r.nextInt(0x10000); assertEquals(intFactory.apply(randomMask).flagsMask(), randomMask); } } From efa73c2038c8b051cf2e984967c3fe72efb06bf7 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 24 Sep 2025 17:34:18 -0500 Subject: [PATCH 2/3] Fix existing misuse --- .../share/classes/java/lang/runtime/SwitchBootstraps.java | 2 +- .../share/classes/jdk/jfr/internal/EventClassBuilder.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 2b5912f02cb..f4d82595842 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -736,7 +736,7 @@ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Clas byte[] classBytes = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS).build(ConstantUtils.binaryNameToDesc(typeSwitchClassName(caller.lookupClass())), clb -> { - clb.withFlags(AccessFlag.FINAL, (PreviewFeatures.isEnabled()) ? AccessFlag.IDENTITY : AccessFlag.SUPER, AccessFlag.SYNTHETIC) + clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC) .withMethodBody("typeSwitch", addExtraInfo ? MTD_TYPE_SWITCH_EXTRA : MTD_TYPE_SWITCH, ClassFile.ACC_FINAL | ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC, diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java index 871f9026cfd..648abab472f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java @@ -113,7 +113,7 @@ private void buildConstructor(ClassBuilder builder) { private void buildClassInfo(ClassBuilder builder) { builder.withSuperclass(Bytecode.classDesc(Event.class)); - builder.withFlags(AccessFlag.FINAL, AccessFlag.PUBLIC, (PreviewFeatures.isEnabled() ? AccessFlag.IDENTITY : AccessFlag.SUPER)); + builder.withFlags(AccessFlag.FINAL, AccessFlag.PUBLIC, AccessFlag.SUPER); List annotations = new ArrayList<>(); for (jdk.jfr.AnnotationElement a : annotationElements) { List list = new ArrayList<>(); From fc52cd9e1c895eefddbebfc443a242455a805c11 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Thu, 25 Sep 2025 11:22:48 -0500 Subject: [PATCH 3/3] Fixes --- .../classes/sun/tools/jar/FingerPrint.java | 7 +++++-- .../jdk/jfr/internal/EventClassBuilder.java | 2 +- .../Class/getSimpleName/GetSimpleNameTest.java | 13 ++++++------- test/jdk/java/lang/invoke/DefineClassTest.java | 11 +++++------ .../defineHiddenClass/StaticInvocableTest.java | 7 +++---- .../java/lang/invoke/lookup/SpecialStatic.java | 11 +++++------ .../util/ServiceLoader/BadProvidersTest.java | 7 +++---- .../ValueObjectCompilationTests.java | 18 +++++++++++------- 8 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java b/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java index a703b8b69c1..624c364c880 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, 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 @@ -42,6 +42,9 @@ import java.lang.classfile.attribute.EnclosingMethodAttribute; import java.lang.classfile.attribute.InnerClassesAttribute; +import static java.lang.classfile.ClassFile.ACC_PROTECTED; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; + /** * A FingerPrint is an abstract representation of a JarFile entry that contains * information to determine if the entry represents a class or a @@ -316,7 +319,7 @@ public void accept(ClassElement cle) { } private static boolean isPublic(AccessFlags access) { - return access.has(AccessFlag.PUBLIC) || access.has(AccessFlag.PROTECTED); + return (access.flagsMask() & (ACC_PUBLIC | ACC_PROTECTED)) != 0; } @Override diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java index 648abab472f..8cb858e99c7 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, 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 diff --git a/test/jdk/java/lang/Class/getSimpleName/GetSimpleNameTest.java b/test/jdk/java/lang/Class/getSimpleName/GetSimpleNameTest.java index ce7e10a49e5..c9d0aea0b22 100644 --- a/test/jdk/java/lang/Class/getSimpleName/GetSimpleNameTest.java +++ b/test/jdk/java/lang/Class/getSimpleName/GetSimpleNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -37,8 +37,7 @@ import java.lang.reflect.AccessFlag; import java.util.Optional; -import static java.lang.classfile.ClassFile.ACC_PUBLIC; -import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.classfile.ClassFile.*; import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.constant.ConstantDescs.INIT_NAME; import static java.lang.constant.ConstantDescs.MTD_void; @@ -167,7 +166,7 @@ byte[] getNestedClasses(boolean isInner) { var name = (isInner ? innerName : outerName); return ClassFile.of().build(name, clb -> { clb.withSuperclass(CD_Object); - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.with(InnerClassesAttribute.of( InnerClassInfo.of(innerName, Optional.of(outerName), @@ -180,7 +179,7 @@ byte[] getInnerClasses(boolean isInner) { var name = (isInner ? innerName : outerName); return ClassFile.of().build(name, clb -> { clb.withSuperclass(CD_Object); - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.with(InnerClassesAttribute.of( InnerClassInfo.of(innerName, Optional.of(outerName), @@ -194,7 +193,7 @@ byte[] getLocalClasses(boolean isInner) { var name = (isInner ? innerName : outerName); return ClassFile.of().build(name, clb -> { clb.withSuperclass(CD_Object); - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.with(InnerClassesAttribute.of( InnerClassInfo.of(innerName, Optional.empty(), @@ -209,7 +208,7 @@ byte[] getAnonymousClasses(boolean isInner) { var name = (isInner ? innerName : outerName); return ClassFile.of().build(name, clb -> { clb.withSuperclass(CD_Object); - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.with(InnerClassesAttribute.of( InnerClassInfo.of(innerName, Optional.empty(), diff --git a/test/jdk/java/lang/invoke/DefineClassTest.java b/test/jdk/java/lang/invoke/DefineClassTest.java index 09a68ef71bc..02a9ab55393 100644 --- a/test/jdk/java/lang/invoke/DefineClassTest.java +++ b/test/jdk/java/lang/invoke/DefineClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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,8 +41,7 @@ import java.nio.file.Paths; import org.testng.annotations.Test; -import static java.lang.classfile.ClassFile.ACC_PUBLIC; -import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.classfile.ClassFile.*; import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME; import static java.lang.constant.ConstantDescs.INIT_NAME; @@ -259,7 +258,7 @@ public void testModuleInfo() throws Exception { */ byte[] generateClass(String className) { return ClassFile.of().build(ClassDesc.of(className), clb -> { - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.withSuperclass(CD_Object); clb.withMethodBody(INIT_NAME, MTD_void, PUBLIC, cob -> { cob.aload(0); @@ -301,7 +300,7 @@ byte[] generateClassWithInitializer(String className, String targetMethod) throws Exception { return ClassFile.of().build(ClassDesc.of(className), clb -> { - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.withSuperclass(CD_Object); clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { cob.aload(0); @@ -320,7 +319,7 @@ byte[] generateClassWithInitializer(String className, */ byte[] generateNonLinkableClass(String className) { return ClassFile.of().build(ClassDesc.of(className), clb -> { - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.withSuperclass(CD_MissingSuperClass); clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { cob.aload(0); diff --git a/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java b/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java index 221a1d7d5f2..d0008a196ae 100644 --- a/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java +++ b/test/jdk/java/lang/invoke/defineHiddenClass/StaticInvocableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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,8 +41,7 @@ import java.lang.reflect.AccessFlag; import org.testng.annotations.Test; -import static java.lang.classfile.ClassFile.ACC_PUBLIC; -import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.classfile.ClassFile.*; import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.constant.ConstantDescs.CD_int; import static java.lang.constant.ConstantDescs.INIT_NAME; @@ -117,7 +116,7 @@ private static void test(String pkg) throws Throwable { public static byte[] dumpClass(String pkg) { return ClassFile.of().build(ClassDesc.of(pkg.replace('/', '.'), "MyClass"), clb -> { clb.withSuperclass(CD_Object); - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.withMethodBody(INIT_NAME, MTD_void, 0, cob -> { cob.aload(0); cob.invokespecial(CD_Object, INIT_NAME, MTD_void); diff --git a/test/jdk/java/lang/invoke/lookup/SpecialStatic.java b/test/jdk/java/lang/invoke/lookup/SpecialStatic.java index bbf4210ee5d..95b1a1086d8 100644 --- a/test/jdk/java/lang/invoke/lookup/SpecialStatic.java +++ b/test/jdk/java/lang/invoke/lookup/SpecialStatic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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,8 +41,7 @@ import org.testng.annotations.*; -import static java.lang.classfile.ClassFile.ACC_PUBLIC; -import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.classfile.ClassFile.*; import static java.lang.constant.ConstantDescs.*; import static java.lang.constant.DirectMethodHandleDesc.Kind.SPECIAL; import static org.testng.Assert.*; @@ -120,7 +119,7 @@ public void testFindSpecial() throws Throwable { public static byte[] dumpT1() { return ClassFile.of().build(CD_T1, clb -> { clb.withSuperclass(CD_Object); - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { cob.aload(0); cob.invokespecial(CD_Object, INIT_NAME, MTD_void); @@ -136,7 +135,7 @@ public static byte[] dumpT1() { public static byte[] dumpT2() { return ClassFile.of().build(CD_T2, clb -> { clb.withSuperclass(CD_T1); - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { cob.aload(0); cob.invokespecial(CD_T1, INIT_NAME, MTD_void); @@ -152,7 +151,7 @@ public static byte[] dumpT2() { public static byte[] dumpT3() { return ClassFile.of().build(CD_T3, clb -> { clb.withSuperclass(CD_T2); - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); clb.withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> { cob.aload(0); cob.invokespecial(CD_T2, INIT_NAME, MTD_void); diff --git a/test/jdk/java/util/ServiceLoader/BadProvidersTest.java b/test/jdk/java/util/ServiceLoader/BadProvidersTest.java index ce1942a952d..4f504a650d4 100644 --- a/test/jdk/java/util/ServiceLoader/BadProvidersTest.java +++ b/test/jdk/java/util/ServiceLoader/BadProvidersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, 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 @@ -54,8 +54,7 @@ import org.testng.annotations.Test; import org.testng.annotations.DataProvider; -import static java.lang.classfile.ClassFile.ACC_PUBLIC; -import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.classfile.ClassFile.*; import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.constant.ConstantDescs.INIT_NAME; import static java.lang.constant.ConstantDescs.MTD_void; @@ -216,7 +215,7 @@ public void testWithTwoFactoryMethods() throws Exception { var bytes = ClassFile.of().build(ClassDesc.of("p", "ProviderFactory"), clb -> { clb.withSuperclass(CD_Object); - clb.withFlags(AccessFlag.PUBLIC, AccessFlag.IDENTITY); + clb.withFlags(ACC_PUBLIC | ACC_IDENTITY); var providerFactory$1 = ClassDesc.of("p", "ProviderFactory$1"); diff --git a/test/langtools/tools/javac/valhalla/value-objects/ValueObjectCompilationTests.java b/test/langtools/tools/javac/valhalla/value-objects/ValueObjectCompilationTests.java index 3e89639569e..18d4200b026 100644 --- a/test/langtools/tools/javac/valhalla/value-objects/ValueObjectCompilationTests.java +++ b/test/langtools/tools/javac/valhalla/value-objects/ValueObjectCompilationTests.java @@ -61,6 +61,8 @@ import tools.javac.combo.CompilationTestCase; import toolbox.ToolBox; +import static java.lang.classfile.ClassFile.*; + class ValueObjectCompilationTests extends CompilationTestCase { private static String[] PREVIEW_OPTIONS = { @@ -644,7 +646,8 @@ abstract class Inner {} for (final File fileEntry : dir.listFiles()) { if (fileEntry.getName().contains("$")) { var classFile = ClassFile.of().parse(fileEntry.toPath()); - Assert.check(classFile.flags().has(AccessFlag.IDENTITY)); + // Check bit, these classes may be non-preview + Assert.check((classFile.flags().flagsMask() & ACC_IDENTITY) != 0); } } } @@ -689,7 +692,8 @@ record R() {} File dir = assertOK(true, source); for (final File fileEntry : dir.listFiles()) { var classFile = ClassFile.of().parse(fileEntry.toPath()); - Assert.check(classFile.flags().has(AccessFlag.IDENTITY)); + // Check bit, these classes may be non-preview + Assert.check((classFile.flags().flagsMask() & ACC_IDENTITY) != 0); } } @@ -766,12 +770,12 @@ class Test { File dir = assertOK(true, source); for (final File fileEntry : dir.listFiles()) { var classFile = ClassFile.of().parse(fileEntry.toPath()); - Assert.check(classFile.flags().has(AccessFlag.IDENTITY)); + // Check bit, these classes may be non-preview + Assert.check((classFile.flags().flagsMask() & ACC_IDENTITY) != 0); for (var field : classFile.fields()) { - if (!field.flags().has(AccessFlag.STATIC)) { - Set fieldFlags = field.flags().flags(); - Assert.check(fieldFlags.contains(AccessFlag.STRICT_INIT)); - } + // TODO migrate to AccessFlag when javac correctly sets preview version + int mask = field.flags().flagsMask(); + Assert.check((mask & ACC_STATIC) != 0 || (mask & ACC_STRICT_INIT) != 0); } } }