8188133: C2: Static field accesses in clinit can trigger deoptimizations
Reviewed-by: kvn
--- a/src/hotspot/share/ci/ciMethod.hpp Mon Feb 04 21:42:47 2019 +0100
+++ b/src/hotspot/share/ci/ciMethod.hpp Mon Feb 04 17:35:35 2019 -0800
@@ -191,10 +191,11 @@
// Code size for inlining decisions.
int code_size_for_inlining();
- bool caller_sensitive() const { return get_Method()->caller_sensitive(); }
- bool force_inline() const { return get_Method()->force_inline(); }
- bool dont_inline() const { return get_Method()->dont_inline(); }
- bool intrinsic_candidate() const { return get_Method()->intrinsic_candidate(); }
+ bool caller_sensitive() const { return get_Method()->caller_sensitive(); }
+ bool force_inline() const { return get_Method()->force_inline(); }
+ bool dont_inline() const { return get_Method()->dont_inline(); }
+ bool intrinsic_candidate() const { return get_Method()->intrinsic_candidate(); }
+ bool is_static_initializer() const { return get_Method()->is_static_initializer(); }
int comp_level();
int highest_osr_comp_level();
--- a/src/hotspot/share/opto/bytecodeInfo.cpp Mon Feb 04 21:42:47 2019 +0100
+++ b/src/hotspot/share/opto/bytecodeInfo.cpp Mon Feb 04 17:35:35 2019 -0800
@@ -204,7 +204,9 @@
// First check all inlining restrictions which are required for correctness
if ( callee_method->is_abstract()) {
fail_msg = "abstract method"; // // note: we allow ik->is_abstract()
- } else if (!callee_method->holder()->is_initialized()) {
+ } else if (!callee_method->holder()->is_initialized() &&
+ // access allowed in the context of static initializer
+ !C->is_compiling_clinit_for(callee_method->holder())) {
fail_msg = "method holder not initialized";
} else if ( callee_method->is_native()) {
fail_msg = "native method";
@@ -446,13 +448,17 @@
}
//------------------------------pass_initial_checks----------------------------
-bool pass_initial_checks(ciMethod* caller_method, int caller_bci, ciMethod* callee_method) {
+bool InlineTree::pass_initial_checks(ciMethod* caller_method, int caller_bci, ciMethod* callee_method) {
ciInstanceKlass *callee_holder = callee_method ? callee_method->holder() : NULL;
// Check if a callee_method was suggested
if( callee_method == NULL ) return false;
// Check if klass of callee_method is loaded
if( !callee_holder->is_loaded() ) return false;
- if( !callee_holder->is_initialized() ) return false;
+ if( !callee_holder->is_initialized() &&
+ // access allowed in the context of static initializer
+ !C->is_compiling_clinit_for(callee_holder)) {
+ return false;
+ }
if( !UseInterpreter ) /* running Xcomp */ {
// Checks that constant pool's call site has been visited
// stricter than callee_holder->is_initialized()
--- a/src/hotspot/share/opto/compile.cpp Mon Feb 04 21:42:47 2019 +0100
+++ b/src/hotspot/share/opto/compile.cpp Mon Feb 04 17:35:35 2019 -0800
@@ -3820,6 +3820,11 @@
}
}
+bool Compile::is_compiling_clinit_for(ciKlass* k) {
+ ciMethod* root = method(); // the root method of compilation
+ return root->is_static_initializer() && root->holder() == k; // access in the context of clinit
+}
+
#ifndef PRODUCT
//------------------------------verify_graph_edges---------------------------
// Walk the Graph and verify that there is a one-to-one correspondence
--- a/src/hotspot/share/opto/compile.hpp Mon Feb 04 21:42:47 2019 +0100
+++ b/src/hotspot/share/opto/compile.hpp Mon Feb 04 17:35:35 2019 -0800
@@ -1374,6 +1374,8 @@
// supporting clone_map
CloneMap& clone_map();
void set_clone_map(Dict* d);
+
+ bool is_compiling_clinit_for(ciKlass* k);
};
#endif // SHARE_OPTO_COMPILE_HPP
--- a/src/hotspot/share/opto/parse.hpp Mon Feb 04 21:42:47 2019 +0100
+++ b/src/hotspot/share/opto/parse.hpp Mon Feb 04 17:35:35 2019 -0800
@@ -57,6 +57,8 @@
GrowableArray<InlineTree*> _subtrees;
+ bool pass_initial_checks(ciMethod* caller_method, int caller_bci, ciMethod* callee_method);
+
void print_impl(outputStream* stj, int indent) const PRODUCT_RETURN;
const char* _msg;
protected:
--- a/src/hotspot/share/opto/parse3.cpp Mon Feb 04 21:42:47 2019 +0100
+++ b/src/hotspot/share/opto/parse3.cpp Mon Feb 04 17:35:35 2019 -0800
@@ -55,25 +55,21 @@
// need to be guarded.
ciInstanceKlass *field_holder = field->holder();
- bool access_OK = false;
if (method->holder()->is_subclass_of(field_holder)) {
- if (method->is_static()) {
- if (method->name() == ciSymbol::class_initializer_name()) {
- // OK to access static fields inside initializer
- access_OK = true;
- }
- } else {
- if (method->name() == ciSymbol::object_initializer_name()) {
- // It's also OK to access static fields inside a constructor,
- // because any thread calling the constructor must first have
- // synchronized on the class by executing a '_new' bytecode.
- access_OK = true;
- }
+ if (method->is_static_initializer()) {
+ // OK to access static fields inside initializer
+ return true;
+ } else if (method->is_object_initializer()) {
+ // It's also OK to access static fields inside a constructor,
+ // because any thread calling the constructor must first have
+ // synchronized on the class by executing a '_new' bytecode.
+ return true;
}
}
-
- return access_OK;
-
+ if (C->is_compiling_clinit_for(field_holder)) {
+ return true; // access in the context of static initializer
+ }
+ return false;
}