mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8360163: Replace hard-coded checks with AOTRuntimeSetup and AOTSafeClassInitializer
Reviewed-by: jrose, iklam
This commit is contained in:
parent
d5d311f026
commit
330ee87131
@ -63,6 +63,7 @@ class TypeArrayKlass;
|
||||
// be AOT-initialized:
|
||||
// - If we discover at least one instance of class X, then class X is AOT-initialized (** Note1).
|
||||
// - If AOTClassInitializer::can_archive_initialized_mirror(X) is true, then X is AOT-initialized.
|
||||
// This function checks for the @jdk.internal.vm.annotation.AOTSafeClassInitializer annotation.
|
||||
// - For each AOT-initialized class, we scan all the static fields in its java mirror. This will in
|
||||
// turn discover more Klasses and java heap objects.
|
||||
// - The scanning continues until we reach a steady state.
|
||||
|
||||
@ -37,67 +37,6 @@
|
||||
|
||||
DEBUG_ONLY(InstanceKlass* _aot_init_class = nullptr;)
|
||||
|
||||
// Detector for class names we wish to handle specially.
|
||||
// It is either an exact string match or a string prefix match.
|
||||
class AOTClassInitializer::AllowedSpec {
|
||||
const char* _class_name;
|
||||
bool _is_prefix;
|
||||
int _len;
|
||||
public:
|
||||
AllowedSpec(const char* class_name, bool is_prefix = false)
|
||||
: _class_name(class_name), _is_prefix(is_prefix)
|
||||
{
|
||||
_len = (class_name == nullptr) ? 0 : (int)strlen(class_name);
|
||||
}
|
||||
const char* class_name() { return _class_name; }
|
||||
|
||||
bool matches(Symbol* name, int len) {
|
||||
assert(_class_name != nullptr, "caller resp.");
|
||||
if (_is_prefix) {
|
||||
return len >= _len && name->starts_with(_class_name);
|
||||
} else {
|
||||
return len == _len && name->equals(_class_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Tell if ik has a name that matches one of the given specs.
|
||||
bool AOTClassInitializer::is_allowed(AllowedSpec* specs, InstanceKlass* ik) {
|
||||
Symbol* name = ik->name();
|
||||
int len = name->utf8_length();
|
||||
for (AllowedSpec* s = specs; s->class_name() != nullptr; s++) {
|
||||
if (s->matches(name, len)) {
|
||||
// If a type is included in the tables inside can_archive_initialized_mirror(), we require that
|
||||
// - all super classes must be included
|
||||
// - all super interfaces that have <clinit> must be included.
|
||||
// This ensures that in the production run, we don't run the <clinit> of a supertype but skips
|
||||
// ik's <clinit>.
|
||||
if (ik->java_super() != nullptr) {
|
||||
DEBUG_ONLY(ResourceMark rm);
|
||||
assert(AOTClassInitializer::can_archive_initialized_mirror(ik->java_super()),
|
||||
"super class %s of %s must be aot-initialized", ik->java_super()->external_name(),
|
||||
ik->external_name());
|
||||
}
|
||||
|
||||
Array<InstanceKlass*>* interfaces = ik->local_interfaces();
|
||||
int len = interfaces->length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
InstanceKlass* intf = interfaces->at(i);
|
||||
if (intf->class_initializer() != nullptr) {
|
||||
assert(AOTClassInitializer::can_archive_initialized_mirror(intf),
|
||||
"super interface %s (which has <clinit>) of %s must be aot-initialized", intf->external_name(),
|
||||
ik->external_name());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
|
||||
assert(!ArchiveBuilder::is_active() || !ArchiveBuilder::current()->is_in_buffer_space(ik), "must be source klass");
|
||||
if (!CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
@ -260,74 +199,19 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
|
||||
// because of invokedynamic. They are few enough for now to be
|
||||
// manually tracked. There may be more in the future.
|
||||
|
||||
// IS_PREFIX means that we match all class names that start with a
|
||||
// prefix. Otherwise, it is an exact match, of just one class name.
|
||||
const bool IS_PREFIX = true;
|
||||
|
||||
{
|
||||
static AllowedSpec specs[] = {
|
||||
if (ik == vmClasses::Object_klass()) {
|
||||
// everybody's favorite super
|
||||
{"java/lang/Object"},
|
||||
|
||||
{nullptr}
|
||||
};
|
||||
if (is_allowed(specs, ik)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (CDSConfig::is_dumping_method_handles()) {
|
||||
// This table was created with the help of CDSHeapVerifier.
|
||||
// The minimal list of @AOTSafeClassInitializer was created with the help of CDSHeapVerifier.
|
||||
// Also, some $Holder classes are needed. E.g., Invokers.<clinit> explicitly
|
||||
// initializes Invokers$Holder. Since Invokers.<clinit> won't be executed
|
||||
// at runtime, we need to make sure Invokers$Holder is also aot-inited.
|
||||
//
|
||||
// We hope we can reduce the size of this list over time, and move
|
||||
// the responsibility for identifying such classes into the JDK
|
||||
// code itself. See tracking RFE JDK-8342481.
|
||||
static AllowedSpec indy_specs[] = {
|
||||
{"java/lang/constant/ConstantDescs"},
|
||||
{"java/lang/constant/DynamicConstantDesc"},
|
||||
{"java/lang/invoke/BoundMethodHandle"},
|
||||
{"java/lang/invoke/BoundMethodHandle$Specializer"},
|
||||
{"java/lang/invoke/BoundMethodHandle$Species_", IS_PREFIX},
|
||||
{"java/lang/invoke/ClassSpecializer"},
|
||||
{"java/lang/invoke/ClassSpecializer$", IS_PREFIX},
|
||||
{"java/lang/invoke/DelegatingMethodHandle"},
|
||||
{"java/lang/invoke/DelegatingMethodHandle$Holder"}, // UNSAFE.ensureClassInitialized()
|
||||
{"java/lang/invoke/DirectMethodHandle"},
|
||||
{"java/lang/invoke/DirectMethodHandle$Constructor"},
|
||||
{"java/lang/invoke/DirectMethodHandle$Holder"}, // UNSAFE.ensureClassInitialized()
|
||||
{"java/lang/invoke/Invokers"},
|
||||
{"java/lang/invoke/Invokers$Holder"}, // UNSAFE.ensureClassInitialized()
|
||||
{"java/lang/invoke/LambdaForm"},
|
||||
{"java/lang/invoke/LambdaForm$Holder"}, // UNSAFE.ensureClassInitialized()
|
||||
{"java/lang/invoke/LambdaForm$NamedFunction"},
|
||||
{"java/lang/invoke/LambdaMetafactory"},
|
||||
{"java/lang/invoke/MethodHandle"},
|
||||
{"java/lang/invoke/MethodHandles"},
|
||||
{"java/lang/invoke/SimpleMethodHandle"},
|
||||
{"java/lang/invoke/StringConcatFactory"},
|
||||
{"java/lang/invoke/VarHandleGuards"},
|
||||
{"java/util/Collections"},
|
||||
{"java/util/stream/Collectors"},
|
||||
{"jdk/internal/constant/ConstantUtils"},
|
||||
{"jdk/internal/constant/PrimitiveClassDescImpl"},
|
||||
{"jdk/internal/constant/ReferenceClassDescImpl"},
|
||||
|
||||
// Can't include this, as it will pull in MethodHandleStatics which has many environment
|
||||
// dependencies (on system properties, etc).
|
||||
// MethodHandleStatics is an example of a class that must NOT get the aot-init treatment,
|
||||
// because of its strong reliance on (a) final fields which are (b) environmentally determined.
|
||||
//{"java/lang/invoke/InvokerBytecodeGenerator"},
|
||||
|
||||
{nullptr}
|
||||
};
|
||||
if (is_allowed(indy_specs, ik)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ik->name()->starts_with("java/lang/invoke/MethodHandleImpl")) {
|
||||
if (ik->has_aot_safe_initializer()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -341,17 +225,6 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: currently we have a hard-coded list. We should turn this into
|
||||
// an annotation: @jdk.internal.vm.annotation.RuntimeSetupRequired
|
||||
// See JDK-8342481.
|
||||
bool AOTClassInitializer::is_runtime_setup_required(InstanceKlass* ik) {
|
||||
return ik == vmClasses::Class_klass() ||
|
||||
ik == vmClasses::internal_Unsafe_klass() ||
|
||||
ik == vmClasses::ConcurrentHashMap_klass() ||
|
||||
ik == vmClasses::MethodHandleImpl_klass() ||
|
||||
ik == vmClasses::Reference_klass();
|
||||
}
|
||||
|
||||
void AOTClassInitializer::call_runtime_setup(JavaThread* current, InstanceKlass* ik) {
|
||||
assert(ik->has_aot_initialized_mirror(), "sanity");
|
||||
if (ik->is_runtime_setup_required()) {
|
||||
|
||||
@ -31,15 +31,11 @@
|
||||
class InstanceKlass;
|
||||
|
||||
class AOTClassInitializer : AllStatic {
|
||||
class AllowedSpec;
|
||||
static bool is_allowed(AllowedSpec* specs, InstanceKlass* ik);
|
||||
|
||||
public:
|
||||
// Called by heapShared.cpp to see if src_ik->java_mirror() can be archived in
|
||||
// the initialized state.
|
||||
static bool can_archive_initialized_mirror(InstanceKlass* src_ik);
|
||||
|
||||
static bool is_runtime_setup_required(InstanceKlass* ik);
|
||||
static void call_runtime_setup(JavaThread* current, InstanceKlass* ik);
|
||||
|
||||
// Support for regression testing. Available in debug builds only.
|
||||
|
||||
@ -505,9 +505,6 @@ bool HeapShared::is_archivable_hidden_klass(InstanceKlass* ik) {
|
||||
|
||||
void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) {
|
||||
ik->set_has_aot_initialized_mirror();
|
||||
if (AOTClassInitializer::is_runtime_setup_required(ik)) {
|
||||
ik->set_is_runtime_setup_required();
|
||||
}
|
||||
|
||||
oop orig_mirror;
|
||||
if (RegeneratedClasses::is_regenerated_object(ik)) {
|
||||
|
||||
@ -941,6 +941,8 @@ public:
|
||||
_jdk_internal_ValueBased,
|
||||
_java_lang_Deprecated,
|
||||
_java_lang_Deprecated_for_removal,
|
||||
_jdk_internal_vm_annotation_AOTSafeClassInitializer,
|
||||
_method_AOTRuntimeSetup,
|
||||
_annotation_LIMIT
|
||||
};
|
||||
const Location _location;
|
||||
@ -976,6 +978,8 @@ public:
|
||||
|
||||
void set_stable(bool stable) { set_annotation(_field_Stable); }
|
||||
bool is_stable() const { return has_annotation(_field_Stable); }
|
||||
|
||||
bool has_aot_runtime_setup() const { return has_annotation(_method_AOTRuntimeSetup); }
|
||||
};
|
||||
|
||||
// This class also doubles as a holder for metadata cleanup.
|
||||
@ -1896,6 +1900,16 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
|
||||
case VM_SYMBOL_ENUM_NAME(java_lang_Deprecated): {
|
||||
return _java_lang_Deprecated;
|
||||
}
|
||||
case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_AOTSafeClassInitializer_signature): {
|
||||
if (_location != _in_class) break; // only allow for classes
|
||||
if (!privileged) break; // only allow in privileged code
|
||||
return _jdk_internal_vm_annotation_AOTSafeClassInitializer;
|
||||
}
|
||||
case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_AOTRuntimeSetup_signature): {
|
||||
if (_location != _in_method) break; // only allow for methods
|
||||
if (!privileged) break; // only allow in privileged code
|
||||
return _method_AOTRuntimeSetup;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
@ -1975,6 +1989,9 @@ void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) {
|
||||
m->set_deprecated_for_removal();
|
||||
}
|
||||
}
|
||||
if (has_annotation(_jdk_internal_vm_annotation_AOTSafeClassInitializer)) {
|
||||
ik->set_has_aot_safe_initializer();
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_ARGS_SIZE 255
|
||||
@ -2661,6 +2678,13 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
|
||||
if (is_hidden()) { // Mark methods in hidden classes as 'hidden'.
|
||||
m->set_is_hidden();
|
||||
}
|
||||
if (parsed_annotations.has_aot_runtime_setup()) {
|
||||
if (name != vmSymbols::runtimeSetup() || signature != vmSymbols::void_method_signature() ||
|
||||
!access_flags.is_private() || !access_flags.is_static()) {
|
||||
classfile_parse_error("@AOTRuntimeSetup method must be declared private static void runtimeSetup() for class %s", CHECK_NULL);
|
||||
}
|
||||
_has_aot_runtime_setup_method = true;
|
||||
}
|
||||
|
||||
// Copy annotations
|
||||
copy_method_annotations(m->constMethod(),
|
||||
@ -3978,6 +4002,15 @@ void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) {
|
||||
const jint lh = Klass::instance_layout_helper(ik->size_helper(), true);
|
||||
ik->set_layout_helper(lh);
|
||||
}
|
||||
|
||||
// Propagate the AOT runtimeSetup method discovery
|
||||
if (_has_aot_runtime_setup_method) {
|
||||
ik->set_is_runtime_setup_required();
|
||||
if (log_is_enabled(Info, aot, init)) {
|
||||
ResourceMark rm;
|
||||
log_info(aot, init)("Found @AOTRuntimeSetup class %s", ik->external_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// utility methods for appending an array with check for duplicates
|
||||
@ -5117,8 +5150,47 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
|
||||
check_methods_for_intrinsics(ik, methods);
|
||||
|
||||
// Fill in field values obtained by parse_classfile_attributes
|
||||
if (_parsed_annotations->has_any_annotations()) {
|
||||
if (_parsed_annotations->has_any_annotations())
|
||||
_parsed_annotations->apply_to(ik);
|
||||
|
||||
// AOT-related checks.
|
||||
// Note we cannot check this in general due to instrumentation or module patching
|
||||
if (CDSConfig::is_initing_classes_at_dump_time()) {
|
||||
// Check the aot initialization safe status.
|
||||
// @AOTSafeClassInitializer is used only to support ahead-of-time initialization of classes
|
||||
// in the AOT assembly phase.
|
||||
if (ik->has_aot_safe_initializer()) {
|
||||
// If a type is included in the tables inside can_archive_initialized_mirror(), we require that
|
||||
// - all super classes must be included
|
||||
// - all super interfaces that have <clinit> must be included.
|
||||
// This ensures that in the production run, we don't run the <clinit> of a supertype but skips
|
||||
// ik's <clinit>.
|
||||
if (_super_klass != nullptr) {
|
||||
guarantee_property(_super_klass->has_aot_safe_initializer(),
|
||||
"Missing @AOTSafeClassInitializer in superclass %s for class %s",
|
||||
_super_klass->external_name(),
|
||||
CHECK);
|
||||
}
|
||||
|
||||
int len = _local_interfaces->length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
InstanceKlass* intf = _local_interfaces->at(i);
|
||||
guarantee_property(intf->class_initializer() == nullptr || intf->has_aot_safe_initializer(),
|
||||
"Missing @AOTSafeClassInitializer in superinterface %s for class %s",
|
||||
intf->external_name(),
|
||||
CHECK);
|
||||
}
|
||||
|
||||
if (log_is_enabled(Info, aot, init)) {
|
||||
ResourceMark rm;
|
||||
log_info(aot, init)("Found @AOTSafeClassInitializer class %s", ik->external_name());
|
||||
}
|
||||
} else {
|
||||
// @AOTRuntimeSetup only meaningful in @AOTClassInitializer
|
||||
guarantee_property(!ik->is_runtime_setup_required(),
|
||||
"@AOTRuntimeSetup meaningless in non-@AOTSafeClassInitializer class %s",
|
||||
CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
apply_parsed_class_attributes(ik);
|
||||
@ -5326,6 +5398,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
|
||||
_has_localvariable_table(false),
|
||||
_has_final_method(false),
|
||||
_has_contended_fields(false),
|
||||
_has_aot_runtime_setup_method(false),
|
||||
_has_finalizer(false),
|
||||
_has_empty_finalizer(false),
|
||||
_max_bootstrap_specifier_index(-1) {
|
||||
|
||||
@ -192,6 +192,7 @@ class ClassFileParser {
|
||||
bool _has_localvariable_table;
|
||||
bool _has_final_method;
|
||||
bool _has_contended_fields;
|
||||
bool _has_aot_runtime_setup_method;
|
||||
|
||||
// precomputed flags
|
||||
bool _has_finalizer;
|
||||
|
||||
@ -732,8 +732,10 @@ class SerializeClosure;
|
||||
template(java_lang_invoke_DelegatingMethodHandle_Holder, "java/lang/invoke/DelegatingMethodHandle$Holder") \
|
||||
template(jdk_internal_loader_ClassLoaders, "jdk/internal/loader/ClassLoaders") \
|
||||
template(jdk_internal_misc_CDS, "jdk/internal/misc/CDS") \
|
||||
template(jdk_internal_vm_annotation_AOTSafeClassInitializer_signature, "Ljdk/internal/vm/annotation/AOTSafeClassInitializer;")\
|
||||
template(java_util_concurrent_ConcurrentHashMap, "java/util/concurrent/ConcurrentHashMap") \
|
||||
template(java_util_ArrayList, "java/util/ArrayList") \
|
||||
template(jdk_internal_vm_annotation_AOTRuntimeSetup_signature, "Ljdk/internal/vm/annotation/AOTRuntimeSetup;") \
|
||||
template(runtimeSetup, "runtimeSetup") \
|
||||
template(toFileURL_name, "toFileURL") \
|
||||
template(toFileURL_signature, "(Ljava/lang/String;)Ljava/net/URL;") \
|
||||
|
||||
@ -764,6 +764,14 @@ public:
|
||||
bool has_final_method() const { return _misc_flags.has_final_method(); }
|
||||
void set_has_final_method() { _misc_flags.set_has_final_method(true); }
|
||||
|
||||
// Indicates presence of @AOTSafeClassInitializer. Also see AOTClassInitializer for more details.
|
||||
bool has_aot_safe_initializer() const { return _misc_flags.has_aot_safe_initializer(); }
|
||||
void set_has_aot_safe_initializer() { _misc_flags.set_has_aot_safe_initializer(true); }
|
||||
|
||||
// Indicates @AOTRuntimeSetup private static void runtimeSetup() presence.
|
||||
bool is_runtime_setup_required() const { return _misc_flags.is_runtime_setup_required(); }
|
||||
void set_is_runtime_setup_required() { _misc_flags.set_is_runtime_setup_required(true); }
|
||||
|
||||
// for adding methods, ConstMethod::UNSET_IDNUM means no more ids available
|
||||
inline u2 next_method_idnum();
|
||||
void set_initial_method_idnum(u2 value) { _idnum_allocated_count = value; }
|
||||
|
||||
@ -54,6 +54,8 @@ 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(has_aot_safe_initializer , 1 << 14) /* has @AOTSafeClassInitializer annotation */ \
|
||||
flag(is_runtime_setup_required , 1 << 15) /* has a runtimeSetup method to be called */ \
|
||||
/* end of list */
|
||||
|
||||
#define IK_FLAGS_ENUM_NAME(name, value) _misc_##name = value,
|
||||
|
||||
@ -186,9 +186,6 @@ private:
|
||||
_is_generated_shared_class = 1 << 5,
|
||||
// archived mirror already initialized by AOT-cache assembly: no further need to call <clinit>
|
||||
_has_aot_initialized_mirror = 1 << 6,
|
||||
// If this class has been aot-inititalized, do we need to call its runtimeSetup()
|
||||
// method during the production run?
|
||||
_is_runtime_setup_required = 1 << 7,
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -380,15 +377,6 @@ protected:
|
||||
NOT_CDS(return false;)
|
||||
}
|
||||
|
||||
void set_is_runtime_setup_required() {
|
||||
assert(has_aot_initialized_mirror(), "sanity");
|
||||
CDS_ONLY(_shared_class_flags |= _is_runtime_setup_required;)
|
||||
}
|
||||
bool is_runtime_setup_required() const {
|
||||
CDS_ONLY(return (_shared_class_flags & _is_runtime_setup_required) != 0;)
|
||||
NOT_CDS(return false;)
|
||||
}
|
||||
|
||||
bool is_shared() const { // shadows MetaspaceObj::is_shared)()
|
||||
CDS_ONLY(return (_shared_class_flags & _is_shared_class) != 0;)
|
||||
NOT_CDS(return false;)
|
||||
|
||||
@ -47,7 +47,6 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.RecordComponent;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
@ -79,6 +78,8 @@ import jdk.internal.reflect.CallerSensitiveAdapter;
|
||||
import jdk.internal.reflect.ConstantPool;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.reflect.ReflectionFactory;
|
||||
import jdk.internal.vm.annotation.AOTRuntimeSetup;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
@ -211,6 +212,7 @@ import sun.reflect.annotation.*;
|
||||
* @see java.lang.ClassLoader#defineClass(byte[], int, int)
|
||||
* @since 1.0
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public final class Class<T> implements java.io.Serializable,
|
||||
GenericDeclaration,
|
||||
Type,
|
||||
@ -226,7 +228,9 @@ public final class Class<T> implements java.io.Serializable,
|
||||
runtimeSetup();
|
||||
}
|
||||
|
||||
// Called from JVM when loading an AOT cache
|
||||
/// No significant static final fields; [#resetArchivedStates()] handles
|
||||
/// prevents storing [#reflectionFactory] into AOT image.
|
||||
@AOTRuntimeSetup
|
||||
private static void runtimeSetup() {
|
||||
registerNatives();
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package java.lang;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
|
||||
/**
|
||||
@ -35,6 +36,7 @@ import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
* @see java.lang.Class
|
||||
* @since 1.0
|
||||
*/
|
||||
@AOTSafeClassInitializer // for hierarchy checks
|
||||
public class Object {
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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,6 +28,7 @@ import jdk.internal.constant.ClassOrInterfaceDescImpl;
|
||||
import jdk.internal.constant.ConstantUtils;
|
||||
import jdk.internal.constant.MethodTypeDescImpl;
|
||||
import jdk.internal.constant.PrimitiveClassDescImpl;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
|
||||
import java.lang.Enum.EnumDesc;
|
||||
import java.lang.invoke.CallSite;
|
||||
@ -56,6 +57,7 @@ import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC;
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public final class ConstantDescs {
|
||||
// No instances
|
||||
private ConstantDescs() { }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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,8 @@ import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.CD_Class;
|
||||
import static java.lang.constant.ConstantDescs.CD_VarHandle;
|
||||
import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
|
||||
@ -56,6 +58,7 @@ import static jdk.internal.constant.ConstantUtils.validateMemberName;
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
@AOTSafeClassInitializer // for PrimitiveClassDescImpl
|
||||
public abstract non-sealed class DynamicConstantDesc<T>
|
||||
implements ConstantDesc {
|
||||
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -44,6 +45,7 @@ import static java.lang.invoke.MethodHandleStatics.uncaughtException;
|
||||
*
|
||||
* All bound arguments are encapsulated in dedicated species.
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
/*non-public*/
|
||||
abstract non-sealed class BoundMethodHandle extends MethodHandle {
|
||||
|
||||
@ -233,6 +235,7 @@ abstract non-sealed class BoundMethodHandle extends MethodHandle {
|
||||
// concrete BMH classes required to close bootstrap loops
|
||||
//
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
private // make it private to force users to access the enclosing class first
|
||||
static final class Species_L extends BoundMethodHandle {
|
||||
|
||||
@ -312,6 +315,7 @@ abstract non-sealed class BoundMethodHandle extends MethodHandle {
|
||||
// BMH species meta-data
|
||||
//
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
/*non-public*/
|
||||
static final class SpeciesData
|
||||
extends ClassSpecializer<BoundMethodHandle, String, SpeciesData>.SpeciesData {
|
||||
@ -402,6 +406,7 @@ abstract non-sealed class BoundMethodHandle extends MethodHandle {
|
||||
Species_L.BMH_SPECIES = BoundMethodHandle.SPECIALIZER.findSpecies("L");
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
/*non-public*/
|
||||
static final class Specializer
|
||||
extends ClassSpecializer<BoundMethodHandle, String, SpeciesData> {
|
||||
|
||||
@ -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
|
||||
@ -47,6 +47,7 @@ import jdk.internal.constant.ClassOrInterfaceDescImpl;
|
||||
import jdk.internal.constant.ConstantUtils;
|
||||
import jdk.internal.constant.MethodTypeDescImpl;
|
||||
import jdk.internal.loader.BootLoader;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.BytecodeName;
|
||||
import sun.invoke.util.Wrapper;
|
||||
@ -64,11 +65,15 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
* @param <K> key which identifies individual specializations.
|
||||
* @param <S> species data type.
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
/*non-public*/
|
||||
abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesData> {
|
||||
|
||||
private static final ClassDesc CD_LambdaForm = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;");
|
||||
private static final ClassDesc CD_BoundMethodHandle = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/BoundMethodHandle;");
|
||||
private static final RuntimeVisibleAnnotationsAttribute AOT_SAFE_ANNOTATION = RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(ConstantUtils.referenceClassDesc(AOTSafeClassInitializer.class))
|
||||
);
|
||||
private static final RuntimeVisibleAnnotationsAttribute STABLE_ANNOTATION = RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(ConstantUtils.referenceClassDesc(Stable.class))
|
||||
);
|
||||
@ -233,6 +238,7 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
|
||||
* it would appear that a shorter species could serve as a supertype of a
|
||||
* longer one which extends it.
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
abstract class SpeciesData {
|
||||
// Bootstrapping requires circular relations Class -> SpeciesData -> Class
|
||||
// Therefore, we need non-final links in the chain. Use @Stable fields.
|
||||
@ -469,6 +475,7 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
|
||||
* Code generation support for instances.
|
||||
* Subclasses can modify the behavior.
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
class Factory {
|
||||
/**
|
||||
* Constructs a factory.
|
||||
@ -624,6 +631,7 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
|
||||
clb.withFlags(ACC_FINAL | ACC_SUPER)
|
||||
.withSuperclass(superClassDesc)
|
||||
.with(SourceFileAttribute.of(classDesc.displayName()))
|
||||
.with(AOT_SAFE_ANNOTATION)
|
||||
|
||||
// emit static types and BMH_SPECIES fields
|
||||
.withField(sdFieldName, CD_SPECIES_DATA, new Consumer<>() {
|
||||
|
||||
@ -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
|
||||
@ -26,6 +26,9 @@
|
||||
package java.lang.invoke;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
|
||||
import static java.lang.invoke.LambdaForm.*;
|
||||
import static java.lang.invoke.LambdaForm.Kind.*;
|
||||
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
||||
@ -36,6 +39,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
|
||||
* The delegating MH itself can hold extra "intentions" beyond the simple behavior.
|
||||
* @author jrose
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
/*non-public*/
|
||||
abstract sealed class DelegatingMethodHandle extends MethodHandle
|
||||
permits MethodHandleImpl.AsVarargsCollector,
|
||||
@ -193,5 +197,6 @@ abstract sealed class DelegatingMethodHandle extends MethodHandle
|
||||
}
|
||||
|
||||
/* Placeholder class for DelegatingMethodHandles generated ahead of time */
|
||||
@AOTSafeClassInitializer
|
||||
final class Holder {}
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ package java.lang.invoke;
|
||||
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.ValueConversions;
|
||||
@ -49,6 +50,7 @@ import static java.lang.invoke.MethodTypeForm.*;
|
||||
* to a class member.
|
||||
* @author jrose
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
sealed class DirectMethodHandle extends MethodHandle {
|
||||
final MemberName member;
|
||||
final boolean crackable;
|
||||
@ -466,6 +468,7 @@ sealed class DirectMethodHandle extends MethodHandle {
|
||||
}
|
||||
|
||||
/** This subclass handles constructor references. */
|
||||
@AOTSafeClassInitializer
|
||||
static final class Constructor extends DirectMethodHandle {
|
||||
final MemberName initMethod;
|
||||
final Class<?> instanceClass;
|
||||
@ -937,5 +940,6 @@ sealed class DirectMethodHandle extends MethodHandle {
|
||||
}
|
||||
|
||||
/* Placeholder class for DirectMethodHandles generated ahead of time */
|
||||
@AOTSafeClassInitializer
|
||||
final class Holder {}
|
||||
}
|
||||
|
||||
@ -25,9 +25,12 @@
|
||||
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
import java.lang.classfile.Annotation;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import java.lang.classfile.attribute.SourceFileAttribute;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.util.ArrayList;
|
||||
@ -67,6 +70,7 @@ class GenerateJLIClassesHelper {
|
||||
static final String INVOKERS_HOLDER = "java/lang/invoke/Invokers$Holder";
|
||||
static final String INVOKERS_HOLDER_CLASS_NAME = INVOKERS_HOLDER.replace('/', '.');
|
||||
static final String BMH_SPECIES_PREFIX = "java.lang.invoke.BoundMethodHandle$Species_";
|
||||
static final Annotation AOT_SAFE_ANNOTATION = Annotation.of(AOTSafeClassInitializer.class.describeConstable().orElseThrow());
|
||||
|
||||
static class HolderClassBuilder {
|
||||
|
||||
@ -562,6 +566,7 @@ class GenerateJLIClassesHelper {
|
||||
return ClassFile.of().build(ClassDesc.ofInternalName(className), clb -> {
|
||||
clb.withFlags(ACC_PRIVATE | ACC_FINAL | ACC_SUPER)
|
||||
.withSuperclass(InvokerBytecodeGenerator.INVOKER_SUPER_DESC)
|
||||
.with(RuntimeVisibleAnnotationsAttribute.of(AOT_SAFE_ANNOTATION))
|
||||
.with(SourceFileAttribute.of(className.substring(className.lastIndexOf('/') + 1)));
|
||||
for (int i = 0; i < forms.length; i++) {
|
||||
new InvokerBytecodeGenerator(className, names[i], forms[i], forms[i].methodType()).addMethod(clb, false);
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.invoke.MhUtil;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.DontInline;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Hidden;
|
||||
@ -43,6 +44,7 @@ import static java.lang.invoke.LambdaForm.Kind.*;
|
||||
* Construction and caching of often-used invokers.
|
||||
* @author jrose
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
class Invokers {
|
||||
// exact type (sans leading target MH) for the outgoing call
|
||||
private final MethodType targetType;
|
||||
@ -696,5 +698,6 @@ class Invokers {
|
||||
}
|
||||
|
||||
/* Placeholder class for Invokers generated ahead of time */
|
||||
@AOTSafeClassInitializer
|
||||
final class Holder {}
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ package java.lang.invoke;
|
||||
|
||||
import java.lang.classfile.TypeKind;
|
||||
import jdk.internal.perf.PerfCounter;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.DontInline;
|
||||
import jdk.internal.vm.annotation.Hidden;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
@ -122,6 +123,7 @@ import static java.lang.invoke.MethodHandleStatics.*;
|
||||
* <p>
|
||||
* @author John Rose, JSR 292 EG
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
class LambdaForm {
|
||||
final int arity;
|
||||
final int result;
|
||||
@ -1032,6 +1034,7 @@ class LambdaForm {
|
||||
return false;
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
static class NamedFunction {
|
||||
final MemberName member;
|
||||
private @Stable MethodHandle resolvedHandle;
|
||||
@ -1728,6 +1731,7 @@ class LambdaForm {
|
||||
}
|
||||
|
||||
/* Placeholder class for identity and constant forms generated ahead of time */
|
||||
@AOTSafeClassInitializer
|
||||
final class Holder {}
|
||||
|
||||
// The following hack is necessary in order to suppress TRACE_INTERPRETER
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 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
|
||||
@ -30,6 +30,8 @@ import java.util.Arrays;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
|
||||
/**
|
||||
* <p>Methods to facilitate the creation of simple "function objects" that
|
||||
* implement one or more interfaces by delegation to a provided {@link MethodHandle},
|
||||
@ -247,6 +249,7 @@ import java.util.Objects;
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public final class LambdaMetafactory {
|
||||
|
||||
private LambdaMetafactory() {}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 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,7 @@ package java.lang.invoke;
|
||||
|
||||
|
||||
import jdk.internal.loader.ClassLoaders;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.DontInline;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
@ -442,6 +443,7 @@ mh.invokeExact(System.out, "Hello, world.");
|
||||
* @author John Rose, JSR 292 EG
|
||||
* @since 1.7
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public abstract sealed class MethodHandle implements Constable
|
||||
permits NativeMethodHandle, DirectMethodHandle,
|
||||
DelegatingMethodHandle, BoundMethodHandle {
|
||||
|
||||
@ -33,6 +33,8 @@ import jdk.internal.constant.MethodTypeDescImpl;
|
||||
import jdk.internal.foreign.abi.NativeEntryPoint;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.vm.annotation.AOTRuntimeSetup;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Hidden;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
@ -72,6 +74,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
* Trusted implementation code for MethodHandle.
|
||||
* @author jrose
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
/*non-public*/
|
||||
abstract class MethodHandleImpl {
|
||||
|
||||
@ -158,6 +161,7 @@ abstract class MethodHandleImpl {
|
||||
return newInternalError("should not reach here (unmatched ArrayAccess: " + a + ")");
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
static final class ArrayAccessor {
|
||||
/// Support for array element and length access
|
||||
static final int GETTER_INDEX = 0, SETTER_INDEX = 1, LENGTH_INDEX = 2, INDEX_LIMIT = 3;
|
||||
@ -453,6 +457,7 @@ abstract class MethodHandleImpl {
|
||||
return new AsVarargsCollector(target, arrayType);
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
static final class AsVarargsCollector extends DelegatingMethodHandle {
|
||||
private final MethodHandle target;
|
||||
private final Class<?> arrayType;
|
||||
@ -675,6 +680,7 @@ abstract class MethodHandleImpl {
|
||||
DONT_INLINE_THRESHOLD);
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
private static final class Makers {
|
||||
/** Constructs reinvoker lambda form which block inlining during JIT-compilation for a particular method handle */
|
||||
static final Function<MethodHandle, LambdaForm> PRODUCE_BLOCK_INLINING_FORM = new Function<MethodHandle, LambdaForm>() {
|
||||
@ -710,6 +716,7 @@ abstract class MethodHandleImpl {
|
||||
* Behavior in counting and non-counting states is determined by lambda forms produced by
|
||||
* countingFormProducer & nonCountingFormProducer respectively.
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
static final class CountingWrapper extends DelegatingMethodHandle {
|
||||
private final MethodHandle target;
|
||||
private int count;
|
||||
@ -1035,6 +1042,7 @@ abstract class MethodHandleImpl {
|
||||
|
||||
// Put the whole mess into its own nested class.
|
||||
// That way we can lazily load the code and set up the constants.
|
||||
@AOTSafeClassInitializer
|
||||
private static class BindCaller {
|
||||
|
||||
private static final ClassDesc CD_Object_array = ConstantUtils.CD_Object_array;
|
||||
@ -1143,6 +1151,7 @@ abstract class MethodHandleImpl {
|
||||
return BindCaller.CV_makeInjectedInvoker.get(caller).reflectInvoker();
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
private static final class InjectedInvokerHolder {
|
||||
private final Class<?> invokerClass;
|
||||
// lazily resolved and cached DMH(s) of invoke_V methods
|
||||
@ -1285,6 +1294,7 @@ abstract class MethodHandleImpl {
|
||||
}
|
||||
|
||||
/** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
|
||||
@AOTSafeClassInitializer
|
||||
static final class WrappedMember extends DelegatingMethodHandle {
|
||||
private final MethodHandle target;
|
||||
private final MemberName member;
|
||||
@ -1348,6 +1358,7 @@ abstract class MethodHandleImpl {
|
||||
|
||||
/** Mark arbitrary method handle as intrinsic.
|
||||
* InvokerBytecodeGenerator uses this info to produce more efficient bytecode shape. */
|
||||
@AOTSafeClassInitializer
|
||||
static final class IntrinsicMethodHandle extends DelegatingMethodHandle {
|
||||
private final MethodHandle target;
|
||||
private final Intrinsic intrinsicName;
|
||||
@ -1528,7 +1539,7 @@ abstract class MethodHandleImpl {
|
||||
runtimeSetup();
|
||||
}
|
||||
|
||||
// Also called from JVM when loading an AOT cache
|
||||
@AOTRuntimeSetup
|
||||
private static void runtimeSetup() {
|
||||
SharedSecrets.setJavaLangInvokeAccess(new JavaLangInvokeAccess() {
|
||||
@Override
|
||||
@ -1778,6 +1789,7 @@ abstract class MethodHandleImpl {
|
||||
return lform.editor().noteLoopLocalTypesForm(BOXED_ARGS, localVarTypes);
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
static class LoopClauses {
|
||||
@Stable final MethodHandle[][] clauses;
|
||||
LoopClauses(MethodHandle[][] clauses) {
|
||||
@ -2105,6 +2117,7 @@ abstract class MethodHandleImpl {
|
||||
}
|
||||
|
||||
// use a wrapper because we need this array to be @Stable
|
||||
@AOTSafeClassInitializer
|
||||
static class CasesHolder {
|
||||
@Stable
|
||||
final MethodHandle[] cases;
|
||||
@ -2134,6 +2147,7 @@ abstract class MethodHandleImpl {
|
||||
return mh;
|
||||
}
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
private static class TableSwitchCacheKey {
|
||||
private static final Map<TableSwitchCacheKey, LambdaForm> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
@ -32,6 +32,7 @@ import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.CallerSensitiveAdapter;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.util.ClassFileDumper;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.ValueConversions;
|
||||
@ -83,6 +84,7 @@ import static java.lang.invoke.MethodType.methodType;
|
||||
* @author John Rose, JSR 292 EG
|
||||
* @since 1.7
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public final class MethodHandles {
|
||||
|
||||
private MethodHandles() { } // do not instantiate
|
||||
|
||||
@ -25,17 +25,16 @@
|
||||
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import static java.lang.invoke.LambdaForm.BasicType.*;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
|
||||
/**
|
||||
* A method handle whose behavior is determined only by its LambdaForm.
|
||||
* Access to SimpleMethodHandle should ensure BoundMethodHandle is initialized
|
||||
* first.
|
||||
* @author jrose
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
final class SimpleMethodHandle extends BoundMethodHandle {
|
||||
|
||||
private SimpleMethodHandle(MethodType type, LambdaForm form) {
|
||||
|
||||
@ -35,6 +35,7 @@ import jdk.internal.misc.VM;
|
||||
import jdk.internal.util.ClassFileDumper;
|
||||
import jdk.internal.util.ReferenceKey;
|
||||
import jdk.internal.util.ReferencedKeyMap;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
@ -116,6 +117,7 @@ import static java.lang.invoke.MethodType.methodType;
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public final class StringConcatFactory {
|
||||
private static final int HIGH_ARITY_THRESHOLD;
|
||||
private static final int CACHE_THRESHOLD;
|
||||
|
||||
@ -24,10 +24,12 @@
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Hidden;
|
||||
|
||||
// This class is auto-generated by java.lang.invoke.VarHandles$GuardMethodGenerator. Do not edit.
|
||||
@AOTSafeClassInitializer
|
||||
final class VarHandleGuards {
|
||||
|
||||
@ForceInline
|
||||
|
||||
@ -746,12 +746,14 @@ final class VarHandles {
|
||||
// public static void main(String[] args) {
|
||||
// System.out.println("package java.lang.invoke;");
|
||||
// System.out.println();
|
||||
// System.out.println("import jdk.internal.vm.annotation.AOTSafeClassInitializer;");
|
||||
// System.out.println("import jdk.internal.vm.annotation.ForceInline;");
|
||||
// System.out.println("import jdk.internal.vm.annotation.Hidden;");
|
||||
// System.out.println();
|
||||
// System.out.println("// This class is auto-generated by " +
|
||||
// GuardMethodGenerator.class.getName() +
|
||||
// ". Do not edit.");
|
||||
// System.out.println("@AOTSafeClassInitializer");
|
||||
// System.out.println("final class VarHandleGuards {");
|
||||
//
|
||||
// System.out.println();
|
||||
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package java.lang.ref;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTRuntimeSetup;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
import jdk.internal.access.JavaLangRefAccess;
|
||||
@ -41,7 +43,7 @@ import jdk.internal.access.SharedSecrets;
|
||||
* @since 1.2
|
||||
* @sealedGraph
|
||||
*/
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
public abstract sealed class Reference<@jdk.internal.RequiresIdentity T>
|
||||
permits PhantomReference, SoftReference, WeakReference, FinalReference {
|
||||
|
||||
@ -292,7 +294,7 @@ public abstract sealed class Reference<@jdk.internal.RequiresIdentity T>
|
||||
runtimeSetup();
|
||||
}
|
||||
|
||||
// Also called from JVM when loading an AOT cache
|
||||
@AOTRuntimeSetup
|
||||
private static void runtimeSetup() {
|
||||
// provide access in SharedSecrets
|
||||
SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
|
||||
|
||||
@ -30,6 +30,8 @@ import java.util.function.Consumer;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
|
||||
/**
|
||||
* This class provides a skeletal implementation of the {@code Map}
|
||||
* interface, to minimize the effort required to implement this interface.
|
||||
@ -68,7 +70,7 @@ import java.util.function.Predicate;
|
||||
* @see Collection
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
public abstract class AbstractMap<K,V> implements Map<K,V> {
|
||||
/**
|
||||
* Sole constructor. (For invocation by subclass constructors, typically
|
||||
|
||||
@ -42,6 +42,7 @@ import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
|
||||
/**
|
||||
* This class consists exclusively of static methods that operate on or return
|
||||
@ -82,6 +83,7 @@ import jdk.internal.access.SharedSecrets;
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
public final class Collections {
|
||||
// Suppresses default constructor, ensuring non-instantiability.
|
||||
private Collections() {
|
||||
|
||||
@ -70,6 +70,8 @@ import java.util.function.ToLongFunction;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import jdk.internal.vm.annotation.AOTRuntimeSetup;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
/**
|
||||
@ -263,6 +265,7 @@ import jdk.internal.vm.annotation.Stable;
|
||||
* @param <K> the type of keys maintained by this map
|
||||
* @param <V> the type of mapped values
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
implements ConcurrentMap<K,V>, Serializable {
|
||||
private static final long serialVersionUID = 7249069246763182397L;
|
||||
@ -602,7 +605,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
runtimeSetup();
|
||||
}
|
||||
|
||||
// Called from JVM when loading an AOT cache.
|
||||
@AOTRuntimeSetup
|
||||
private static void runtimeSetup() {
|
||||
NCPU = Runtime.getRuntime().availableProcessors();
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@ import java.util.function.ToIntFunction;
|
||||
import java.util.function.ToLongFunction;
|
||||
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
|
||||
/**
|
||||
* Implementations of {@link Collector} that implement various useful reduction
|
||||
@ -103,6 +104,7 @@ import jdk.internal.access.SharedSecrets;
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
@AOTSafeClassInitializer
|
||||
public final class Collectors {
|
||||
|
||||
static final Set<Collector.Characteristics> CH_CONCURRENT_ID
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -24,6 +24,7 @@
|
||||
*/
|
||||
package jdk.internal.constant;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
@ -41,6 +42,7 @@ import static jdk.internal.constant.PrimitiveClassDescImpl.*;
|
||||
/**
|
||||
* Helper methods for the implementation of {@code java.lang.constant}.
|
||||
*/
|
||||
@AOTSafeClassInitializer // initialization dependency of PrimitiveClassDescImpl
|
||||
public final class ConstantUtils {
|
||||
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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
|
||||
@ -29,6 +29,7 @@ import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
@ -38,6 +39,7 @@ import static java.util.Objects.requireNonNull;
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for the class
|
||||
* constant corresponding to a primitive type (e.g., {@code int.class}).
|
||||
*/
|
||||
@AOTSafeClassInitializer // identity-sensitive static final fields
|
||||
public final class PrimitiveClassDescImpl
|
||||
extends DynamicConstantDesc<Class<?>> implements ClassDesc {
|
||||
|
||||
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package jdk.internal.misc;
|
||||
|
||||
import jdk.internal.vm.annotation.AOTRuntimeSetup;
|
||||
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
import sun.nio.Cleaner;
|
||||
@ -52,7 +54,7 @@ import static jdk.internal.misc.UnsafeConstants.*;
|
||||
* @author John R. Rose
|
||||
* @see #getUnsafe
|
||||
*/
|
||||
|
||||
@AOTSafeClassInitializer
|
||||
public final class Unsafe {
|
||||
|
||||
private static native void registerNatives();
|
||||
@ -60,7 +62,9 @@ public final class Unsafe {
|
||||
runtimeSetup();
|
||||
}
|
||||
|
||||
// Called from JVM when loading an AOT cache
|
||||
/// BASE_OFFSET, INDEX_SCALE, and ADDRESS_SIZE fields are equivalent if the
|
||||
/// AOT initialized heap is reused, so just register natives
|
||||
@AOTRuntimeSetup
|
||||
private static void runtimeSetup() {
|
||||
registerNatives();
|
||||
}
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 that if the enclosing class or interface is present in the AOT
|
||||
/// cache in the AOT-initialized state, the annotated method must be executed
|
||||
/// before bootstrap phase 3 (that is, before [System#initPhase3]).
|
||||
///
|
||||
/// The annotated method must be declared `private` and `static`, must be named
|
||||
/// `runtimeSetup`, and must have no arguments or return value. The enclosing
|
||||
/// class must be annotated with [AOTSafeClassInitializer], meaning that it is
|
||||
/// allowed to be stored in the AOT-initialized state.
|
||||
///
|
||||
/// The annotated method will be executed if and only if the class was loaded
|
||||
/// in the AOT-initialized state from the AOT cache.
|
||||
///
|
||||
/// The author of the class is responsible for deciding whether some or all of
|
||||
/// a class's initialization state should be re-initialized in any way. In all
|
||||
/// cases, the static initializer (`<clinit>` method) of any given class or
|
||||
/// interface is run at most once, either in the assembly phase (only for an
|
||||
/// AOT-initialized class) or in the production run.
|
||||
///
|
||||
/// After a `static` `final` field is assigned a value in an AOT-initialized
|
||||
/// class, its value may never be changed, as such values are always immutable
|
||||
/// runtime constants. (...Barring `System.out` and its two siblings.)
|
||||
/// Rarely, a `static` field may require differing values in the assembly phase
|
||||
/// for an AOT cache, and for the production run. Such variables must be
|
||||
/// marked non-`final`, and should be adjusted by the `runtimeSetup` method.
|
||||
/// Full constant folding (as if with a `final` field) may usually be recovered
|
||||
/// by also marking the field as [Stable]. That annotation instructs the JIT
|
||||
/// to perform constant folding, and _only_ during the production run, after
|
||||
/// `runtimeSetup` has had a chance to give the field its "finally final"
|
||||
/// value.
|
||||
///
|
||||
/// A related method is `resetArchivedStates`, which allows special handling of
|
||||
/// an AOT-initialized class, at the end of the assembly phase run which builds
|
||||
/// an AOT cache. The `resetArchivedStates` may "tear down" state that should
|
||||
/// not be stored in the AOT cache, which the `runtimeSetup` method may then
|
||||
/// "build up again" as the production run begins. This additional method is
|
||||
/// currently only used by [Class] to reset a cache field, but it may be
|
||||
/// expanded to other classes and interfaces later on, using more
|
||||
/// annotation-driven logic.
|
||||
///
|
||||
/// The logic in `classFileParser.cpp` performs checks on the annotated method: If the
|
||||
/// annotated method's signature differs from that described above, or if (during the
|
||||
/// assembly phase) the class is not marked to have an AOT-safe initializer, a
|
||||
/// [ClassFormatError] will be thrown.
|
||||
///
|
||||
/// This annotation is only recognized on privileged code and is ignored elsewhere.
|
||||
///
|
||||
/// @since 26
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface AOTRuntimeSetup {
|
||||
}
|
||||
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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 that the static initializer of this class or interface
|
||||
/// (its `<clinit>` method) is allowed to be _AOT-initialized_,
|
||||
/// because its author considers it safe to execute during the AOT
|
||||
/// assembly phase.
|
||||
///
|
||||
/// This annotation directs the VM to expect that normal execution of Java code
|
||||
/// during the assembly phase could trigger initialization of this class,
|
||||
/// and if that happens, to store the resulting static field values in the
|
||||
/// AOT cache. (These fields happen to be allocated in the `Class` mirror.)
|
||||
///
|
||||
/// During the production run, the static initializer (`<clinit>`) of
|
||||
/// this class or interface will not be executed, if it was already
|
||||
/// executed during the assembling of the AOT being used to start the
|
||||
/// production run. In that case the resulting static field states
|
||||
/// (within the `Class` mirror) were already stored in the AOT cache.
|
||||
///
|
||||
/// Currently, this annotation is used mainly for supporting AOT
|
||||
/// linking of APIs, including bootstrap methods, in the
|
||||
/// `java.lang.invoke` package.
|
||||
///
|
||||
/// In more detail, the AOT assembly phase performs the following:
|
||||
///
|
||||
/// 1. It loads and links (but does not initialize) the classes that were loaded
|
||||
/// during the application's training run.
|
||||
/// 2. During linking of these classes, it resolves their constant pool
|
||||
/// entries, when it is safe and beneficial to do so.
|
||||
/// 3. As part of those resolutions, bootstrap methods may be called and may
|
||||
/// create graphs of Java objects to support linkage states.
|
||||
/// 4. Every object within those graphs must have its class AOT-initialized,
|
||||
/// along with every relevant superclass and implemented interface, along
|
||||
/// with classes for every object created during the course of static
|
||||
/// initialization (running `<clinit>` for each such class or interface).
|
||||
///
|
||||
/// Thus, in order to determine that a class or interface _X_ is safe to
|
||||
/// AOT-initialize requires evaluating every other class or interface _Y_ that
|
||||
/// the `<clinit>` of _X_ will initialize (during AOT cache assembly), and
|
||||
/// ensuring that each such _Y_ is (recursively) safe to AOT-initialize.
|
||||
///
|
||||
/// For example, an AOT-resolved constant pool entry for an invokedynamic or
|
||||
/// invokehandle bytecode can have direct or indirect references to Java objects.
|
||||
/// To ensure the correctness of the AOT-resolved constant pool entrties, the VM
|
||||
/// must AOT-initialize the classes of such Java objects.
|
||||
///
|
||||
/// In addition, such Java objects may have references to static fields whose
|
||||
/// object identity is important. For example, `PrimitiveClassDescImpl::CD_void`.
|
||||
/// To ensure correctness, we must also store classes like `PrimitiveClassDescImpl`
|
||||
/// in the initialized state. The VM requires implementor to manually annotate
|
||||
/// such classes with `@AOTSafeClassInitializer`.
|
||||
///
|
||||
/// There is one more requirement for a class to be safe for
|
||||
/// AOT initialization, and that is compatibility with all eventual production
|
||||
/// runs. The state of an AOT-initialized class _X_ must not contain any data
|
||||
/// (anything reachable from _X_) that is incompatible with the eventual
|
||||
/// production run.
|
||||
///
|
||||
/// In general, if some sort of computed datum, environmental setting, or
|
||||
/// variable behavior may differ between the AOT assembly phase and the
|
||||
/// production run, it may not be immutably bound to _X_, if _X_ is to be
|
||||
/// marked AOT-initialized. Here are specific examples:
|
||||
///
|
||||
/// - The value of an environment string (if it may differ in the production run).
|
||||
///
|
||||
/// - A transient configuration parameter specific to this VM run, such as
|
||||
/// wall clock time, process ID, host name, temporary directory names, etc.
|
||||
///
|
||||
/// - A random seed or key that may need to be re-sampled at production
|
||||
/// startup.
|
||||
///
|
||||
/// What is more, if the initialization of _X_ computes with some value _V_
|
||||
/// obtained from some other class _Y_, _Y_ should also be safe for AOT
|
||||
/// initialization, if there is any way for _X_ to detect a mismatch between
|
||||
/// the version of _V_ produced at AOT time, and the version of _V_ produced in
|
||||
/// the production run. Specifically, if _V_ has an object identity, _X_
|
||||
/// should not test that identity (compare it against another or get its
|
||||
/// hashcode) unless _Y_ is also marked for AOT initialization.
|
||||
///
|
||||
/// Thus, to support AOT-time linkage, a class _X_ should be marked for (possible)
|
||||
/// AOT initialization whenever objects it creates (such as `MethodHandle`s)
|
||||
/// may be required to execute a `java.lang.invoke` API request, or (more
|
||||
/// remotely) if the execution of such an API touches _X_ for initialization,
|
||||
/// or even if such an API request is in any way sensitive to values stored in
|
||||
/// the fields of _X_, even if the sensitivity is a simple reference identity
|
||||
/// test. As noted above, all supertypes of _X_ must also have the
|
||||
/// `@AOTSafeClassInitializer` annotation, and must also be safe for AOT
|
||||
/// initialization.
|
||||
///
|
||||
/// The author of an AOT-initialized class may elect to patch some states at
|
||||
/// production startup, using an [AOTRuntimeSetup] method, as long as the
|
||||
/// pre-patched field values (present during AOT assembly) are determined to be
|
||||
/// compatible with the post-patched values that apply to the production run.
|
||||
///
|
||||
/// In the assembly phase, `classFileParser.cpp` performs checks on the annotated
|
||||
/// classes, to ensure all supertypes of this class that must be initialized when
|
||||
/// this class is initialized have the `@AOTSafeClassInitializer` annotation.
|
||||
/// Otherwise, a [ClassFormatError] will be thrown. (This assembly phase restriction
|
||||
/// allows module patching and instrumentation to work on annotated classes when
|
||||
/// AOT is not enabled)
|
||||
///
|
||||
/// This annotation is only recognized on privileged code and is ignored elsewhere.
|
||||
///
|
||||
/// @since 26
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface AOTSafeClassInitializer {
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user