Skip to content

Commit 5212535

Browse files
author
Vladimir Ivanov
committed
8282218: C1: Missing side effects of dynamic class loading during constant linkage
Reviewed-by: thartmann, kvn
1 parent d8f9686 commit 5212535

File tree

6 files changed

+136
-7
lines changed

6 files changed

+136
-7
lines changed

src/hotspot/share/c1/c1_GraphBuilder.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ void GraphBuilder::load_constant() {
952952
case T_ARRAY : // fall-through
953953
case T_OBJECT : {
954954
ciObject* obj = con.as_object();
955-
if (!obj->is_loaded() || (PatchALot && (obj->is_null_object() || obj->klass() != ciEnv::current()->String_klass()))) {
955+
if (!obj->is_loaded() || (PatchALot && !stream()->is_string_constant())) {
956956
// A Class, MethodType, MethodHandle, Dynamic, or String.
957957
patch_state = copy_state_before();
958958
t = new ObjectConstant(obj);
@@ -973,7 +973,9 @@ void GraphBuilder::load_constant() {
973973
}
974974
Value x;
975975
if (patch_state != NULL) {
976-
bool kills_memory = stream()->is_dynamic_constant(); // arbitrary memory effects from running BSM during linkage
976+
// Arbitrary memory effects from running BSM or class loading (using custom loader) during linkage.
977+
bool kills_memory = stream()->is_dynamic_constant() ||
978+
(!stream()->is_string_constant() && !method()->holder()->has_trusted_loader());
977979
x = new Constant(t, patch_state, kills_memory);
978980
} else {
979981
x = new Constant(t);

src/hotspot/share/ci/ciInstanceKlass.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
100100
_is_shared = true;
101101
}
102102

103+
_has_trusted_loader = compute_has_trusted_loader();
104+
103105
// Lazy fields get filled in only upon request.
104106
_super = NULL;
105107
_java_mirror = NULL;
@@ -132,6 +134,7 @@ ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
132134
_super = NULL;
133135
_java_mirror = NULL;
134136
_field_cache = NULL;
137+
_has_trusted_loader = compute_has_trusted_loader();
135138
}
136139

137140

@@ -568,6 +571,15 @@ bool ciInstanceKlass::has_object_fields() const {
568571
);
569572
}
570573

574+
bool ciInstanceKlass::compute_has_trusted_loader() {
575+
ASSERT_IN_VM;
576+
oop loader_oop = loader();
577+
if (loader_oop == NULL) {
578+
return true; // bootstrap class loader
579+
}
580+
return java_lang_ClassLoader::is_trusted_loader(loader_oop);
581+
}
582+
571583
// ------------------------------------------------------------------
572584
// ciInstanceKlass::find_method
573585
//

src/hotspot/share/ci/ciInstanceKlass.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class ciInstanceKlass : public ciKlass {
5959
bool _has_nonstatic_concrete_methods;
6060
bool _is_hidden;
6161
bool _is_record;
62+
bool _has_trusted_loader;
6263

6364
ciFlags _flags;
6465

@@ -107,6 +108,7 @@ class ciInstanceKlass : public ciKlass {
107108
bool compute_shared_has_subklass();
108109
int compute_nonstatic_fields();
109110
GrowableArray<ciField*>* compute_nonstatic_fields_impl(GrowableArray<ciField*>* super_fields);
111+
bool compute_has_trusted_loader();
110112

111113
// Update the init_state for shared klasses
112114
void update_if_shared(InstanceKlass::ClassState expected) {
@@ -287,6 +289,10 @@ class ciInstanceKlass : public ciKlass {
287289
return !is_interface() && !is_abstract();
288290
}
289291

292+
bool has_trusted_loader() const {
293+
return _has_trusted_loader;
294+
}
295+
290296
// Replay support
291297

292298
// Dump the current state of this klass for compilation replay.

src/hotspot/share/ci/ciStreams.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ constantTag ciBytecodeStream::get_constant_pool_tag(int index) const {
259259
// ------------------------------------------------------------------
260260
// ciBytecodeStream::get_raw_pool_tag
261261
//
262-
constantTag ciBytecodeStream::get_raw_pool_tag(int index) const {
262+
constantTag ciBytecodeStream::get_raw_pool_tag_at(int index) const {
263263
VM_ENTRY_MARK;
264264
return _method->get_Method()->constants()->tag_at(index);
265265
}

src/hotspot/share/ci/ciStreams.hpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,14 @@ class ciBytecodeStream : StackObj {
230230
constantTag get_constant_pool_tag(int index) const;
231231
BasicType get_basic_type_for_constant_at(int index) const;
232232

233-
constantTag get_raw_pool_tag(int index) const;
233+
constantTag get_raw_pool_tag_at(int index) const;
234234

235-
// True if the klass-using bytecode points to an unresolved klass
235+
constantTag get_raw_pool_tag() const {
236+
int index = get_constant_pool_index();
237+
return get_raw_pool_tag_at(index);
238+
}
239+
240+
// True if the klass-using bytecode points to an unresolved klass
236241
bool is_unresolved_klass() const {
237242
constantTag tag = get_constant_pool_tag(get_klass_index());
238243
return tag.is_unresolved_klass();
@@ -243,12 +248,20 @@ class ciBytecodeStream : StackObj {
243248
cur_bc() == Bytecodes::_ldc_w ||
244249
cur_bc() == Bytecodes::_ldc2_w, "not supported: %s", Bytecodes::name(cur_bc()));
245250

246-
int index = get_constant_pool_index();
247-
constantTag tag = get_raw_pool_tag(index);
251+
constantTag tag = get_raw_pool_tag();
248252
return tag.is_dynamic_constant() ||
249253
tag.is_dynamic_constant_in_error();
250254
}
251255

256+
bool is_string_constant() const {
257+
assert(cur_bc() == Bytecodes::_ldc ||
258+
cur_bc() == Bytecodes::_ldc_w ||
259+
cur_bc() == Bytecodes::_ldc2_w, "not supported: %s", Bytecodes::name(cur_bc()));
260+
261+
constantTag tag = get_raw_pool_tag();
262+
return tag.is_string();
263+
}
264+
252265
bool is_in_error() const {
253266
assert(cur_bc() == Bytecodes::_ldc ||
254267
cur_bc() == Bytecodes::_ldc_w ||
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright (c) 2022, 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+
* @test
26+
* @bug 8282218
27+
*
28+
* @run main/othervm -Xcomp -XX:TieredStopAtLevel=1
29+
* -XX:CompileCommand=compileonly,compiler.c1.TestClassConstantPatching$Test::run
30+
* compiler.c1.TestClassConstantPatching
31+
*/
32+
package compiler.c1;
33+
34+
import java.io.File;
35+
import java.io.IOException;
36+
import java.io.InputStream;
37+
import java.lang.reflect.Method;
38+
39+
public class TestClassConstantPatching {
40+
public static int COUNTER = 0;
41+
42+
static class CustomLoader extends ClassLoader {
43+
@Override
44+
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
45+
if (name.startsWith(Test.class.getName())) {
46+
Class<?> c = findLoadedClass(name);
47+
if (c != null) {
48+
return c;
49+
}
50+
try {
51+
COUNTER++; // update counter on loading
52+
53+
InputStream in = getSystemResourceAsStream(name.replace('.', File.separatorChar) + ".class");
54+
byte[] buf = in.readAllBytes();
55+
return defineClass(name, buf, 0, buf.length);
56+
} catch (IOException e) {
57+
throw new ClassNotFoundException(name);
58+
}
59+
}
60+
return super.loadClass(name, resolve);
61+
}
62+
}
63+
64+
public static class Test {
65+
static class T {}
66+
67+
public static Class<?> run(boolean cond) {
68+
int before = COUNTER;
69+
Class<?> c = null;
70+
if (cond) {
71+
c = T.class;
72+
}
73+
int after = COUNTER;
74+
if (cond && before == after) {
75+
throw new AssertionError("missed update");
76+
}
77+
return c;
78+
}
79+
}
80+
81+
public static void main(String[] args) throws ReflectiveOperationException {
82+
ClassLoader cl = new CustomLoader();
83+
84+
Class.forName(TestClassConstantPatching.class.getName(), true, cl); // preload counter holder class
85+
86+
Class<?> test = Class.forName(Test.class.getName(), true, cl);
87+
88+
Method m = test.getDeclaredMethod("run", boolean.class);
89+
90+
m.invoke(null, false);
91+
m.invoke(null, true);
92+
93+
System.out.println("TEST PASSED");
94+
}
95+
}
96+

0 commit comments

Comments
 (0)