8012322: Tiered: CompilationPolicy::can_be_compiled(CompLevel_all) mistakenly return false
authoriignatyev
Fri, 26 Apr 2013 07:21:41 -0700
changeset 17126 42a942feeea2
parent 17123 a8e62eed2e3e
child 17127 3665c17d4fba
8012322: Tiered: CompilationPolicy::can_be_compiled(CompLevel_all) mistakenly return false Reviewed-by: kvn, vlivanov
hotspot/src/share/vm/classfile/classLoader.cpp
hotspot/src/share/vm/runtime/compilationPolicy.cpp
hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java
hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java
--- a/hotspot/src/share/vm/classfile/classLoader.cpp	Thu Apr 25 11:09:24 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp	Fri Apr 26 07:21:41 2013 -0700
@@ -1345,9 +1345,10 @@
           tty->print_cr("CompileTheWorld (%d) : %s", _compile_the_world_class_counter, buffer);
           // Preload all classes to get around uncommon traps
           // Iterate over all methods in class
+          int comp_level = CompilationPolicy::policy()->initial_compile_level();
           for (int n = 0; n < k->methods()->length(); n++) {
             methodHandle m (THREAD, k->methods()->at(n));
-            if (CompilationPolicy::can_be_compiled(m)) {
+            if (CompilationPolicy::can_be_compiled(m, comp_level)) {
 
               if (++_codecache_sweep_counter == CompileTheWorldSafepointInterval) {
                 // Give sweeper a chance to keep up with CTW
@@ -1356,7 +1357,7 @@
                 _codecache_sweep_counter = 0;
               }
               // Force compilation
-              CompileBroker::compile_method(m, InvocationEntryBci, CompilationPolicy::policy()->initial_compile_level(),
+              CompileBroker::compile_method(m, InvocationEntryBci, comp_level,
                                             methodHandle(), 0, "CTW", THREAD);
               if (HAS_PENDING_EXCEPTION) {
                 clear_pending_exception_if_not_oom(CHECK);
--- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp	Thu Apr 25 11:09:24 2013 -0700
+++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp	Fri Apr 26 07:21:41 2013 -0700
@@ -109,6 +109,9 @@
 
 // Returns true if m is allowed to be compiled
 bool CompilationPolicy::can_be_compiled(methodHandle m, int comp_level) {
+  // allow any levels for WhiteBox
+  assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level");
+
   if (m->is_abstract()) return false;
   if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false;
 
@@ -122,7 +125,13 @@
     return false;
   }
   if (comp_level == CompLevel_all) {
-    return !m->is_not_compilable(CompLevel_simple) && !m->is_not_compilable(CompLevel_full_optimization);
+    if (TieredCompilation) {
+      // enough to be compilable at any level for tiered
+      return !m->is_not_compilable(CompLevel_simple) || !m->is_not_compilable(CompLevel_full_optimization);
+    } else {
+      // must be compilable at available level for non-tiered
+      return !m->is_not_compilable(CompLevel_highest_tier);
+    }
   } else if (is_compile(comp_level)) {
     return !m->is_not_compilable(comp_level);
   }
@@ -436,7 +445,7 @@
   reset_counter_for_invocation_event(m);
   const char* comment = "count";
 
-  if (is_compilation_enabled() && can_be_compiled(m)) {
+  if (is_compilation_enabled() && can_be_compiled(m, comp_level)) {
     nmethod* nm = m->code();
     if (nm == NULL ) {
       CompileBroker::compile_method(m, InvocationEntryBci, comp_level, m, hot_count, comment, thread);
@@ -449,7 +458,7 @@
   const int hot_count = m->backedge_count();
   const char* comment = "backedge_count";
 
-  if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m)) {
+  if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m, comp_level)) {
     CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread);
     NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));)
   }
@@ -467,7 +476,7 @@
   reset_counter_for_invocation_event(m);
   const char* comment = "count";
 
-  if (is_compilation_enabled() && m->code() == NULL && can_be_compiled(m)) {
+  if (is_compilation_enabled() && m->code() == NULL && can_be_compiled(m, comp_level)) {
     ResourceMark rm(thread);
     frame       fr     = thread->last_frame();
     assert(fr.is_interpreted_frame(), "must be interpreted");
@@ -505,7 +514,7 @@
   const int hot_count = m->backedge_count();
   const char* comment = "backedge_count";
 
-  if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m)) {
+  if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m, comp_level)) {
     CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread);
     NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));)
   }
