Skip to content

Commit f44e593

Browse files
committed
8216302: StackTraceElement::fill_in can use cached Class.name
Reviewed-by: coleenp, dholmes, mchung
1 parent 79c92ea commit f44e593

8 files changed

Lines changed: 140 additions & 31 deletions

File tree

make/hotspot/symbols/symbols-unix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ JVM_GetClassFieldsCount
8181
JVM_GetClassInterfaces
8282
JVM_GetClassMethodsCount
8383
JVM_GetClassModifiers
84-
JVM_GetClassName
8584
JVM_GetClassNameUTF
8685
JVM_GetClassSignature
8786
JVM_GetClassSigners
@@ -133,6 +132,7 @@ JVM_Halt
133132
JVM_HasReferencePendingList
134133
JVM_HoldsLock
135134
JVM_IHashCode
135+
JVM_InitClassName
136136
JVM_InitStackTraceElement
137137
JVM_InitStackTraceElementArray
138138
JVM_InitializeFromArchive

src/hotspot/share/classfile/javaClasses.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,6 +1344,16 @@ void java_lang_Class::set_module(oop java_class, oop module) {
13441344
java_class->obj_field_put(_module_offset, module);
13451345
}
13461346

1347+
oop java_lang_Class::name(Handle java_class, TRAPS) {
1348+
assert(_name_offset != 0, "must be set");
1349+
oop o = java_class->obj_field(_name_offset);
1350+
if (o == NULL) {
1351+
o = StringTable::intern(java_lang_Class::as_external_name(java_class()), THREAD);
1352+
java_class->obj_field_put(_name_offset, o);
1353+
}
1354+
return o;
1355+
}
1356+
13471357
oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) {
13481358
// This should be improved by adding a field at the Java level or by
13491359
// introducing a new VM klass (see comment in ClassFileParser)
@@ -1504,7 +1514,8 @@ int java_lang_Class::classRedefinedCount_offset = -1;
15041514
macro(classRedefinedCount_offset, k, "classRedefinedCount", int_signature, false) ; \
15051515
macro(_class_loader_offset, k, "classLoader", classloader_signature, false); \
15061516
macro(_component_mirror_offset, k, "componentType", class_signature, false); \
1507-
macro(_module_offset, k, "module", module_signature, false)
1517+
macro(_module_offset, k, "module", module_signature, false); \
1518+
macro(_name_offset, k, "name", string_signature, false); \
15081519

15091520
void java_lang_Class::compute_offsets() {
15101521
if (offsets_computed) {
@@ -2550,12 +2561,14 @@ void java_lang_StackTraceElement::fill_in(Handle element,
25502561
int version, int bci, Symbol* name, TRAPS) {
25512562
assert(element->is_a(SystemDictionary::StackTraceElement_klass()), "sanity check");
25522563

2553-
// Fill in class name
25542564
ResourceMark rm(THREAD);
2555-
const char* str = holder->external_name();
2556-
oop classname = StringTable::intern(str, CHECK);
2565+
HandleMark hm(THREAD);
2566+
2567+
// Fill in class name
2568+
Handle java_class(THREAD, holder->java_mirror());
2569+
oop classname = java_lang_Class::name(java_class, CHECK);
25572570
java_lang_StackTraceElement::set_declaringClass(element(), classname);
2558-
java_lang_StackTraceElement::set_declaringClassObject(element(), holder->java_mirror());
2571+
java_lang_StackTraceElement::set_declaringClassObject(element(), java_class());
25592572

25602573
oop loader = holder->class_loader();
25612574
if (loader != NULL) {
@@ -3966,6 +3979,7 @@ int java_lang_Class::_protection_domain_offset;
39663979
int java_lang_Class::_component_mirror_offset;
39673980
int java_lang_Class::_init_lock_offset;
39683981
int java_lang_Class::_signers_offset;
3982+
int java_lang_Class::_name_offset;
39693983
GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL;
39703984
GrowableArray<Klass*>* java_lang_Class::_fixup_module_field_list = NULL;
39713985
int java_lang_Throwable::backtrace_offset;

src/hotspot/share/classfile/javaClasses.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -240,6 +240,7 @@ class java_lang_Class : AllStatic {
240240
static int _class_loader_offset;
241241
static int _module_offset;
242242
static int _component_mirror_offset;
243+
static int _name_offset;
243244

244245
static bool offsets_computed;
245246
static int classRedefinedCount_offset;
@@ -310,6 +311,8 @@ class java_lang_Class : AllStatic {
310311
static void set_module(oop java_class, oop module);
311312
static oop module(oop java_class);
312313

314+
static oop name(Handle java_class, TRAPS);
315+
313316
static int oop_size(oop java_class);
314317
static int oop_size_raw(oop java_class);
315318
static void set_oop_size(HeapWord* java_class, int size);

src/hotspot/share/include/jvm.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -63,7 +63,7 @@ extern "C" {
6363
* class.
6464
*/
6565

66-
#define JVM_INTERFACE_VERSION 5
66+
#define JVM_INTERFACE_VERSION 6
6767

6868
JNIEXPORT jint JNICALL
6969
JVM_GetInterfaceVersion(void);
@@ -450,7 +450,7 @@ JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module);
450450
*/
451451

452452
JNIEXPORT jstring JNICALL
453-
JVM_GetClassName(JNIEnv *env, jclass cls);
453+
JVM_InitClassName(JNIEnv *env, jclass cls);
454454

455455
JNIEXPORT jobjectArray JNICALL
456456
JVM_GetClassInterfaces(JNIEnv *env, jclass cls);

src/hotspot/share/prims/jvm.cpp

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1059,21 +1059,14 @@ JVM_END
10591059

10601060
// Reflection support //////////////////////////////////////////////////////////////////////////////
10611061

1062-
JVM_ENTRY(jstring, JVM_GetClassName(JNIEnv *env, jclass cls))
1062+
JVM_ENTRY(jstring, JVM_InitClassName(JNIEnv *env, jclass cls))
10631063
assert (cls != NULL, "illegal class");
1064-
JVMWrapper("JVM_GetClassName");
1064+
JVMWrapper("JVM_InitClassName");
10651065
JvmtiVMObjectAllocEventCollector oam;
10661066
ResourceMark rm(THREAD);
1067-
const char* name;
1068-
if (java_lang_Class::is_primitive(JNIHandles::resolve(cls))) {
1069-
name = type2name(java_lang_Class::primitive_type(JNIHandles::resolve(cls)));
1070-
} else {
1071-
// Consider caching interned string in Klass
1072-
Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve(cls));
1073-
assert(k->is_klass(), "just checking");
1074-
name = k->external_name();
1075-
}
1076-
oop result = StringTable::intern((char*) name, CHECK_NULL);
1067+
HandleMark hm(THREAD);
1068+
Handle java_class(THREAD, JNIHandles::resolve(cls));
1069+
oop result = java_lang_Class::name(java_class, CHECK_NULL);
10771070
return (jstring) JNIHandles::make_local(env, result);
10781071
JVM_END
10791072

src/java.base/share/classes/java/lang/Class.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -795,14 +795,13 @@ public boolean isSynthetic() {
795795
*/
796796
public String getName() {
797797
String name = this.name;
798-
if (name == null)
799-
this.name = name = getName0();
800-
return name;
798+
return name != null ? name : initClassName();
801799
}
802800

803-
// cache the name to reduce the number of calls into the VM
801+
// Cache the name to reduce the number of calls into the VM.
802+
// This field would be set by VM itself during initClassName call.
804803
private transient String name;
805-
private native String getName0();
804+
private native String initClassName();
806805

807806
/**
808807
* Returns the class loader for the class. Some implementations may use

src/java.base/share/native/libjava/Class.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -52,7 +52,7 @@ extern jboolean VerifyFixClassname(char *utf_name);
5252
#define BA "[B"
5353

5454
static JNINativeMethod methods[] = {
55-
{"getName0", "()" STR, (void *)&JVM_GetClassName},
55+
{"initClassName", "()" STR, (void *)&JVM_InitClassName},
5656
{"getSuperclass", "()" CLS, NULL},
5757
{"getInterfaces0", "()[" CLS, (void *)&JVM_GetClassInterfaces},
5858
{"isInterface", "()Z", (void *)&JVM_IsInterface},
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright (c) 2019, Red Hat, Inc. 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+
* @test
26+
* @bug 8216302
27+
* @summary Check that stack trace contains proper strings even with class caching
28+
* @modules java.base/java.lang:open
29+
* @compile StackTraceClassCache.java
30+
* @run main StackTraceClassCache
31+
*/
32+
33+
import java.lang.reflect.*;
34+
35+
public class StackTraceClassCache {
36+
public static void main(String... args) throws Exception {
37+
Outer.Inner o = new Outer().new Inner();
38+
Class cl = o.getClass();
39+
40+
// Check out of the box class name
41+
try {
42+
o.work();
43+
} catch (Exception e) {
44+
checkException(e, 42);
45+
}
46+
47+
// Clear and populate class caches via getName
48+
clearNameCache(cl);
49+
cl.getName();
50+
try {
51+
o.work();
52+
} catch (Exception e) {
53+
checkException(e, 51);
54+
}
55+
56+
// Clear and populate class caches via stack trace
57+
clearNameCache(cl);
58+
try {
59+
o.work();
60+
} catch (Exception e) {
61+
checkException(e, 59);
62+
}
63+
}
64+
65+
static void checkException(Exception e, int line) throws Exception {
66+
StackTraceElement[] fs = e.getStackTrace();
67+
68+
if (fs.length < 2) {
69+
throw new IllegalStateException("Exception should have at least two frames", e);
70+
}
71+
72+
assertCorrect("StackTraceClassCache$Outer$Inner.work(StackTraceClassCache.java:95)", fs[0].toString(), e);
73+
assertCorrect("StackTraceClassCache.main(StackTraceClassCache.java:" + line + ")", fs[1].toString(), e);
74+
}
75+
76+
static void assertCorrect(String expected, String actual, Exception e) throws Exception {
77+
if (!expected.equals(actual)) {
78+
throw new IllegalStateException("Expected: " + expected + "; Actual: " + actual, e);
79+
}
80+
}
81+
82+
static void clearNameCache(Class cl) {
83+
try {
84+
Field f = Class.class.getDeclaredField("name");
85+
f.setAccessible(true);
86+
f.set(cl, null);
87+
} catch (Exception e) {
88+
throw new IllegalStateException(e);
89+
}
90+
}
91+
92+
static class Outer {
93+
class Inner {
94+
void work() throws Exception {
95+
throw new Exception("Sample exception");
96+
}
97+
}
98+
}
99+
100+
}

0 commit comments

Comments
 (0)