Skip to content

Commit

Permalink
8263582: WB_IsMethodCompilable ignores compiler directives
Browse files Browse the repository at this point in the history
Reviewed-by: iveresov, kvn, neliasso
  • Loading branch information
chhagedorn committed Mar 31, 2021
1 parent 928fa5b commit ab6faa6
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 13 deletions.
8 changes: 4 additions & 4 deletions src/hotspot/share/compiler/compilationPolicy.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ void CompilationPolicy::compile_if_required(const methodHandle& m, TRAPS) {
} }


static inline CompLevel adjust_level_for_compilability_query(CompLevel comp_level) { static inline CompLevel adjust_level_for_compilability_query(CompLevel comp_level) {
if (comp_level == CompLevel_all) { if (comp_level == CompLevel_any) {
if (CompilerConfig::is_c1_only()) { if (CompilerConfig::is_c1_only()) {
comp_level = CompLevel_simple; comp_level = CompLevel_simple;
} else if (CompilerConfig::is_c2_or_jvmci_compiler_only()) { } else if (CompilerConfig::is_c2_or_jvmci_compiler_only()) {
Expand All @@ -125,7 +125,7 @@ static inline CompLevel adjust_level_for_compilability_query(CompLevel comp_leve
// Returns true if m is allowed to be compiled // Returns true if m is allowed to be compiled
bool CompilationPolicy::can_be_compiled(const methodHandle& m, int comp_level) { bool CompilationPolicy::can_be_compiled(const methodHandle& m, int comp_level) {
// allow any levels for WhiteBox // allow any levels for WhiteBox
assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level"); assert(WhiteBoxAPI || comp_level == CompLevel_any || is_compile(comp_level), "illegal compilation level");


if (m->is_abstract()) return false; if (m->is_abstract()) return false;
if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false; if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false;
Expand All @@ -140,7 +140,7 @@ bool CompilationPolicy::can_be_compiled(const methodHandle& m, int comp_level) {
return false; return false;
} }
comp_level = adjust_level_for_compilability_query((CompLevel) comp_level); comp_level = adjust_level_for_compilability_query((CompLevel) comp_level);
if (comp_level == CompLevel_all || is_compile(comp_level)) { if (comp_level == CompLevel_any || is_compile(comp_level)) {
return !m->is_not_compilable(comp_level); return !m->is_not_compilable(comp_level);
} }
return false; return false;
Expand All @@ -150,7 +150,7 @@ bool CompilationPolicy::can_be_compiled(const methodHandle& m, int comp_level) {
bool CompilationPolicy::can_be_osr_compiled(const methodHandle& m, int comp_level) { bool CompilationPolicy::can_be_osr_compiled(const methodHandle& m, int comp_level) {
bool result = false; bool result = false;
comp_level = adjust_level_for_compilability_query((CompLevel) comp_level); comp_level = adjust_level_for_compilability_query((CompLevel) comp_level);
if (comp_level == CompLevel_all || is_compile(comp_level)) { if (comp_level == CompLevel_any || is_compile(comp_level)) {
result = !m->is_not_osr_compilable(comp_level); result = !m->is_not_osr_compilable(comp_level);
} }
return (result && can_be_compiled(m, comp_level)); return (result && can_be_compiled(m, comp_level));
Expand Down
6 changes: 3 additions & 3 deletions src/hotspot/share/compiler/compilationPolicy.hpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ class CompilationPolicy : AllStatic {
static jlong start_time() { return _start_time; } static jlong start_time() { return _start_time; }


// m must be compiled before executing it // m must be compiled before executing it
static bool must_be_compiled(const methodHandle& m, int comp_level = CompLevel_all); static bool must_be_compiled(const methodHandle& m, int comp_level = CompLevel_any);
public: public:
static int c1_count() { return _c1_count; } static int c1_count() { return _c1_count; }
static int c2_count() { return _c2_count; } static int c2_count() { return _c2_count; }
Expand All @@ -248,9 +248,9 @@ class CompilationPolicy : AllStatic {
static void compile_if_required(const methodHandle& m, TRAPS); static void compile_if_required(const methodHandle& m, TRAPS);


// m is allowed to be compiled // m is allowed to be compiled
static bool can_be_compiled(const methodHandle& m, int comp_level = CompLevel_all); static bool can_be_compiled(const methodHandle& m, int comp_level = CompLevel_any);
// m is allowed to be osr compiled // m is allowed to be osr compiled
static bool can_be_osr_compiled(const methodHandle& m, int comp_level = CompLevel_all); static bool can_be_osr_compiled(const methodHandle& m, int comp_level = CompLevel_any);
static bool is_compilation_enabled(); static bool is_compilation_enabled();


static void do_safepoint_work() { } static void do_safepoint_work() { }
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/compiler/compilerDefinitions.hpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ enum MethodCompilation {


// Enumeration to distinguish tiers of compilation // Enumeration to distinguish tiers of compilation
enum CompLevel { enum CompLevel {
CompLevel_any = -2, CompLevel_any = -2, // Used for querying the state
CompLevel_all = -2, CompLevel_all = -2, // Used for changing the state
CompLevel_aot = -1, CompLevel_aot = -1,
CompLevel_none = 0, // Interpreter CompLevel_none = 0, // Interpreter
CompLevel_simple = 1, // C1 CompLevel_simple = 1, // C1
Expand Down
48 changes: 44 additions & 4 deletions src/hotspot/share/prims/whitebox.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -832,6 +832,25 @@ WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method, j
return (code->is_alive() && !code->is_marked_for_deoptimization()); return (code->is_alive() && !code->is_marked_for_deoptimization());
WB_END WB_END


static bool is_excluded_for_compiler(AbstractCompiler* comp, methodHandle& mh) {
if (comp == NULL) {
return true;
}
DirectiveSet* directive = DirectivesStack::getMatchingDirective(mh, comp);
if (directive->ExcludeOption) {
return true;
}
return false;
}

static bool can_be_compiled_at_level(methodHandle& mh, jboolean is_osr, int level) {
if (is_osr) {
return CompilationPolicy::can_be_osr_compiled(mh, level);
} else {
return CompilationPolicy::can_be_compiled(mh, level);
}
}

WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level, jboolean is_osr)) WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level, jboolean is_osr))
if (method == NULL || comp_level > CompilationPolicy::highest_compile_level()) { if (method == NULL || comp_level > CompilationPolicy::highest_compile_level()) {
return false; return false;
Expand All @@ -840,11 +859,32 @@ WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method,
CHECK_JNI_EXCEPTION_(env, JNI_FALSE); CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
MutexLocker mu(Compile_lock); MutexLocker mu(Compile_lock);
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
if (is_osr) {
return CompilationPolicy::can_be_osr_compiled(mh, comp_level); // The ExcludeOption directive is evaluated lazily upon compilation attempt. If a method was not tried to be compiled by
} else { // a compiler, yet, the method object is not set to be not compilable by that compiler. Thus, evaluate the compiler directive
return CompilationPolicy::can_be_compiled(mh, comp_level); // to exclude a compilation of 'method'.
if (comp_level == CompLevel_any) {
// Both compilers could have ExcludeOption set. Check all combinations.
bool excluded_c1 = is_excluded_for_compiler(CompileBroker::compiler1(), mh);
bool excluded_c2 = is_excluded_for_compiler(CompileBroker::compiler2(), mh);
if (excluded_c1 && excluded_c2) {
// Compilation of 'method' excluded by both compilers.
return false;
}

if (excluded_c1) {
// C1 only has ExcludeOption set: Check if compilable with C2.
return can_be_compiled_at_level(mh, is_osr, CompLevel_full_optimization);
} else if (excluded_c2) {
// C2 only has ExcludeOption set: Check if compilable with C1.
return can_be_compiled_at_level(mh, is_osr, CompLevel_simple);
}
} else if (comp_level > CompLevel_none && is_excluded_for_compiler(CompileBroker::compiler((int)comp_level), mh)) {
// Compilation of 'method' excluded by compiler used for 'comp_level'.
return false;
} }

return can_be_compiled_at_level(mh, is_osr, (int)comp_level);
WB_END WB_END


WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method)) WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method))
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2021, 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
* @summary Tests WB::isMethodCompilable(m) in combination with compiler directives that prevent a compilation of m.
* @bug 8263582
* @library /test/lib /
* @build sun.hotspot.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:CompileCommand=compileonly,compiler.whitebox.TestMethodCompilableCompilerDirectives::doesNotExist
* compiler.whitebox.TestMethodCompilableCompilerDirectives
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:CompileCommand=exclude,compiler.whitebox.TestMethodCompilableCompilerDirectives::*
* compiler.whitebox.TestMethodCompilableCompilerDirectives
*/

package compiler.whitebox;

import jdk.test.lib.Asserts;
import sun.hotspot.WhiteBox;
import java.lang.reflect.Method;

public class TestMethodCompilableCompilerDirectives {
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();

// Method too simple for C2 and only C1 compiled.
public static int c1Compiled() {
return 3;
}


// Method first C1 and then C2 compiled.
public static int c2Compiled() {
for (int i = 0; i < 100; i++);
return 3;
}

// WB::isMethodCompilable(m) uses Method::is_not_compilable() to decide if m is compilable. Method::is_not_compilable(), however,
// returns false regardless of any compiler directives if m was not yet tried to be compiled. The compiler directive ExcludeOption
// to prevent a compilation is evaluated lazily and is only applied when a compilation for m is attempted.
// Another problem is that Method::is_not_compilable() only returns true for CompLevel_any if C1 AND C2 cannot compile it.
// This means that a compilation of m must have been attempted for C1 and C2 before WB::isMethodCompilable(m, CompLevel_any) will
// ever return false. This disregards any compiler directives (e.g. compileonly, exclude) that prohibit a compilation of m completely.
// WB::isMethodCompilable() should be aware of the ExcludeOption compiler directives at any point in time.
public static void main(String[] args) throws NoSuchMethodException {
Method c1CompiledMethod = TestMethodCompilableCompilerDirectives.class.getDeclaredMethod("c1Compiled");
Method c2CompiledMethod = TestMethodCompilableCompilerDirectives.class.getDeclaredMethod("c2Compiled");

boolean compilable = WhiteBox.getWhiteBox().isMethodCompilable(c1CompiledMethod);
Asserts.assertFalse(compilable);
for (int i = 0; i < 3000; i++) {
c1Compiled();
}
compilable = WhiteBox.getWhiteBox().isMethodCompilable(c1CompiledMethod);
Asserts.assertFalse(compilable);


compilable = WhiteBox.getWhiteBox().isMethodCompilable(c2CompiledMethod);
Asserts.assertFalse(compilable);
for (int i = 0; i < 3000; i++) {
c2Compiled();
}
compilable = WhiteBox.getWhiteBox().isMethodCompilable(c2CompiledMethod);
Asserts.assertFalse(compilable);
}
}

1 comment on commit ab6faa6

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.