@@ -600,7 +609,7 @@
 
     // If the caller method is too big or something then we do not want to
     // compile it just to inline a method
-    if (!can_be_compiled(next_m)) {
+    if (!can_be_compiled(next_m, CompLevel_any)) {
       msg = "caller cannot be compiled";
       break;
     }
--- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java	Thu Apr 25 11:09:24 2013 -0700
+++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java	Fri Apr 26 07:21:41 2013 -0700
@@ -42,6 +42,11 @@
     protected static int COMP_LEVEL_NONE = 0;
     /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */
     protected static int COMP_LEVEL_ANY = -1;
+    /** {@code CompLevel::CompLevel_simple} -- C1 */
+    protected static int COMP_LEVEL_SIMPLE = 1;
+    /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */
+    protected static int COMP_LEVEL_FULL_OPTIMIZATION = 4;
+
     /** Instance of WhiteBox */
     protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
     /** Value of {@code -XX:CompileThreshold} */
@@ -91,6 +96,17 @@
         return result == null ? defaultValue : result;
     }
 
+    /** copy of is_c1_compile(int) from utilities/globalDefinitions.hpp */
+    protected static boolean isC1Compile(int compLevel) {
+        return (compLevel > COMP_LEVEL_NONE)
+                && (compLevel < COMP_LEVEL_FULL_OPTIMIZATION);
+    }
+
+    /** copy of is_c2_compile(int) from utilities/globalDefinitions.hpp */
+    protected static boolean isC2Compile(int compLevel) {
+        return compLevel == COMP_LEVEL_FULL_OPTIMIZATION;
+    }
+
     /** tested method */
     protected final Executable method;
     private final Callable<Integer> callable;
