# HG changeset patch # User vlivanov # Date 1549330535 28800 # Node ID d620a4a1d5ed823dfcac1085a0530d49e1ec26e7 # Parent a5321bcfa2de47ed5fa020055be6a098053e4b2a 8188133: C2: Static field accesses in clinit can trigger deoptimizations Reviewed-by: kvn diff -r a5321bcfa2de -r d620a4a1d5ed src/hotspot/share/ci/ciMethod.hpp --- 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(); diff -r a5321bcfa2de -r d620a4a1d5ed src/hotspot/share/opto/bytecodeInfo.cpp --- 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() diff -r a5321bcfa2de -r d620a4a1d5ed src/hotspot/share/opto/compile.cpp --- 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 diff -r a5321bcfa2de -r d620a4a1d5ed src/hotspot/share/opto/compile.hpp --- 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 diff -r a5321bcfa2de -r d620a4a1d5ed src/hotspot/share/opto/parse.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 _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: diff -r a5321bcfa2de -r d620a4a1d5ed src/hotspot/share/opto/parse3.cpp --- 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; }