Add implicit null pointer and stack overflow checks for Mips.

Bug: 21555893
Change-Id: I2a995be128a5603d08753c14956dd8c8240ac63c
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index da12d8e..853980d 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -24,6 +24,7 @@
 #include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/accounting/card_table.h"
 #include "mips_lir.h"
@@ -285,12 +286,25 @@
   RegStorage check_reg = AllocPtrSizeTemp();
   RegStorage new_sp = AllocPtrSizeTemp();
   const RegStorage rs_sp = TargetPtrReg(kSp);
+  const size_t kStackOverflowReservedUsableBytes = GetStackOverflowReservedBytes(target);
+  const bool large_frame = static_cast<size_t>(frame_size_) > kStackOverflowReservedUsableBytes;
+  bool generate_explicit_stack_overflow_check = large_frame ||
+    !cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks();
+
   if (!skip_overflow_check) {
-    // Load stack limit.
-    if (cu_->target64) {
-      LoadWordDisp(TargetPtrReg(kSelf), Thread::StackEndOffset<8>().Int32Value(), check_reg);
+    if (generate_explicit_stack_overflow_check) {
+      // Load stack limit.
+      if (cu_->target64) {
+        LoadWordDisp(TargetPtrReg(kSelf), Thread::StackEndOffset<8>().Int32Value(), check_reg);
+      } else {
+        Load32Disp(TargetPtrReg(kSelf), Thread::StackEndOffset<4>().Int32Value(), check_reg);
+      }
     } else {
-      Load32Disp(TargetPtrReg(kSelf), Thread::StackEndOffset<4>().Int32Value(), check_reg);
+      // Implicit stack overflow check.
+      // Generate a load from [sp, #-overflowsize].  If this is in the stack
+      // redzone we will get a segmentation fault.
+      Load32Disp(rs_sp, -kStackOverflowReservedUsableBytes, rs_rZERO);
+      MarkPossibleStackOverflowException();
     }
   }
   // Spill core callee saves.
@@ -298,7 +312,7 @@
   // NOTE: promotion of FP regs currently unsupported, thus no FP spill.
   DCHECK_EQ(num_fp_spills_, 0);
   const int frame_sub = frame_size_ - spill_count * ptr_size;
-  if (!skip_overflow_check) {
+  if (!skip_overflow_check && generate_explicit_stack_overflow_check) {
     class StackOverflowSlowPath : public LIRSlowPath {
      public:
       StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, size_t sp_displace)
@@ -329,6 +343,8 @@
     OpRegCopy(rs_sp, new_sp);  // Establish stack.
     cfi_.AdjustCFAOffset(frame_sub);
   } else {
+    // Here if skip_overflow_check or doing implicit stack overflow check.
+    // Just make room on the stack for the frame now.
     OpRegImm(kOpSub, rs_sp, frame_sub);
     cfi_.AdjustCFAOffset(frame_sub);
   }
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 713264e..43fbcbd 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -79,6 +79,7 @@
   OVERRIDE;
   LIR* CheckSuspendUsingLoad() OVERRIDE;
   RegStorage LoadHelper(QuickEntrypointEnum trampoline) OVERRIDE;
+  void ForceImplicitNullCheck(RegStorage reg, int opt_flags, bool is_wide);
   LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size,
                     VolatileKind is_volatile) OVERRIDE;
   LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index f5ad7c7..1099303 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -691,6 +691,9 @@
     reg_len = AllocTemp();
     // Get len.
     Load32Disp(rl_array.reg, len_offset, reg_len);
+    MarkPossibleNullPointerException(opt_flags);
+  } else {
+    ForceImplicitNullCheck(rl_array.reg, opt_flags, false);
   }
   // reg_ptr -> array data.
   OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
@@ -781,6 +784,9 @@
     // NOTE: max live temps(4) here.
     // Get len.
     Load32Disp(rl_array.reg, len_offset, reg_len);
+    MarkPossibleNullPointerException(opt_flags);
+  } else {
+    ForceImplicitNullCheck(rl_array.reg, opt_flags, false);
   }
   // reg_ptr -> array data.
   OpRegImm(kOpAdd, reg_ptr, data_offset);
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 4c0bd83..b098bc2 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -791,6 +791,7 @@
   RegStorage reg_ptr = TargetReg(kArg0);
   OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
   RegStorage r_tgt = LoadHelper(kQuickA64Load);
+  ForceImplicitNullCheck(reg_ptr, 0, true);  // is_wide = true
   LIR *ret = OpReg(kOpBlx, r_tgt);
   RegStorage reg_ret;
   if (cu_->target64) {
@@ -813,6 +814,7 @@
   LockCallTemps();  // Using fixed registers.
   RegStorage temp_ptr = AllocTemp();
   OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
+  ForceImplicitNullCheck(temp_ptr, 0, true);  // is_wide = true
   RegStorage temp_value = AllocTempWide();
   OpRegCopyWide(temp_value, r_src);
   if (cu_->target64) {
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 95c61cd..37e5804 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -21,7 +21,9 @@
 #include "base/logging.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
+#include "dex/mir_graph.h"
 #include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
 #include "mips_lir.h"
 
 namespace art {
@@ -830,6 +832,22 @@
   return res;
 }
 
+void MipsMir2Lir::ForceImplicitNullCheck(RegStorage reg, int opt_flags, bool is_wide) {
+  if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
+    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).
+    LIR* load = Load32Disp(reg, LOWORD_OFFSET, rs_rZERO);
+    MarkSafepointPC(load);
+    if (is_wide) {
+      load = Load32Disp(reg, HIWORD_OFFSET, rs_rZERO);
+      MarkSafepointPC(load);
+    }
+  }
+}
+
 LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size,
                                VolatileKind is_volatile) {
   if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble))