8074551: GWT can be marked non-compilable due to deopt count pollution
authorvlivanov
Thu, 11 Jun 2015 14:19:40 +0300
changeset 31228 8e427370cdd1
parent 31133 3e7542b42a61
child 31229 3a76ba7c09e5
child 31583 eb5bea7b4835
8074551: GWT can be marked non-compilable due to deopt count pollution Reviewed-by: kvn
hotspot/src/share/vm/ci/ciMethod.cpp
hotspot/src/share/vm/ci/ciMethod.hpp
hotspot/src/share/vm/classfile/classFileParser.cpp
hotspot/src/share/vm/classfile/classFileParser.hpp
hotspot/src/share/vm/classfile/vmSymbols.hpp
hotspot/src/share/vm/oops/method.cpp
hotspot/src/share/vm/oops/method.hpp
hotspot/src/share/vm/opto/compile.cpp
hotspot/src/share/vm/opto/library_call.cpp
hotspot/src/share/vm/runtime/deoptimization.cpp
hotspot/test/compiler/jsr292/PollutedTrapCounts.java
--- a/hotspot/src/share/vm/ci/ciMethod.cpp	Tue May 12 14:26:31 2015 +0200
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp	Thu Jun 11 14:19:40 2015 +0300
@@ -71,8 +71,7 @@
 // Loaded method.
 ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) :
   ciMetadata(h_m()),
-  _holder(holder),
-  _has_injected_profile(false)
+  _holder(holder)
 {
   assert(h_m() != NULL, "no null method");
 
@@ -170,8 +169,7 @@
   _liveness(               NULL),
   _can_be_statically_bound(false),
   _method_blocks(          NULL),
-  _method_data(            NULL),
-  _has_injected_profile(   false)
+  _method_data(            NULL)
 #if defined(COMPILER2) || defined(SHARK)
   ,
   _flow(                   NULL),
--- a/hotspot/src/share/vm/ci/ciMethod.hpp	Tue May 12 14:26:31 2015 +0200
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp	Thu Jun 11 14:19:40 2015 +0300
@@ -81,7 +81,6 @@
   bool _is_c1_compilable;
   bool _is_c2_compilable;
   bool _can_be_statically_bound;
-  bool _has_injected_profile;
 
   // Lazy fields, filled in on demand
   address              _code;
@@ -179,9 +178,9 @@
   // Code size for inlining decisions.
   int code_size_for_inlining();
 
-  bool caller_sensitive() { return get_Method()->caller_sensitive(); }
-  bool force_inline()     { return get_Method()->force_inline();     }
-  bool dont_inline()      { return get_Method()->dont_inline();      }
+  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();        }
 
   int comp_level();
   int highest_osr_comp_level();
@@ -289,9 +288,6 @@
   int instructions_size();
   int scale_count(int count, float prof_factor = 1.);  // make MDO count commensurate with IIC
 
-  bool has_injected_profile() const { return _has_injected_profile;     }
-  void set_injected_profile(bool x) {        _has_injected_profile = x; }
-
   // Stack walking support
   bool is_ignored_by_security_stack_walk() const;
 
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Tue May 12 14:26:31 2015 +0200
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Thu Jun 11 14:19:40 2015 +0300
@@ -1742,6 +1742,10 @@
     if (_location != _in_method)  break;  // only allow for methods
     if (!privileged)              break;  // only allow in privileged code
     return _method_DontInline;
+  case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_InjectedProfile_signature):
+    if (_location != _in_method)  break;  // only allow for methods
+    if (!privileged)              break;  // only allow in privileged code
+    return _method_InjectedProfile;
   case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature):
     if (_location != _in_method)  break;  // only allow for methods
     if (!privileged)              break;  // only allow in privileged code
@@ -1783,6 +1787,8 @@
     m->set_force_inline(true);
   if (has_annotation(_method_DontInline))
     m->set_dont_inline(true);
+  if (has_annotation(_method_InjectedProfile))
+    m->set_has_injected_profile(true);
   if (has_annotation(_method_LambdaForm_Compiled) && m->intrinsic_id() == vmIntrinsics::_none)
     m->set_intrinsic_id(vmIntrinsics::_compiledLambdaForm);
   if (has_annotation(_method_LambdaForm_Hidden))
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp	Tue May 12 14:26:31 2015 +0200
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp	Thu Jun 11 14:19:40 2015 +0300
@@ -127,6 +127,7 @@
       _method_CallerSensitive,
       _method_ForceInline,
       _method_DontInline,
