8372696: Allow boot classes to explicitly opt-in for final field trusting

Reviewed-by: jvernee, jrose, alanb
This commit is contained in:
Chen Liang 2026-01-26 18:32:15 +00:00
parent b42861a2aa
commit 3220c4cb43
13 changed files with 155 additions and 14 deletions

View File

@ -216,6 +216,10 @@ ciField::ciField(fieldDescriptor *fd) :
static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
if (holder == nullptr)
return false;
if (holder->trust_final_fields()) {
// Explicit opt-in from system classes
return true;
}
// Even if general trusting is disabled, trust system-built closures in these packages.
if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke") ||
holder->is_in_package("java/lang/reflect") || holder->is_in_package("jdk/internal/reflect") ||
@ -230,14 +234,6 @@ static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
// Trust final fields in records
if (holder->is_record())
return true;
// Trust Atomic*FieldUpdaters: they are very important for performance, and make up one
// more reason not to use Unsafe, if their final fields are trusted. See more in JDK-8140483.
if (holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl() ||
holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater() ||
holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater() ||
holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl()) {
return true;
}
return TrustFinalNonStaticFields;
}

View File

@ -65,6 +65,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
_has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods();
_is_hidden = ik->is_hidden();
_is_record = ik->is_record();
_trust_final_fields = ik->trust_final_fields();
_nonstatic_fields = nullptr; // initialized lazily by compute_nonstatic_fields:
_has_injected_fields = -1;
_implementor = nullptr; // we will fill these lazily

View File

@ -59,6 +59,7 @@ private:
bool _has_nonstatic_concrete_methods;
bool _is_hidden;
bool _is_record;
bool _trust_final_fields;
bool _has_trusted_loader;
ciFlags _flags;
@ -207,6 +208,10 @@ public:
return _is_record;
}
bool trust_final_fields() const {
return _trust_final_fields;
}
ciInstanceKlass* get_canonical_holder(int offset);
ciField* get_field_by_offset(int field_offset, bool is_static);
ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static);

View File