--- a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java	Thu Apr 25 11:09:24 2013 -0700
+++ b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java	Fri Apr 26 07:21:41 2013 -0700
@@ -23,6 +23,7 @@
 
 /*
  * @test MakeMethodNotCompilableTest
+ * @bug 8012322
  * @library /testlibrary /testlibrary/whitebox
  * @build MakeMethodNotCompilableTest
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
@@ -67,28 +68,69 @@
         }
 
         if (TIERED_COMPILATION) {
-            for (int i = 1, n = TIERED_STOP_AT_LEVEL + 1; i < n; ++i) {
-                WHITE_BOX.makeMethodNotCompilable(method, i);
-                if (WHITE_BOX.isMethodCompilable(method, i)) {
+            final int tierLimit = TIERED_STOP_AT_LEVEL + 1;
+            for (int testedTier = 1; testedTier < tierLimit; ++testedTier) {
+                testTier(testedTier);
+            }
+            for (int testedTier = 1; testedTier < tierLimit; ++testedTier) {
+                WHITE_BOX.makeMethodNotCompilable(method, testedTier);
+                if (WHITE_BOX.isMethodCompilable(method, testedTier)) {
                     throw new RuntimeException(method
-                            + " must be not compilable at level" + i);
+                            + " must be not compilable at level" + testedTier);
                 }
-                WHITE_BOX.enqueueMethodForCompilation(method, i);
+                WHITE_BOX.enqueueMethodForCompilation(method, testedTier);
                 checkNotCompiled();
 
                 if (!WHITE_BOX.isMethodCompilable(method)) {
                     System.out.println(method
-                            + " is not compilable after level " + i);
+                            + " is not compilable after level " + testedTier);
                 }
             }
+        } else {
+            compile();
+            checkCompiled();
+            int compLevel = WHITE_BOX.getMethodCompilationLevel(method);
+            WHITE_BOX.deoptimizeMethod(method);
+            WHITE_BOX.makeMethodNotCompilable(method, compLevel);
+            if (WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) {
+                throw new RuntimeException(method
+                        + " must be not compilable at CompLevel::CompLevel_any,"
+                        + " after it is not compilable at " + compLevel);
+            }
+            WHITE_BOX.clearMethodState(method);
+
+            // nocompilable at opposite level must make no sense
+            int oppositeLevel;
+            if (isC1Compile(compLevel)) {
+              oppositeLevel = COMP_LEVEL_FULL_OPTIMIZATION;
+            } else {
+              oppositeLevel = COMP_LEVEL_SIMPLE;
+            }
+            WHITE_BOX.makeMethodNotCompilable(method, oppositeLevel);
+
+            if (!WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) {
+                  throw new RuntimeException(method
+                        + " must be compilable at CompLevel::CompLevel_any,"
+                        + " even it is not compilable at opposite level ["
+                        + compLevel + "]");
+            }
 
-            // WB.clearMethodState() must reset no-compilable flags
-            WHITE_BOX.clearMethodState(method);
-            if (!WHITE_BOX.isMethodCompilable(method)) {
-                throw new RuntimeException(method
-                        + " is not compilable after clearMethodState()");
+            if (!WHITE_BOX.isMethodCompilable(method, compLevel)) {
+                  throw new RuntimeException(method
+                        + " must be compilable at level " + compLevel
+                        + ", even it is not compilable at opposite level ["
+                        + compLevel + "]");
             }
         }
+
+        // clearing after tiered/non-tiered tests
+        // WB.clearMethodState() must reset no-compilable flags
+        WHITE_BOX.clearMethodState(method);
+        if (!WHITE_BOX.isMethodCompilable(method)) {
+            throw new RuntimeException(method
+                    + " is not compilable after clearMethodState()");
+        }
+
         WHITE_BOX.makeMethodNotCompilable(method);
         if (WHITE_BOX.isMethodCompilable(method)) {
             throw new RuntimeException(method + " must be not compilable");
@@ -108,4 +150,65 @@
         compile();
         checkCompiled();
     }
+
+    // separately tests each tier
+    private void testTier(int testedTier) {
+        if (!WHITE_BOX.isMethodCompilable(method, testedTier)) {
+            throw new RuntimeException(method
+                    + " is not compilable on start");
+        }
+        WHITE_BOX.makeMethodNotCompilable(method, testedTier);
+
+        // tests for all other tiers
+        for (int anotherTier = 1, tierLimit = TIERED_STOP_AT_LEVEL + 1;
+                    anotherTier < tierLimit; ++anotherTier) {
+            boolean isCompilable = WHITE_BOX.isMethodCompilable(method,
+                    anotherTier);
+            if (sameCompile(testedTier, anotherTier)) {
+                if (isCompilable) {
+                    throw new RuntimeException(method
+                            + " must be not compilable at level " + anotherTier
+                            + ", if it is not compilable at " + testedTier);
+                }
+                WHITE_BOX.enqueueMethodForCompilation(method, anotherTier);
+                checkNotCompiled();
+            } else {
+                if (!isCompilable) {
+                    throw new RuntimeException(method
+                            + " must be compilable at level " + anotherTier
+                            + ", even if it is not compilable at "
+                            + testedTier);
+                }
+                WHITE_BOX.enqueueMethodForCompilation(method, anotherTier);
+                checkCompiled();
+                WHITE_BOX.deoptimizeMethod(method);
+            }
+
+            if (!WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) {
+                throw new RuntimeException(method
+                        + " must be compilable at 'CompLevel::CompLevel_any'"
+                        + ", if it is not compilable only at " + testedTier);
+            }
+        }
+
+        // clear state after test
+        WHITE_BOX.clearMethodState(method);
+        if (!WHITE_BOX.isMethodCompilable(method, testedTier)) {
+            throw new RuntimeException(method
+                    + " is not compilable after clearMethodState()");
+        }
+    }
+
+    private boolean sameCompile(int level1, int level2) {
+        if (level1 == level2) {
+            return true;
+        }
+        if (isC1Compile(level1) && isC1Compile(level2)) {
+            return true;
+        }
+        if (isC2Compile(level1) && isC2Compile(level2)) {
+            return true;
+        }
+        return false;
+    }
 }