+      _method_InjectedProfile,
       _method_LambdaForm_Compiled,
       _method_LambdaForm_Hidden,
       _sun_misc_Contended,
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Tue May 12 14:26:31 2015 +0200
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Thu Jun 11 14:19:40 2015 +0300
@@ -278,6 +278,7 @@
   template(java_lang_invoke_LambdaForm,               "java/lang/invoke/LambdaForm")              \
   template(java_lang_invoke_ForceInline_signature,    "Ljava/lang/invoke/ForceInline;")           \
   template(java_lang_invoke_DontInline_signature,     "Ljava/lang/invoke/DontInline;")            \
+  template(java_lang_invoke_InjectedProfile_signature, "Ljava/lang/invoke/InjectedProfile;")      \
   template(java_lang_invoke_Stable_signature,         "Ljava/lang/invoke/Stable;")                \
   template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \
   template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;")  \
--- a/hotspot/src/share/vm/oops/method.cpp	Tue May 12 14:26:31 2015 +0200
+++ b/hotspot/src/share/vm/oops/method.cpp	Thu Jun 11 14:19:40 2015 +0300
@@ -93,6 +93,7 @@
   set_force_inline(false);
   set_hidden(false);
   set_dont_inline(false);
+  set_has_injected_profile(false);
   set_method_data(NULL);
   clear_method_counters();
   set_vtable_index(Method::garbage_vtable_index);
--- a/hotspot/src/share/vm/oops/method.hpp	Tue May 12 14:26:31 2015 +0200
+++ b/hotspot/src/share/vm/oops/method.hpp	Thu Jun 11 14:19:40 2015 +0300
@@ -76,12 +76,13 @@
 
   // Flags
   enum Flags {
-    _jfr_towrite      = 1 << 0,
-    _caller_sensitive = 1 << 1,
-    _force_inline     = 1 << 2,
-    _dont_inline      = 1 << 3,
-    _hidden           = 1 << 4,
-    _running_emcp     = 1 << 5
+    _jfr_towrite          = 1 << 0,
+    _caller_sensitive     = 1 << 1,
+    _force_inline         = 1 << 2,
+    _dont_inline          = 1 << 3,
+    _hidden               = 1 << 4,
+    _has_injected_profile = 1 << 5,
+    _running_emcp         = 1 << 6
   };
   u1 _flags;
 
@@ -814,6 +815,13 @@
     _flags = x ? (_flags | _hidden) : (_flags & ~_hidden);
   }
 
+  bool has_injected_profile() {
+    return (_flags & _has_injected_profile) != 0;
+  }
+  void set_has_injected_profile(bool x) {
+    _flags = x ? (_flags | _has_injected_profile) : (_flags & ~_has_injected_profile);
+  }
+
   ConstMethod::MethodType method_type() const {
       return _constMethod->method_type();
   }