@ -943,6 +943,7 @@ public:
_java_lang_Deprecated_for_removal,
_jdk_internal_vm_annotation_AOTSafeClassInitializer,
_method_AOTRuntimeSetup,
_jdk_internal_vm_annotation_TrustFinalFields,
_annotation_LIMIT
};
const Location _location;
@ -1878,6 +1879,11 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
if (!privileged) break; // only allow in privileged code
return _field_Stable;
}
case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_TrustFinalFields_signature): {
if (_location != _in_class) break; // only allow for classes
if (!privileged) break; // only allow in privileged code
return _jdk_internal_vm_annotation_TrustFinalFields;
}
case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Contended_signature): {
if (_location != _in_field && _location != _in_class) {
break; // only allow for fields and classes
@ -1992,6 +1998,9 @@ void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) {
if (has_annotation(_jdk_internal_vm_annotation_AOTSafeClassInitializer)) {
ik->set_has_aot_safe_initializer();
}
if (has_annotation(_jdk_internal_vm_annotation_TrustFinalFields)) {
ik->set_trust_final_fields(true);
}
}
#define MAX_ARGS_SIZE 255

View File

@ -245,10 +245,6 @@ class SerializeClosure;
\
/* Concurrency support */ \
template(java_util_concurrent_locks_AbstractOwnableSynchronizer, "java/util/concurrent/locks/AbstractOwnableSynchronizer") \
template(java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl") \
template(java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater") \
template(java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$LockedUpdater") \
template(java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl") \
template(jdk_internal_vm_annotation_Contended_signature, "Ljdk/internal/vm/annotation/Contended;") \
template(jdk_internal_vm_annotation_ReservedStackAccess_signature, "Ljdk/internal/vm/annotation/ReservedStackAccess;") \
template(jdk_internal_ValueBased_signature, "Ljdk/internal/ValueBased;") \
@ -302,6 +298,7 @@ class SerializeClosure;
template(jdk_internal_misc_Scoped_signature, "Ljdk/internal/misc/ScopedMemoryAccess$Scoped;") \
template(jdk_internal_vm_annotation_IntrinsicCandidate_signature, "Ljdk/internal/vm/annotation/IntrinsicCandidate;") \
template(jdk_internal_vm_annotation_Stable_signature, "Ljdk/internal/vm/annotation/Stable;") \
template(jdk_internal_vm_annotation_TrustFinalFields_signature, "Ljdk/internal/vm/annotation/TrustFinalFields;") \
\
template(jdk_internal_vm_annotation_ChangesCurrentThread_signature, "Ljdk/internal/vm/annotation/ChangesCurrentThread;") \
template(jdk_internal_vm_annotation_JvmtiHideEvents_signature, "Ljdk/internal/vm/annotation/JvmtiHideEvents;") \

View File

@ -353,6 +353,9 @@ class InstanceKlass: public Klass {
int static_oop_field_count() const { return (int)_static_oop_field_count; }
void set_static_oop_field_count(u2 size) { _static_oop_field_count = size; }
bool trust_final_fields() { return _misc_flags.trust_final_fields(); }
void set_trust_final_fields(bool value) { _misc_flags.set_trust_final_fields(value); }
// Java itable
int itable_length() const { return _itable_len; }
void set_itable_length(int len) { _itable_len = len; }

View File

@ -54,6 +54,7 @@ class InstanceKlassFlags {
flag(has_localvariable_table , 1 << 11) /* has localvariable information */ \
flag(has_miranda_methods , 1 << 12) /* True if this class has miranda methods in it's vtable */ \
flag(has_final_method , 1 << 13) /* True if klass has final method */ \
flag(trust_final_fields , 1 << 14) /* All instance final fields in this class should be trusted */ \
/* end of list */
#define IK_FLAGS_ENUM_NAME(name, value) _misc_##name = value,

View File

@ -25,7 +25,7 @@
package java.util;
import jdk.internal.vm.annotation.Stable;
import jdk.internal.vm.annotation.TrustFinalFields;
import java.util.function.Consumer;
import java.util.function.Function;
@ -62,6 +62,7 @@ import java.util.stream.Stream;
* @since 1.8
*/
@jdk.internal.ValueBased
@TrustFinalFields
public final class Optional<T> {
/**
* Common instance for {@code empty()}.
@ -71,7 +72,6 @@ public final class Optional<T> {
/**
* If non-null, the value; if null, indicates no value is present
*/
@Stable
private final T value;
/**

View File

@ -42,6 +42,8 @@ import java.util.function.IntUnaryOperator;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.TrustFinalFields;
import java.lang.invoke.VarHandle;
/**
@ -371,6 +373,7 @@ public abstract class AtomicIntegerFieldUpdater<T> {
/**
* Standard hotspot implementation using intrinsics.
*/
@TrustFinalFields
private static final class AtomicIntegerFieldUpdaterImpl<T>
extends AtomicIntegerFieldUpdater<T> {
private static final Unsafe U = Unsafe.getUnsafe();

View File

@ -42,6 +42,8 @@ import java.util.function.LongUnaryOperator;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.TrustFinalFields;
import java.lang.invoke.VarHandle;
/**
@ -368,6 +370,7 @@ public abstract class AtomicLongFieldUpdater<T> {
return next;
}
@TrustFinalFields
private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;

View File

@ -42,6 +42,8 @@ import java.util.function.UnaryOperator;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.TrustFinalFields;
import java.lang.invoke.VarHandle;
/**
@ -312,6 +314,7 @@ public abstract class AtomicReferenceFieldUpdater<T,V> {
return next;
}
@TrustFinalFields
private static final class AtomicReferenceFieldUpdaterImpl<T,V>
extends AtomicReferenceFieldUpdater<T,V> {
private static final Unsafe U = Unsafe.getUnsafe();

View File

@ -0,0 +1,57 @@
/*
* 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.vm.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/// Indicates all instance final fields declared in the annotated class should
/// be trusted as constants by compilers in `ciField::is_constant`.
///
/// The compiler already treats static final fields and instance final fields in
/// record classes and hidden classes as constant. All classes in select
/// packages (Defined in `trust_final_non_static_fields` in `ciField.cpp`) in
/// the boot class loader also have their instance final fields trusted. This
/// annotation is not necessary in these cases.
///
/// The [Stable] annotation treats fields as constants once they are not the
/// zero or null value. In comparison, a non-stable final instance field
/// trusted by this annotation can treat zero and null values as constants.
///
/// This annotation is suitable when constant treatment of final fields is
/// performance sensitive, yet package-wide final field constant treatment may
/// be at risk from final field modifications such as serialization.
///
/// This annotation is only recognized on classes from the boot and platform
/// class loaders and is ignored elsewhere.
///
/// @since 26
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TrustFinalFields {
}

View File

@ -0,0 +1,63 @@
/*
* 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.
*
* 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 compiler.corelibs;
import java.util.Optional;
import compiler.lib.ir_framework.Check;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.IRNode;
import compiler.lib.ir_framework.Test;
import compiler.lib.ir_framework.TestFramework;
/*
* @test
* @bug 8372696
* @summary Verify constant folding for Optional, both present and absent
* @library /test/lib /
* @run driver ${test.main.class}
*/
public class OptionalFold {
public static void main(String[] args) {
TestFramework.run();
}
// Ensure both present and empty values can fold
static final Optional<Integer> ONE = Optional.of(5), TWO = Optional.empty();
@Test
@IR(failOn = {IRNode.ADD_I})
public int testSum() {
return ONE.orElse(7) + TWO.orElse(12);
}
@Check(test = "testSum")
public void checkTestSum(int res) {
if (res != 5 + 12) {
throw new RuntimeException("incorrect result: " + res);
}
}
}