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/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/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 super FieldBuilder> 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 s
@Override
public ClassBuilder transformField(FieldModel field, FieldTransform transform) {
- BufferedFieldBuilder builder = new BufferedFieldBuilder(terminal.constantPool, terminal.context,
+ BufferedFieldBuilder builder = new BufferedFieldBuilder(terminal.constantPool, terminal.context, terminal,
field.fieldName(), field.fieldType());
builder.transform(field, transform);
consumer.accept(builder.toModel());
@@ -70,7 +70,7 @@ public ClassBuilder transformField(FieldModel field, FieldTransform transform) {
@Override
public ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int flags,
Consumer super MethodBuilder> 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 super FieldBuilder> 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 super MethodBuilder> 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 super FieldElement> 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 annotations = new ArrayList<>();
for (jdk.jfr.AnnotationElement a : annotationElements) {
List list = new ArrayList<>();
diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt
index aaff6ace982..b261166a334 100644
--- a/test/jdk/ProblemList.txt
+++ b/test/jdk/ProblemList.txt
@@ -858,7 +858,6 @@ tools/sincechecker/modules/jdk.management.jfr/JdkManagementJfrCheckSince.java 83
############################################################################
# valhalla
-jdk/classfile/AccessFlagsTest.java 8366270 generic-all
java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java 8367346 generic-all
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/jdk/jdk/classfile/AccessFlagsTest.java b/test/jdk/jdk/classfile/AccessFlagsTest.java
index 379dcddb9c8..9e992779953 100644
--- a/test/jdk/jdk/classfile/AccessFlagsTest.java
+++ b/test/jdk/jdk/classfile/AccessFlagsTest.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
@@ -93,9 +93,9 @@ void testRandomAccessFlagsConverions(AccessFlag.Location ctx) {
var r = new Random(123);
for (int i = 0; i < 1000; i++) {
var randomFlags = allFlags.stream().filter(f -> 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);
}
}
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);
}
}
}