Skip to content

Commit 68b1b94

Browse files
committed
8344904: Interned strings in old classes are not stored in CDS archive
Reviewed-by: dholmes, ccheung
1 parent 1997e89 commit 68b1b94

File tree

5 files changed

+153
-11
lines changed

5 files changed

+153
-11
lines changed

src/hotspot/share/cds/metaspaceShared.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -1014,9 +1014,7 @@ void VM_PopulateDumpSharedSpace::dump_java_heap_objects(GrowableArray<Klass*>* k
10141014
Klass* k = klasses->at(i);
10151015
if (k->is_instance_klass()) {
10161016
InstanceKlass* ik = InstanceKlass::cast(k);
1017-
if (ik->is_linked()) {
1018-
ik->constants()->add_dumped_interned_strings();
1019-
}
1017+
ik->constants()->add_dumped_interned_strings();
10201018
}
10211019
}
10221020
if (_extra_interned_strings != nullptr) {

src/hotspot/share/oops/constantPool.cpp

+30-8
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include "oops/array.hpp"
5454
#include "oops/constantPool.inline.hpp"
5555
#include "oops/cpCache.inline.hpp"
56+
#include "oops/fieldStreams.inline.hpp"
5657
#include "oops/instanceKlass.hpp"
5758
#include "oops/klass.inline.hpp"
5859
#include "oops/objArrayKlass.hpp"
@@ -61,6 +62,7 @@
6162
#include "oops/typeArrayOop.inline.hpp"
6263
#include "prims/jvmtiExport.hpp"
6364
#include "runtime/atomic.hpp"
65+
#include "runtime/fieldDescriptor.inline.hpp"
6466
#include "runtime/handles.inline.hpp"
6567
#include "runtime/init.hpp"
6668
#include "runtime/javaCalls.hpp"
@@ -403,18 +405,38 @@ void ConstantPool::find_required_hidden_classes() {
403405
}
404406

405407
void ConstantPool::add_dumped_interned_strings() {
406-
objArrayOop rr = resolved_references();
407-
if (rr != nullptr) {
408-
int rr_len = rr->length();
409-
for (int i = 0; i < rr_len; i++) {
410-
oop p = rr->obj_at(i);
411-
if (java_lang_String::is_instance(p) &&
412-
!ArchiveHeapWriter::is_string_too_large_to_archive(p)) {
413-
HeapShared::add_to_dumped_interned_strings(p);
408+
InstanceKlass* ik = pool_holder();
409+
if (!ik->is_linked()) {
410+
// resolved_references() doesn't exist yet, so we have no resolved CONSTANT_String entries. However,
411+
// some static final fields may have default values that were initialized when the class was parsed.
412+
// We need to enter those into the CDS archive strings table.
413+
for (JavaFieldStream fs(ik); !fs.done(); fs.next()) {
414+
if (fs.access_flags().is_static()) {
415+
fieldDescriptor& fd = fs.field_descriptor();
416+
if (fd.field_type() == T_OBJECT) {
417+
int offset = fd.offset();
418+
check_and_add_dumped_interned_string(ik->java_mirror()->obj_field(offset));
419+
}
420+
}
421+
}
422+
} else {
423+
objArrayOop rr = resolved_references();
424+
if (rr != nullptr) {
425+
int rr_len = rr->length();
426+
for (int i = 0; i < rr_len; i++) {
427+
check_and_add_dumped_interned_string(rr->obj_at(i));
414428
}
415429
}
416430
}
417431
}
432+
433+
void ConstantPool::check_and_add_dumped_interned_string(oop obj) {
434+
if (obj != nullptr && java_lang_String::is_instance(obj) &&
435+
!ArchiveHeapWriter::is_string_too_large_to_archive(obj)) {
436+
HeapShared::add_to_dumped_interned_strings(obj);
437+
}
438+
}
439+
418440
#endif
419441

420442
#if INCLUDE_CDS

src/hotspot/share/oops/constantPool.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ class ConstantPool : public Metadata {
162162
assert(is_within_bounds(cp_index), "index out of bounds");
163163
return (jdouble*) &base()[cp_index];
164164
}
165+
static void check_and_add_dumped_interned_string(oop obj);
165166

166167
ConstantPool(Array<u1>* tags);
167168
ConstantPool();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
/*
26+
27+
// Compiled from this source, but we want the version to be 49.0 to use the old verifier.
28+
29+
class OldClassWithStaticString {
30+
static final String s = "xxxx123yyyy456";
31+
static final String t = "OldClassWithStaticString";
32+
}
33+
34+
*/
35+
36+
public super class OldClassWithStaticString
37+
version 49:0
38+
{
39+
public static final Field s:"Ljava/lang/String;" = String "xxxx123yyyy456";
40+
public static final Field t:"Ljava/lang/String;" = String "OldClassWithStaticString";
41+
42+
Method "<init>":"()V"
43+
stack 1 locals 1
44+
{
45+
aload_0;
46+
invokespecial Method java/lang/Object."<init>":"()V";
47+
return;
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
/**
26+
* @test
27+
* @bug 8344904
28+
* @summary make sure all interned strings in old classes are archived.
29+
* @requires vm.cds.write.archived.java.heap
30+
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
31+
* @build OldClassWithStaticString
32+
* @build StaticStringInOldClass
33+
* @run driver jdk.test.lib.helpers.ClassFileInstaller
34+
* -jar StaticStringInOldClass.jar StaticStringInOldClass StaticStringInOldClassApp OldClassWithStaticString
35+
* @run driver StaticStringInOldClass
36+
*/
37+
38+
import java.lang.reflect.Field;
39+
import jdk.test.lib.process.OutputAnalyzer;
40+
import jdk.test.lib.helpers.ClassFileInstaller;
41+
42+
public class StaticStringInOldClass {
43+
static final String appClass = StaticStringInOldClassApp.class.getName();
44+
static String[] classes = {
45+
appClass,
46+
OldClassWithStaticString.class.getName(),
47+
};
48+
49+
public static void main(String[] args) throws Exception {
50+
String appJar = ClassFileInstaller.getJarPath("StaticStringInOldClass.jar");
51+
OutputAnalyzer output;
52+
output = TestCommon.testDump(appJar, TestCommon.list(classes));
53+
output = TestCommon.exec(appJar, appClass);
54+
TestCommon.checkExec(output, "Hello");
55+
}
56+
}
57+
58+
class StaticStringInOldClassApp {
59+
static String a = "xxxx123";
60+
public static void main(String args[]) throws Exception {
61+
System.out.println("Hello");
62+
String x = (a + "yyyy456").intern();
63+
Class c = OldClassWithStaticString.class;
64+
Field f = c.getField("s");
65+
String y = (String)(f.get(null));
66+
if (x != y) {
67+
throw new RuntimeException("Interned strings not equal: " +
68+
"\"" + x + "\" @ " + System.identityHashCode(x) + " vs " +
69+
"\"" + y + "\" @ " + System.identityHashCode(y));
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)