8012322: Tiered: CompilationPolicy::can_be_compiled(CompLevel_all) mistakenly return false
Reviewed-by: kvn, vlivanov
--- 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;
+ }
}