--- a/hotspot/src/share/vm/opto/compile.cpp	Tue May 12 14:26:31 2015 +0200
+++ b/hotspot/src/share/vm/opto/compile.cpp	Thu Jun 11 14:19:40 2015 +0300
@@ -3390,9 +3390,6 @@
 bool Compile::too_many_traps(ciMethod* method,
                              int bci,
                              Deoptimization::DeoptReason reason) {
-  if (method->has_injected_profile()) {
-    return false;
-  }
   ciMethodData* md = method->method_data();
   if (md->is_empty()) {
     // Assume the trap has not occurred, or that it occurred only
@@ -3442,9 +3439,6 @@
 bool Compile::too_many_recompiles(ciMethod* method,
                                   int bci,
                                   Deoptimization::DeoptReason reason) {
-  if (method->has_injected_profile()) {
-    return false;
-  }
   ciMethodData* md = method->method_data();
   if (md->is_empty()) {
     // Assume the trap has not occurred, or that it occurred only
--- a/hotspot/src/share/vm/opto/library_call.cpp	Tue May 12 14:26:31 2015 +0200
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Thu Jun 11 14:19:40 2015 +0300
@@ -6125,8 +6125,6 @@
     jint false_cnt = aobj->element_value(0).as_int();
     jint  true_cnt = aobj->element_value(1).as_int();
 
-    method()->set_injected_profile(true);
-
     if (C->log() != NULL) {
       C->log()->elem("observe source='profileBoolean' false='%d' true='%d'",
                      false_cnt, true_cnt);
--- a/hotspot/src/share/vm/runtime/deoptimization.cpp	Tue May 12 14:26:31 2015 +0200
+++ b/hotspot/src/share/vm/runtime/deoptimization.cpp	Thu Jun 11 14:19:40 2015 +0300
@@ -1460,7 +1460,11 @@
     //
     // The other actions cause immediate removal of the present code.
 
-    bool update_trap_state = (reason != Reason_tenured);
+    // Traps caused by injected profile shouldn't pollute trap counts.
+    bool injected_profile_trap = trap_method->has_injected_profile() &&
+                                 (reason == Reason_intrinsic || reason == Reason_unreached);
+
+    bool update_trap_state = (reason != Reason_tenured) && !injected_profile_trap;
     bool make_not_entrant = false;
     bool make_not_compilable = false;
     bool reprofile = false;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jsr292/PollutedTrapCounts.java	Thu Jun 11 14:19:40 2015 +0300
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8074551
+ * @library /testlibrary
+ * @run main PollutedTrapCounts
+ */
+import java.lang.invoke.*;
+import jdk.test.lib.*;
+
+public class PollutedTrapCounts {
+    public static void main(String[] args) throws Exception {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                "-XX:+IgnoreUnrecognizedVMOptions",
+                "-XX:-TieredCompilation", "-Xbatch",
+                "-XX:PerBytecodeRecompilationCutoff=10", "-XX:PerMethodRecompilationCutoff=10",
+                "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining",
+                    "PollutedTrapCounts$Test");
+
+        OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
+
+        analyzer.shouldHaveExitValue(0);
+
+        analyzer.shouldNotContain("not compilable (disabled)");
+    }
+
+    static class Test {
+        public static final MethodHandle test1;
+        public static final MethodHandle test2;
+        public static final MethodHandle empty;
+
+        static {
+            try {
+                Class<?> THIS_CLASS = Test.class;
+                MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+                test1 = LOOKUP.findStatic(THIS_CLASS, "test1", MethodType.methodType(boolean.class, boolean.class));
+                test2 = LOOKUP.findStatic(THIS_CLASS, "test2", MethodType.methodType(boolean.class, boolean.class));
+                empty = LOOKUP.findStatic(THIS_CLASS, "empty", MethodType.methodType(void.class, boolean.class));
+            } catch(Throwable e) {
+                throw new Error(e);
+            }
+        }
+
+        static boolean test1(boolean b) {
+            return b;
+        }
+        static boolean test2(boolean b) {
+            return true;
+        }
+        static void    empty(boolean b) {}
+
+        static void test(boolean freqValue, boolean removeInlineBlocker) throws Throwable {
+            MethodHandle innerGWT = MethodHandles.guardWithTest(test1, empty, empty);
+            MethodHandle outerGWT = MethodHandles.guardWithTest(test2, innerGWT, innerGWT);
+
+            // Trigger compilation
+            for (int i = 0; i < 20_000; i++) {
+                outerGWT.invokeExact(freqValue);
+            }
+
+            // Trigger deopt & nmethod invalidation
+            outerGWT.invokeExact(!freqValue);
+
+            // Force inline blocker removal on rare-taken path
+            if (removeInlineBlocker) {
+                for (int i = 0; i < 100; i++) {
+                    outerGWT.invokeExact(!freqValue);
+                }
+            }
+
+            // Trigger recompilation
+            for (int i = 0; i < 20_000; i++) {
+                outerGWT.invokeExact(freqValue);
+            }
+        }
+
+        public static void main(String[] args) throws Throwable {
+            boolean freqValue = true;
+            boolean removeInlineBlocker = false;
+            for (int i = 0; i < 20; i++) {
+                test(freqValue, removeInlineBlocker);
+                freqValue = !freqValue;
+                removeInlineBlocker = !removeInlineBlocker;
+            }
+        }
+    }
+}