mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
8372696: Allow boot classes to explicitly opt-in for final field trusting
Reviewed-by: jvernee, jrose, alanb
This commit is contained in:
parent
b42861a2aa
commit
3220c4cb43
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;") \
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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 {
|
||||
}
|
||||
63
test/hotspot/jtreg/compiler/corelibs/OptionalFold.java
Normal file
63
test/hotspot/jtreg/compiler/corelibs/OptionalFold.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user