ART: Implicit checks in the compiler are independent from Runtime
When cross-compiling, those flags are independent. This is an
initial CL that helps bypass fatal failures when cross-compiling,
as not all architectures support (and have turned on) implicit
checks.
The actual transport for the target architecture when it is
different from the runtime needs to be implemented in a follow-up
CL.
Bug: 15703710
Change-Id: Idc881a9a4abfd38643b862a491a5af9b8841f693
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 5466abd..dae6a4f 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -190,7 +190,7 @@
null_check_branch = nullptr; // No null check.
} else {
// If the null-check fails its handled by the slow-path to reduce exception related meta-data.
- if (Runtime::Current()->ExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
null_check_branch = OpCmpImmBranch(kCondEq, rs_r0, 0, NULL);
}
}
@@ -261,7 +261,7 @@
null_check_branch = nullptr; // No null check.
} else {
// If the null-check fails its handled by the slow-path to reduce exception related meta-data.
- if (Runtime::Current()->ExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
null_check_branch = OpCmpImmBranch(kCondEq, rs_r0, 0, NULL);
}
}
@@ -362,7 +362,7 @@
NewLIR0(kPseudoMethodEntry);
bool large_frame = (static_cast<size_t>(frame_size_) > Thread::kStackOverflowReservedUsableBytes);
if (!skip_overflow_check) {
- if (Runtime::Current()->ExplicitStackOverflowChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
if (!large_frame) {
/* Load stack limit */
LockTemp(rs_r12);
@@ -401,7 +401,7 @@
const int spill_size = spill_count * 4;
const int frame_size_without_spills = frame_size_ - spill_size;
if (!skip_overflow_check) {
- if (Runtime::Current()->ExplicitStackOverflowChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
class StackOverflowSlowPath : public LIRSlowPath {
public:
StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, bool restore_lr, size_t sp_displace)
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index f1748ef..ddfec2d 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -213,7 +213,7 @@
null_check_branch = nullptr; // No null check.
} else {
// If the null-check fails its handled by the slow-path to reduce exception related meta-data.
- if (Runtime::Current()->ExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
null_check_branch = OpCmpImmBranch(kCondEq, rs_x0, 0, NULL);
}
}
@@ -261,7 +261,7 @@
null_check_branch = nullptr; // No null check.
} else {
// If the null-check fails its handled by the slow-path to reduce exception related meta-data.
- if (Runtime::Current()->ExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
null_check_branch = OpCmpImmBranch(kCondEq, rs_x0, 0, NULL);
}
}
@@ -349,7 +349,7 @@
const int frame_size_without_spills = frame_size_ - spill_size;
if (!skip_overflow_check) {
- if (Runtime::Current()->ExplicitStackOverflowChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
if (!large_frame) {
// Load stack limit
LoadWordDisp(rs_rA64_SELF, Thread::StackEndOffset<8>().Int32Value(), rs_x9);
@@ -382,7 +382,7 @@
}
if (!skip_overflow_check) {
- if (Runtime::Current()->ExplicitStackOverflowChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
class StackOverflowSlowPath: public LIRSlowPath {
public:
StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, size_t sp_displace) :
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index fba368a..06e1cda 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -1163,7 +1163,7 @@
call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
if (pcrLabel) {
- if (Runtime::Current()->ExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
*pcrLabel = GenExplicitNullCheck(TargetReg(kArg1), info->opt_flags);
} else {
*pcrLabel = nullptr;
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 3b99421..e36b592 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -173,7 +173,7 @@
/* Perform null-check on a register. */
LIR* Mir2Lir::GenNullCheck(RegStorage m_reg, int opt_flags) {
- if (Runtime::Current()->ExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
return GenExplicitNullCheck(m_reg, opt_flags);
}
return nullptr;
@@ -188,7 +188,7 @@
}
void Mir2Lir::MarkPossibleNullPointerException(int opt_flags) {
- if (!Runtime::Current()->ExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
return;
}
@@ -197,13 +197,13 @@
}
void Mir2Lir::MarkPossibleStackOverflowException() {
- if (!Runtime::Current()->ExplicitStackOverflowChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
MarkSafepointPC(last_lir_insn_);
}
}
void Mir2Lir::ForceImplicitNullCheck(RegStorage reg, int opt_flags) {
- if (!Runtime::Current()->ExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
return;
}
@@ -2171,7 +2171,7 @@
/* Check if we need to check for pending suspend request */
void Mir2Lir::GenSuspendTest(int opt_flags) {
- if (Runtime::Current()->ExplicitSuspendChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitSuspendChecks()) {
if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
return;
}
@@ -2191,7 +2191,7 @@
/* Check if we need to check for pending suspend request */
void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) {
- if (Runtime::Current()->ExplicitSuspendChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitSuspendChecks()) {
if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
OpUnconditionalBranch(target);
return;
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 641579f..b3fac77 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -977,7 +977,7 @@
type, skip_this);
if (pcrLabel) {
- if (Runtime::Current()->ExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
*pcrLabel = GenExplicitNullCheck(TargetReg(kArg1), info->opt_flags);
} else {
*pcrLabel = nullptr;
@@ -1204,7 +1204,7 @@
call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
if (pcrLabel) {
- if (Runtime::Current()->ExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
*pcrLabel = GenExplicitNullCheck(TargetReg(kArg1), info->opt_flags);
} else {
*pcrLabel = nullptr;
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 483d8cf..2948e56 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -2177,7 +2177,7 @@
call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
if (pcrLabel) {
- if (Runtime::Current()->ExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
*pcrLabel = GenExplicitNullCheck(TargetReg(kArg1), info->opt_flags);
} else {
*pcrLabel = nullptr;
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 5d1c5da..fb3341b 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -53,7 +53,10 @@
num_dex_methods_threshold_(kDefaultNumDexMethodsThreshold),
generate_gdb_information_(false),
top_k_profile_threshold_(kDefaultTopKProfileThreshold),
- include_debug_symbols_(kDefaultIncludeDebugSymbols)
+ include_debug_symbols_(kDefaultIncludeDebugSymbols),
+ explicit_null_checks_(true),
+ explicit_so_checks_(true),
+ explicit_suspend_checks_(true)
#ifdef ART_SEA_IR_MODE
, sea_ir_mode_(false)
#endif
@@ -67,7 +70,10 @@
size_t num_dex_methods_threshold,
bool generate_gdb_information,
double top_k_profile_threshold,
- bool include_debug_symbols
+ bool include_debug_symbols,
+ bool explicit_null_checks,
+ bool explicit_so_checks,
+ bool explicit_suspend_checks
#ifdef ART_SEA_IR_MODE
, bool sea_ir_mode
#endif
@@ -80,7 +86,10 @@
num_dex_methods_threshold_(num_dex_methods_threshold),
generate_gdb_information_(generate_gdb_information),
top_k_profile_threshold_(top_k_profile_threshold),
- include_debug_symbols_(include_debug_symbols)
+ include_debug_symbols_(include_debug_symbols),
+ explicit_null_checks_(explicit_null_checks),
+ explicit_so_checks_(explicit_so_checks),
+ explicit_suspend_checks_(explicit_suspend_checks)
#ifdef ART_SEA_IR_MODE
, sea_ir_mode_(sea_ir_mode)
#endif
@@ -147,6 +156,30 @@
return include_debug_symbols_;
}
+ bool GetExplicitNullChecks() const {
+ return explicit_null_checks_;
+ }
+
+ void SetExplicitNullChecks(bool new_val) {
+ explicit_null_checks_ = new_val;
+ }
+
+ bool GetExplicitStackOverflowChecks() const {
+ return explicit_so_checks_;
+ }
+
+ void SetExplicitStackOverflowChecks(bool new_val) {
+ explicit_so_checks_ = new_val;
+ }
+
+ bool GetExplicitSuspendChecks() const {
+ return explicit_suspend_checks_;
+ }
+
+ void SetExplicitSuspendChecks(bool new_val) {
+ explicit_suspend_checks_ = new_val;
+ }
+
#ifdef ART_SEA_IR_MODE
bool GetSeaIrMode();
#endif
@@ -166,6 +199,9 @@
// When using a profile file only the top K% of the profiled samples will be compiled.
double top_k_profile_threshold_;
bool include_debug_symbols_;
+ bool explicit_null_checks_;
+ bool explicit_so_checks_;
+ bool explicit_suspend_checks_;
#ifdef ART_SEA_IR_MODE
bool sea_ir_mode_;
#endif
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index c3f2082..d7b34dc 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -744,6 +744,19 @@
*parsed_value = value;
}
+void CheckExplicitCheckOptions(InstructionSet isa, bool* explicit_null_checks,
+ bool* explicit_so_checks, bool* explicit_suspend_checks) {
+ switch (isa) {
+ case kArm:
+ break; // All checks implemented, leave as is.
+
+ default: // No checks implemented, reset all to explicit checks.
+ *explicit_null_checks = true;
+ *explicit_so_checks = true;
+ *explicit_suspend_checks = true;
+ }
+}
+
static int dex2oat(int argc, char** argv) {
#if defined(__linux__) && defined(__arm__)
int major, minor;
@@ -825,6 +838,11 @@
bool watch_dog_enabled = !kIsTargetBuild;
bool generate_gdb_information = kIsDebugBuild;
+ bool explicit_null_checks = true;
+ bool explicit_so_checks = true;
+ bool explicit_suspend_checks = true;
+ bool has_explicit_checks_options = false;
+
for (int i = 0; i < argc; i++) {
const StringPiece option(argv[i]);
const bool log_options = false;
@@ -998,6 +1016,31 @@
} else if (option.starts_with("--dump-cfg-passes=")) {
std::string dump_passes = option.substr(strlen("--dump-cfg-passes=")).data();
PassDriverMEOpts::SetDumpPassList(dump_passes);
+ } else if (option.starts_with("--implicit-checks=")) {
+ std::string checks = option.substr(strlen("--implicit-checks=")).data();
+ std::vector<std::string> checkvec;
+ Split(checks, ',', checkvec);
+ for (auto& str : checkvec) {
+ std::string val = Trim(str);
+ if (val == "none") {
+ explicit_null_checks = true;
+ explicit_so_checks = true;
+ explicit_suspend_checks = true;
+ } else if (val == "null") {
+ explicit_null_checks = false;
+ } else if (val == "suspend") {
+ explicit_suspend_checks = false;
+ } else if (val == "stack") {
+ explicit_so_checks = false;
+ } else if (val == "all") {
+ explicit_null_checks = false;
+ explicit_so_checks = false;
+ explicit_suspend_checks = false;
+ } else {
+ Usage("--implicit-checks passed non-recognized value %s", val.c_str());
+ }
+ has_explicit_checks_options = true;
+ }
} else {
Usage("Unknown argument %s", option.data());
}
@@ -1126,6 +1169,9 @@
Usage("Unknown --compiler-filter value %s", compiler_filter_string);
}
+ CheckExplicitCheckOptions(instruction_set, &explicit_null_checks, &explicit_so_checks,
+ &explicit_suspend_checks);
+
CompilerOptions compiler_options(compiler_filter,
huge_method_threshold,
large_method_threshold,
@@ -1134,7 +1180,10 @@
num_dex_methods_threshold,
generate_gdb_information,
top_k_profile_threshold,
- include_debug_symbols
+ include_debug_symbols,
+ explicit_null_checks,
+ explicit_so_checks,
+ explicit_suspend_checks
#ifdef ART_SEA_IR_MODE
, compiler_options.sea_ir_ = true;
#endif
@@ -1205,6 +1254,18 @@
return EXIT_FAILURE;
}
std::unique_ptr<Dex2Oat> dex2oat(p_dex2oat);
+
+ // TODO: Not sure whether it's a good idea to allow anything else but the runtime option in
+ // this case at all, as we'll have to throw away produced code for a mismatch.
+ if (!has_explicit_checks_options) {
+ if (instruction_set == kRuntimeISA) {
+ Runtime* runtime = Runtime::Current();
+ compiler_options.SetExplicitNullChecks(runtime->ExplicitNullChecks());
+ compiler_options.SetExplicitStackOverflowChecks(runtime->ExplicitStackOverflowChecks());
+ compiler_options.SetExplicitSuspendChecks(runtime->ExplicitSuspendChecks());
+ }
+ }
+
// Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
// give it away now so that we don't starve GC.
Thread* self = Thread::Current();