8188133: C2: Static field accesses in clinit can trigger deoptimizations
authorvlivanov
Mon, 04 Feb 2019 17:35:35 -0800
changeset 53632 d620a4a1d5ed
parent 53631 a5321bcfa2de
child 53633 eebdde444bb5
8188133: C2: Static field accesses in clinit can trigger deoptimizations Reviewed-by: kvn
src/hotspot/share/ci/ciMethod.hpp
src/hotspot/share/opto/bytecodeInfo.cpp
src/hotspot/share/opto/compile.cpp
src/hotspot/share/opto/compile.hpp
src/hotspot/share/opto/parse.hpp
src/hotspot/share/opto/parse3.cpp
--- 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;
 }