Implicit null/suspend checks (oat version bump)
This adds the ability to use SEGV signals
to throw NullPointerException exceptions from Java code rather
than having the compiler generate explicit comparisons and
branches. It does this by using sigaction to trap SIGSEGV and when triggered
makes sure it's in compiled code and if so, sets the return
address to the entry point to throw the exception.
It also uses this signal mechanism to determine whether to check
for thread suspension. Instead of the compiler generating calls
to a function to check for threads being suspended, the compiler
will now load indirect via an address in the TLS area. To trigger
a suspend, the contents of this address are changed from something
valid to 0. A SIGSEGV will occur and the handler will check
for a valid instruction pattern before invoking the thread
suspension check code.
If a user program taps SIGSEGV it will prevent our signal handler
working. This will cause a failure in the runtime.
There are two signal handlers at present. You can control them
individually using the flags -implicit-checks: on the runtime
command line. This takes a string parameter, a comma
separated set of strings. Each can be one of:
none switch off
null null pointer checks
suspend suspend checks
all all checks
So to switch only suspend checks on, pass:
-implicit-checks:suspend
There is also -explicit-checks to provide the reverse once
we change the default.
For dalvikvm, pass --runtime-arg -implicit-checks:foo,bar
The default is -implicit-checks:none
There is also a property 'dalvik.vm.implicit_checks' whose value is the same
string as the command option. The default is 'none'. For example to switch on
null checks using the option:
setprop dalvik.vm.implicit_checks null
It only works for ARM right now.
Bumps OAT version number due to change to Thread offsets.
Bug: 13121132
Change-Id: If743849138162f3c7c44a523247e413785677370
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 0fce5bb..bba3d40 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -214,8 +214,9 @@
GenMemBarrier(kLoadLoad);
} else {
// Explicit null-check as slow-path is entered using an IT.
- GenNullCheck(rl_src.s_reg_low, r0, opt_flags);
+ GenNullCheck(r0, opt_flags);
LoadWordDisp(rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2);
+ MarkPossibleNullPointerException(opt_flags);
NewLIR3(kThumb2Ldrex, r1, r0, mirror::Object::MonitorOffset().Int32Value() >> 2);
OpRegImm(kOpCmp, r1, 0);
OpIT(kCondEq, "");
@@ -273,8 +274,9 @@
GenMemBarrier(kStoreLoad);
} else {
// Explicit null-check as slow-path is entered using an IT.
- GenNullCheck(rl_src.s_reg_low, r0, opt_flags);
+ GenNullCheck(r0, opt_flags);
LoadWordDisp(r0, mirror::Object::MonitorOffset().Int32Value(), r1); // Get lock
+ MarkPossibleNullPointerException(opt_flags);
LoadWordDisp(rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2);
LoadConstantNoClobber(r3, 0);
// Is lock unheld on lock or held by us (==thread_id) on unlock?
@@ -340,8 +342,10 @@
Thread::kStackOverflowReservedBytes));
NewLIR0(kPseudoMethodEntry);
if (!skip_overflow_check) {
- /* Load stack limit */
- LoadWordDisp(rARM_SELF, Thread::StackEndOffset().Int32Value(), r12);
+ if (Runtime::Current()->ExplicitStackOverflowChecks()) {
+ /* Load stack limit */
+ LoadWordDisp(rARM_SELF, Thread::StackEndOffset().Int32Value(), r12);
+ }
}
/* Spill core callee saves */
NewLIR1(kThumb2Push, core_spill_mask_);
@@ -355,9 +359,20 @@
NewLIR1(kThumb2VPushCS, num_fp_spills_);
}
if (!skip_overflow_check) {
- OpRegRegImm(kOpSub, rARM_LR, rARM_SP, frame_size_ - (spill_count * 4));
- GenRegRegCheck(kCondUlt, rARM_LR, r12, kThrowStackOverflow);
- OpRegCopy(rARM_SP, rARM_LR); // Establish stack
+ if (Runtime::Current()->ExplicitStackOverflowChecks()) {
+ OpRegRegImm(kOpSub, rARM_LR, rARM_SP, frame_size_ - (spill_count * 4));
+ GenRegRegCheck(kCondUlt, rARM_LR, r12, kThrowStackOverflow);
+ OpRegCopy(rARM_SP, rARM_LR); // Establish stack
+ } else {
+ // Implicit stack overflow check.
+ // Generate a load from [sp, #-framesize]. If this is in the stack
+ // redzone we will get a segmentation fault.
+ uint32_t full_frame_size = frame_size_ - (spill_count * 4);
+
+ OpRegImm(kOpSub, rARM_SP, full_frame_size);
+ LoadWordDisp(rARM_SP, 0, rARM_LR);
+ MarkPossibleStackOverflowException();
+ }
} else {
OpRegImm(kOpSub, rARM_SP, frame_size_ - (spill_count * 4));
}
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 2c0cead..6e72c80 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -30,6 +30,7 @@
bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
RegLocation rl_dest, int lit);
int LoadHelper(ThreadOffset offset);
+ LIR* CheckSuspendUsingLoad() OVERRIDE;
LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
int s_reg);
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index fb2096f..d22219a 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -938,7 +938,7 @@
}
/* null object? */
- GenNullCheck(rl_array.s_reg_low, rl_array.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_array.reg.GetReg(), opt_flags);
bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
int reg_len = INVALID_REG;
@@ -946,6 +946,9 @@
reg_len = AllocTemp();
/* Get len */
LoadWordDisp(rl_array.reg.GetReg(), len_offset, reg_len);
+ MarkPossibleNullPointerException(opt_flags);
+ } else {
+ ForceImplicitNullCheck(rl_array.reg.GetReg(), opt_flags);
}
if (rl_dest.wide || rl_dest.fp || constant_index) {
int reg_ptr;
@@ -969,13 +972,16 @@
FreeTemp(reg_len);
}
if (rl_dest.wide) {
- LoadBaseDispWide(reg_ptr, data_offset, rl_result.reg.GetReg(), rl_result.reg.GetHighReg(), INVALID_SREG);
+ LoadBaseDispWide(reg_ptr, data_offset, rl_result.reg.GetReg(), rl_result.reg.GetHighReg(),
+ INVALID_SREG);
+ MarkPossibleNullPointerException(opt_flags);
if (!constant_index) {
FreeTemp(reg_ptr);
}
StoreValueWide(rl_dest, rl_result);
} else {
LoadBaseDisp(reg_ptr, data_offset, rl_result.reg.GetReg(), size, INVALID_SREG);
+ MarkPossibleNullPointerException(opt_flags);
if (!constant_index) {
FreeTemp(reg_ptr);
}
@@ -993,6 +999,7 @@
FreeTemp(reg_len);
}
LoadBaseIndexed(reg_ptr, rl_index.reg.GetReg(), rl_result.reg.GetReg(), scale, size);
+ MarkPossibleNullPointerException(opt_flags);
FreeTemp(reg_ptr);
StoreValue(rl_dest, rl_result);
}
@@ -1038,7 +1045,7 @@
}
/* null object? */
- GenNullCheck(rl_array.s_reg_low, rl_array.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_array.reg.GetReg(), opt_flags);
bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
int reg_len = INVALID_REG;
@@ -1047,6 +1054,9 @@
// NOTE: max live temps(4) here.
/* Get len */
LoadWordDisp(rl_array.reg.GetReg(), len_offset, reg_len);
+ MarkPossibleNullPointerException(opt_flags);
+ } else {
+ ForceImplicitNullCheck(rl_array.reg.GetReg(), opt_flags);
}
/* at this point, reg_ptr points to array, 2 live temps */
if (rl_src.wide || rl_src.fp || constant_index) {
@@ -1073,6 +1083,7 @@
} else {
StoreBaseDisp(reg_ptr, data_offset, rl_src.reg.GetReg(), size);
}
+ MarkPossibleNullPointerException(opt_flags);
} else {
/* reg_ptr -> array data */
OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg.GetReg(), data_offset);
@@ -1083,6 +1094,7 @@
}
StoreBaseIndexed(reg_ptr, rl_index.reg.GetReg(), rl_src.reg.GetReg(),
scale, size);
+ MarkPossibleNullPointerException(opt_flags);
}
if (allocated_reg_ptr_temp) {
FreeTemp(reg_ptr);
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 01d669b..7f8656a 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -727,6 +727,13 @@
return rARM_LR;
}
+LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
+ int tmp = r0;
+ LoadWordDisp(rARM_SELF, Thread::ThreadSuspendTriggerOffset().Int32Value(), tmp);
+ LIR* load2 = LoadWordDisp(tmp, 0, tmp);
+ return load2;
+}
+
uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
DCHECK(!IsPseudoLirOp(opcode));
return ArmMir2Lir::EncodingMap[opcode].flags;
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 1c5f6a0..2384c7f 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -66,12 +66,45 @@
return branch;
}
+
/* Perform null-check on a register. */
-LIR* Mir2Lir::GenNullCheck(int s_reg, int m_reg, int opt_flags) {
- if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
- return NULL;
+LIR* Mir2Lir::GenNullCheck(int m_reg, int opt_flags) {
+ if (Runtime::Current()->ExplicitNullChecks()) {
+ if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
+ return NULL;
+ }
+ return GenImmedCheck(kCondEq, m_reg, 0, kThrowNullPointer);
}
- return GenImmedCheck(kCondEq, m_reg, 0, kThrowNullPointer);
+ return nullptr;
+}
+
+void Mir2Lir::MarkPossibleNullPointerException(int opt_flags) {
+ if (!Runtime::Current()->ExplicitNullChecks()) {
+ if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
+ return;
+ }
+ MarkSafepointPC(last_lir_insn_);
+ }
+}
+
+void Mir2Lir::MarkPossibleStackOverflowException() {
+ if (!Runtime::Current()->ExplicitStackOverflowChecks()) {
+ MarkSafepointPC(last_lir_insn_);
+ }
+}
+
+void Mir2Lir::ForceImplicitNullCheck(int reg, int opt_flags) {
+ if (!Runtime::Current()->ExplicitNullChecks()) {
+ if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
+ return;
+ }
+ // Force an implicit null check by performing a memory operation (load) from the given
+ // register with offset 0. This will cause a signal if the register contains 0 (null).
+ int tmp = AllocTemp();
+ LIR* load = LoadWordDisp(reg, 0, tmp);
+ FreeTemp(tmp);
+ MarkSafepointPC(load);
+ }
}
/* Perform check on two registers */
@@ -680,12 +713,14 @@
rl_obj = LoadValue(rl_obj, kCoreReg);
if (is_long_or_double) {
DCHECK(rl_dest.wide);
- GenNullCheck(rl_obj.s_reg_low, rl_obj.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_obj.reg.GetReg(), opt_flags);
if (cu_->instruction_set == kX86) {
rl_result = EvalLoc(rl_dest, reg_class, true);
- GenNullCheck(rl_obj.s_reg_low, rl_obj.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_obj.reg.GetReg(), opt_flags);
LoadBaseDispWide(rl_obj.reg.GetReg(), field_info.FieldOffset().Int32Value(),
- rl_result.reg.GetReg(), rl_result.reg.GetHighReg(), rl_obj.s_reg_low);
+ rl_result.reg.GetReg(),
+ rl_result.reg.GetHighReg(), rl_obj.s_reg_low);
+ MarkPossibleNullPointerException(opt_flags);
if (field_info.IsVolatile()) {
GenMemBarrier(kLoadLoad);
}
@@ -703,9 +738,10 @@
StoreValueWide(rl_dest, rl_result);
} else {
rl_result = EvalLoc(rl_dest, reg_class, true);
- GenNullCheck(rl_obj.s_reg_low, rl_obj.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_obj.reg.GetReg(), opt_flags);
LoadBaseDisp(rl_obj.reg.GetReg(), field_info.FieldOffset().Int32Value(),
rl_result.reg.GetReg(), kWord, rl_obj.s_reg_low);
+ MarkPossibleNullPointerException(opt_flags);
if (field_info.IsVolatile()) {
GenMemBarrier(kLoadLoad);
}
@@ -739,25 +775,27 @@
if (is_long_or_double) {
int reg_ptr;
rl_src = LoadValueWide(rl_src, kAnyReg);
- GenNullCheck(rl_obj.s_reg_low, rl_obj.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_obj.reg.GetReg(), opt_flags);
reg_ptr = AllocTemp();
OpRegRegImm(kOpAdd, reg_ptr, rl_obj.reg.GetReg(), field_info.FieldOffset().Int32Value());
if (field_info.IsVolatile()) {
GenMemBarrier(kStoreStore);
}
StoreBaseDispWide(reg_ptr, 0, rl_src.reg.GetReg(), rl_src.reg.GetHighReg());
+ MarkPossibleNullPointerException(opt_flags);
if (field_info.IsVolatile()) {
GenMemBarrier(kLoadLoad);
}
FreeTemp(reg_ptr);
} else {
rl_src = LoadValue(rl_src, reg_class);
- GenNullCheck(rl_obj.s_reg_low, rl_obj.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_obj.reg.GetReg(), opt_flags);
if (field_info.IsVolatile()) {
GenMemBarrier(kStoreStore);
}
StoreBaseDisp(rl_obj.reg.GetReg(), field_info.FieldOffset().Int32Value(),
- rl_src.reg.GetReg(), kWord);
+ rl_src.reg.GetReg(), kWord);
+ MarkPossibleNullPointerException(opt_flags);
if (field_info.IsVolatile()) {
GenMemBarrier(kLoadLoad);
}
@@ -1929,31 +1967,53 @@
/* Check if we need to check for pending suspend request */
void Mir2Lir::GenSuspendTest(int opt_flags) {
- if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
- return;
+ if (Runtime::Current()->ExplicitSuspendChecks()) {
+ if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
+ return;
+ }
+ FlushAllRegs();
+ LIR* branch = OpTestSuspend(NULL);
+ LIR* ret_lab = NewLIR0(kPseudoTargetLabel);
+ LIR* target = RawLIR(current_dalvik_offset_, kPseudoSuspendTarget, WrapPointer(ret_lab),
+ current_dalvik_offset_);
+ branch->target = target;
+ suspend_launchpads_.Insert(target);
+ } else {
+ if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
+ return;
+ }
+ FlushAllRegs(); // TODO: needed?
+ LIR* inst = CheckSuspendUsingLoad();
+ MarkSafepointPC(inst);
}
- FlushAllRegs();
- LIR* branch = OpTestSuspend(NULL);
- LIR* ret_lab = NewLIR0(kPseudoTargetLabel);
- LIR* target = RawLIR(current_dalvik_offset_, kPseudoSuspendTarget, WrapPointer(ret_lab),
- current_dalvik_offset_);
- branch->target = target;
- suspend_launchpads_.Insert(target);
}
/* Check if we need to check for pending suspend request */
void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) {
- if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
+ if (Runtime::Current()->ExplicitSuspendChecks()) {
+ if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
+ OpUnconditionalBranch(target);
+ return;
+ }
+ OpTestSuspend(target);
+ LIR* launch_pad =
+ RawLIR(current_dalvik_offset_, kPseudoSuspendTarget, WrapPointer(target),
+ current_dalvik_offset_);
+ FlushAllRegs();
+ OpUnconditionalBranch(launch_pad);
+ suspend_launchpads_.Insert(launch_pad);
+ } else {
+ // For the implicit suspend check, just perform the trigger
+ // load and branch to the target.
+ if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
+ OpUnconditionalBranch(target);
+ return;
+ }
+ FlushAllRegs();
+ LIR* inst = CheckSuspendUsingLoad();
+ MarkSafepointPC(inst);
OpUnconditionalBranch(target);
- return;
}
- OpTestSuspend(target);
- LIR* launch_pad =
- RawLIR(current_dalvik_offset_, kPseudoSuspendTarget, WrapPointer(target),
- current_dalvik_offset_);
- FlushAllRegs();
- OpUnconditionalBranch(launch_pad);
- suspend_launchpads_.Insert(launch_pad);
}
/* Call out to helper assembly routine that will null check obj and then lock it. */
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 5d2886e..859a033 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -489,10 +489,11 @@
break;
}
case 1: // Is "this" null? [use kArg1]
- cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
+ cg->GenNullCheck(cg->TargetReg(kArg1), info->opt_flags);
// get this->klass_ [use kArg1, set kInvokeTgt]
cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
cg->TargetReg(kInvokeTgt));
+ cg->MarkPossibleNullPointerException(info->opt_flags);
break;
case 2: // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
@@ -543,10 +544,11 @@
break;
}
case 2: // Is "this" null? [use kArg1]
- cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
+ cg->GenNullCheck(cg->TargetReg(kArg1), info->opt_flags);
// Get this->klass_ [use kArg1, set kInvokeTgt]
cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
cg->TargetReg(kInvokeTgt));
+ cg->MarkPossibleNullPointerException(info->opt_flags);
break;
case 3: // Get this->klass_->imtable [use kInvokeTgt, set kInvokeTgt]
cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::ImTableOffset().Int32Value(),
@@ -753,7 +755,7 @@
type, skip_this);
if (pcrLabel) {
- *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
+ *pcrLabel = GenNullCheck(TargetReg(kArg1), info->opt_flags);
}
return call_state;
}
@@ -957,7 +959,7 @@
call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
if (pcrLabel) {
- *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
+ *pcrLabel = GenNullCheck(TargetReg(kArg1), info->opt_flags);
}
return call_state;
}
@@ -1004,7 +1006,7 @@
rl_idx = LoadValue(rl_idx, kCoreReg);
}
int reg_max;
- GenNullCheck(rl_obj.s_reg_low, rl_obj.reg.GetReg(), info->opt_flags);
+ GenNullCheck(rl_obj.reg.GetReg(), info->opt_flags);
bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
LIR* range_check_branch = nullptr;
int reg_off = INVALID_REG;
@@ -1015,8 +1017,10 @@
if (range_check) {
reg_max = AllocTemp();
LoadWordDisp(rl_obj.reg.GetReg(), count_offset, reg_max);
+ MarkPossibleNullPointerException(info->opt_flags);
}
LoadWordDisp(rl_obj.reg.GetReg(), offset_offset, reg_off);
+ MarkPossibleNullPointerException(info->opt_flags);
LoadWordDisp(rl_obj.reg.GetReg(), value_offset, reg_ptr);
if (range_check) {
// Set up a launch pad to allow retry in case of bounds violation */
@@ -1082,8 +1086,10 @@
rl_obj = LoadValue(rl_obj, kCoreReg);
RegLocation rl_dest = InlineTarget(info);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
- GenNullCheck(rl_obj.s_reg_low, rl_obj.reg.GetReg(), info->opt_flags);
- LoadWordDisp(rl_obj.reg.GetReg(), mirror::String::CountOffset().Int32Value(), rl_result.reg.GetReg());
+ GenNullCheck(rl_obj.reg.GetReg(), info->opt_flags);
+ LoadWordDisp(rl_obj.reg.GetReg(), mirror::String::CountOffset().Int32Value(),
+ rl_result.reg.GetReg());
+ MarkPossibleNullPointerException(info->opt_flags);
if (is_empty) {
// dst = (dst == 0);
if (cu_->instruction_set == kThumb2) {
@@ -1281,7 +1287,7 @@
LoadValueDirectFixed(rl_start, reg_start);
}
int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pIndexOf));
- GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags);
+ GenNullCheck(reg_ptr, info->opt_flags);
LIR* high_code_point_branch =
rl_char.is_const ? nullptr : OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, nullptr);
// NOTE: not a safepoint
@@ -1319,7 +1325,7 @@
LoadValueDirectFixed(rl_cmp, reg_cmp);
int r_tgt = (cu_->instruction_set != kX86) ?
LoadHelper(QUICK_ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
- GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags);
+ GenNullCheck(reg_this, info->opt_flags);
info->opt_flags |= MIR_IGNORE_NULL_CHECK; // Record that we've null checked.
// TUNING: check if rl_cmp.s_reg_low is already null checked
LIR* cmp_null_check_branch = OpCmpImmBranch(kCondEq, reg_cmp, 0, nullptr);
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 61eb68d..28ebe0e 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -30,6 +30,7 @@
bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
RegLocation rl_dest, int lit);
int LoadHelper(ThreadOffset offset);
+ LIR* CheckSuspendUsingLoad() OVERRIDE;
LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
int s_reg);
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index fec801b..9fcc8bb 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -471,7 +471,7 @@
}
/* null object? */
- GenNullCheck(rl_array.s_reg_low, rl_array.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_array.reg.GetReg(), opt_flags);
int reg_ptr = AllocTemp();
bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
@@ -548,7 +548,7 @@
}
/* null object? */
- GenNullCheck(rl_array.s_reg_low, rl_array.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_array.reg.GetReg(), opt_flags);
bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
int reg_len = INVALID_REG;
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 4f495ee..b7fb2f4 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -512,6 +512,14 @@
return r_T9;
}
+LIR* MipsMir2Lir::CheckSuspendUsingLoad() {
+ int tmp = AllocTemp();
+ LoadWordDisp(rMIPS_SELF, Thread::ThreadSuspendTriggerOffset().Int32Value(), tmp);
+ LIR *inst = LoadWordDisp(tmp, 0, tmp);
+ FreeTemp(tmp);
+ return inst;
+}
+
void MipsMir2Lir::SpillCoreRegs() {
if (num_core_spills_ == 0) {
return;
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index f93a5e3..538c292 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -437,7 +437,7 @@
int len_offset;
len_offset = mirror::Array::LengthOffset().Int32Value();
rl_src[0] = LoadValue(rl_src[0], kCoreReg);
- GenNullCheck(rl_src[0].s_reg_low, rl_src[0].reg.GetReg(), opt_flags);
+ GenNullCheck(rl_src[0].reg.GetReg(), opt_flags);
rl_result = EvalLoc(rl_dest, kCoreReg, true);
LoadWordDisp(rl_src[0].reg.GetReg(), len_offset, rl_result.reg.GetReg());
StoreValue(rl_dest, rl_result);
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index e2326bb..048b157 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -546,7 +546,10 @@
LIR* GenCheck(ConditionCode c_code, ThrowKind kind);
LIR* GenImmedCheck(ConditionCode c_code, int reg, int imm_val,
ThrowKind kind);
- LIR* GenNullCheck(int s_reg, int m_reg, int opt_flags);
+ LIR* GenNullCheck(int m_reg, int opt_flags);
+ void MarkPossibleNullPointerException(int opt_flags);
+ void MarkPossibleStackOverflowException();
+ void ForceImplicitNullCheck(int reg, int opt_flags);
LIR* GenRegRegCheck(ConditionCode c_code, int reg1, int reg2,
ThrowKind kind);
void GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1,
@@ -796,6 +799,7 @@
virtual bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
RegLocation rl_src, RegLocation rl_dest, int lit) = 0;
virtual int LoadHelper(ThreadOffset offset) = 0;
+ virtual LIR* CheckSuspendUsingLoad() = 0;
virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg) = 0;
virtual LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
int s_reg) = 0;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 8269898..275a2d9 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -30,6 +30,7 @@
bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, RegLocation rl_src,
RegLocation rl_dest, int lit);
int LoadHelper(ThreadOffset offset);
+ LIR* CheckSuspendUsingLoad() OVERRIDE;
LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
int s_reg);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index d7eeeac..a67c43c 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1298,7 +1298,7 @@
}
/* null object? */
- GenNullCheck(rl_array.s_reg_low, rl_array.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_array.reg.GetReg(), opt_flags);
if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
if (constant_index) {
@@ -1352,7 +1352,7 @@
}
/* null object? */
- GenNullCheck(rl_array.s_reg_low, rl_array.reg.GetReg(), opt_flags);
+ GenNullCheck(rl_array.reg.GetReg(), opt_flags);
if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
if (constant_index) {
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index c70efa4..7b2be0e 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -552,6 +552,11 @@
return INVALID_REG;
}
+LIR* X86Mir2Lir::CheckSuspendUsingLoad() {
+ LOG(FATAL) << "Unexpected use of CheckSuspendUsingLoad in x86";
+ return nullptr;
+}
+
uint64_t X86Mir2Lir::GetTargetInstFlags(int opcode) {
DCHECK(!IsPseudoLirOp(opcode));
return X86Mir2Lir::EncodingMap[opcode].flags;
@@ -975,7 +980,7 @@
// Is the string non-NULL?
LoadValueDirectFixed(rl_obj, rDX);
- GenNullCheck(rl_obj.s_reg_low, rDX, info->opt_flags);
+ GenNullCheck(rDX, info->opt_flags);
info->opt_flags |= MIR_IGNORE_NULL_CHECK; // Record that we've null checked.
// Does the character fit in 16 bits?