From 33c9f20bef05239ee016d980dc69a3d583ce8293 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 19 Feb 2026 05:24:08 +0000 Subject: [PATCH] 8377712: ConstantPool of WeakReferenceKey is not deterministic in CDS archive Reviewed-by: liach, kvn --- src/hotspot/share/cds/aotMetaspace.cpp | 2 +- src/hotspot/share/cds/heapShared.cpp | 22 +++++++++++++++++++ src/hotspot/share/cds/heapShared.hpp | 4 +++- .../jdk/internal/util/WeakReferenceKey.java | 16 +++++++++++++- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index 544eaa07a4d..b75d7628aa9 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -1148,7 +1148,7 @@ void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS if (CDSConfig::is_dumping_full_module_graph()) { ClassLoaderDataShared::ensure_module_entry_tables_exist(); ClassLoaderDataShared::build_tables(CHECK); - HeapShared::reset_archived_object_states(CHECK); + HeapShared::prepare_for_archiving(CHECK); } AOTReferenceObjSupport::initialize(CHECK); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index c01e6ded25a..0c0f70eac0a 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -247,6 +247,28 @@ void HeapShared::reset_archived_object_states(TRAPS) { reset_states(boot_loader(), CHECK); } +void HeapShared::ensure_determinism(TRAPS) { + TempNewSymbol class_name = SymbolTable::new_symbol("jdk/internal/util/WeakReferenceKey"); + TempNewSymbol method_name = SymbolTable::new_symbol("ensureDeterministicAOTCache"); + + Klass* weak_ref_key_class = SystemDictionary::resolve_or_fail(class_name, true, CHECK); + precond(weak_ref_key_class != nullptr); + + log_debug(aot)("Calling WeakReferenceKey::ensureDeterministicAOTCache(Object.class)"); + JavaValue result(T_BOOLEAN); + JavaCalls::call_static(&result, + weak_ref_key_class, + method_name, + vmSymbols::void_boolean_signature(), + CHECK); + assert(result.get_jboolean() == false, "sanity"); +} + +void HeapShared::prepare_for_archiving(TRAPS) { + reset_archived_object_states(CHECK); + ensure_determinism(CHECK); +} + HeapShared::ArchivedObjectCache* HeapShared::_archived_object_cache = nullptr; bool HeapShared::is_archived_heap_in_use() { diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index ba17ddda267..2cb330160e4 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -382,8 +382,10 @@ private: static bool walk_one_object(PendingOopStack* stack, int level, KlassSubGraphInfo* subgraph_info, oop orig_obj, oop referrer); - public: static void reset_archived_object_states(TRAPS); + static void ensure_determinism(TRAPS); + public: + static void prepare_for_archiving(TRAPS); static void create_archived_object_cache() { _archived_object_cache = new (mtClass)ArchivedObjectCache(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE); diff --git a/src/java.base/share/classes/jdk/internal/util/WeakReferenceKey.java b/src/java.base/share/classes/jdk/internal/util/WeakReferenceKey.java index 3fe6d6026d7..0b26aa40c0d 100644 --- a/src/java.base/share/classes/jdk/internal/util/WeakReferenceKey.java +++ b/src/java.base/share/classes/jdk/internal/util/WeakReferenceKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -88,4 +88,18 @@ final class WeakReferenceKey extends WeakReference implements ReferenceKey public String toString() { return this.getClass().getCanonicalName() + "#" + System.identityHashCode(this); } + + // WeakReferenceKey.equals() is usually executed in the AOT assembly phase. However, + // in some rare occasions, it's not executed (due to peculiarity of hash code and + // memory addressing??). As a result, the constant pool entries used by + // equals() are not resolved. + // + // The JVM calls ensureDeterministicAOTCache() during the AOT assembly phase to ensure + // that the constant pool entries used by equals() are resolved, so that the + // the JDK's default CDS archives have deterministic contents. + private static boolean ensureDeterministicAOTCache() { + WeakReferenceKey k1 = new WeakReferenceKey<>("1", null); + WeakReferenceKey k2 = new WeakReferenceKey<>("2", null); + return k1.equals(k2); + } }