Merge "Add untested x86-64 downcall and exception assembly."
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index 38d37b0..8a88d61 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -323,7 +323,6 @@
 std::ostream& operator<<(std::ostream& os, const X86ConditionCode& kind);
 
 enum ThrowKind {
-  kThrowNullPointer,
   kThrowArrayBounds,
   kThrowConstantArrayBounds,
   kThrowNoSuchMethod,
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 13fa635..b0bc11d 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -131,7 +131,7 @@
     RegLocation GenDivRem(RegLocation rl_dest, RegStorage reg_lo, RegStorage reg_hi, bool is_div);
     RegLocation GenDivRemLit(RegLocation rl_dest, RegStorage reg_lo, int lit, bool is_div);
     void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    void GenDivZeroCheck(RegStorage reg);
+    void GenDivZeroCheckWide(RegStorage reg);
     void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
     void GenExitSequence();
     void GenSpecialExitSequence();
diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index 8b4171d..c876b3a 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -911,12 +911,12 @@
   }
 }
 
-void ArmMir2Lir::GenDivZeroCheck(RegStorage reg) {
+void ArmMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
   DCHECK(reg.IsPair());   // TODO: support k64BitSolo.
   RegStorage t_reg = AllocTemp();
   NewLIR4(kThumb2OrrRRRs, t_reg.GetReg(), reg.GetLowReg(), reg.GetHighReg(), 0);
   FreeTemp(t_reg);
-  AddDivZeroSlowPath(kCondEq);
+  GenDivZeroCheck(kCondEq);
 }
 
 // Test suspend flag, return target of taken suspend branch
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 73a123e..055f60c 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -58,18 +58,18 @@
   return branch;
 }
 
-void Mir2Lir::AddDivZeroSlowPath(ConditionCode c_code) {
+void Mir2Lir::GenDivZeroException() {
+  LIR* branch = OpUnconditionalBranch(nullptr);
+  AddDivZeroCheckSlowPath(branch);
+}
+
+void Mir2Lir::GenDivZeroCheck(ConditionCode c_code) {
   LIR* branch = OpCondBranch(c_code, nullptr);
   AddDivZeroCheckSlowPath(branch);
 }
 
-void Mir2Lir::AddDivZeroSlowPath(ConditionCode c_code, RegStorage reg, int imm_val) {
-  LIR* branch;
-  if (c_code == kCondAl) {
-    branch = OpUnconditionalBranch(nullptr);
-  } else {
-    branch = OpCmpImmBranch(c_code, reg, imm_val, nullptr);
-  }
+void Mir2Lir::GenDivZeroCheck(RegStorage reg) {
+  LIR* branch = OpCmpImmBranch(kCondEq, reg, 0, nullptr);
   AddDivZeroCheckSlowPath(branch);
 }
 
@@ -80,7 +80,7 @@
         : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch) {
     }
 
-    void Compile() {
+    void Compile() OVERRIDE {
       m2l_->ResetRegPool();
       m2l_->ResetDefTracking();
       GenerateTargetLabel();
@@ -91,6 +91,26 @@
   AddSlowPath(new (arena_) DivZeroCheckSlowPath(this, branch));
 }
 
+LIR* Mir2Lir::GenNullCheck(RegStorage reg) {
+  class NullCheckSlowPath : public Mir2Lir::LIRSlowPath {
+   public:
+    NullCheckSlowPath(Mir2Lir* m2l, LIR* branch)
+        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch) {
+    }
+
+    void Compile() OVERRIDE {
+      m2l_->ResetRegPool();
+      m2l_->ResetDefTracking();
+      GenerateTargetLabel();
+      m2l_->CallRuntimeHelper(QUICK_ENTRYPOINT_OFFSET(4, pThrowNullPointer), true);
+    }
+  };
+
+  LIR* branch = OpCmpImmBranch(kCondEq, reg, 0, nullptr);
+  AddSlowPath(new (arena_) NullCheckSlowPath(this, branch));
+  return branch;
+}
+
 /* Perform null-check on a register.  */
 LIR* Mir2Lir::GenNullCheck(RegStorage m_reg, int opt_flags) {
   if (Runtime::Current()->ExplicitNullChecks()) {
@@ -104,7 +124,7 @@
   if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
     return NULL;
   }
-  return GenImmedCheck(kCondEq, m_reg, 0, kThrowNullPointer);
+  return GenNullCheck(m_reg);
 }
 
 void Mir2Lir::MarkPossibleNullPointerException(int opt_flags) {
@@ -668,9 +688,6 @@
     int v2 = lab->operands[3];
     const bool target_x86 = cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64;
     switch (lab->operands[0]) {
-      case kThrowNullPointer:
-        func_offset = QUICK_ENTRYPOINT_OFFSET(4, pThrowNullPointer);
-        break;
       case kThrowConstantArrayBounds:  // v1 is length reg (for Arm/Mips), v2 constant index
         // v1 holds the constant array index.  Mips/Arm uses v2 for length, x86 reloads.
         if (target_x86) {
@@ -1569,7 +1586,7 @@
       rl_src1 = LoadValue(rl_src1, kCoreReg);
       rl_src2 = LoadValue(rl_src2, kCoreReg);
       if (check_zero) {
-          AddDivZeroSlowPath(kCondEq, rl_src2.reg, 0);
+          GenDivZeroCheck(rl_src2.reg);
       }
       rl_result = GenDivRem(rl_dest, rl_src1.reg, rl_src2.reg, op == kOpDiv);
       done = true;
@@ -1580,7 +1597,7 @@
         rl_src1 = LoadValue(rl_src1, kCoreReg);
         rl_src2 = LoadValue(rl_src2, kCoreReg);
         if (check_zero) {
-            AddDivZeroSlowPath(kCondEq, rl_src2.reg, 0);
+            GenDivZeroCheck(rl_src2.reg);
         }
         rl_result = GenDivRem(rl_dest, rl_src1.reg, rl_src2.reg, op == kOpDiv);
         done = true;
@@ -1595,7 +1612,7 @@
       RegStorage r_tgt = CallHelperSetup(func_offset);
       LoadValueDirectFixed(rl_src1, TargetReg(kArg0));
       if (check_zero) {
-        AddDivZeroSlowPath(kCondEq, TargetReg(kArg1), 0);
+        GenDivZeroCheck(TargetReg(kArg1));
       }
       // NOTE: callout here is not a safepoint.
       CallHelper(r_tgt, func_offset, false /* not a safepoint */);
@@ -1820,7 +1837,7 @@
     case Instruction::REM_INT_LIT8:
     case Instruction::REM_INT_LIT16: {
       if (lit == 0) {
-        AddDivZeroSlowPath(kCondAl, RegStorage::InvalidReg(), 0);
+        GenDivZeroException();
         return;
       }
       if ((opcode == Instruction::DIV_INT) ||
@@ -1994,7 +2011,7 @@
       RegStorage r_tmp2 = RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3));
       LoadValueDirectWideFixed(rl_src2, r_tmp2);
       RegStorage r_tgt = CallHelperSetup(func_offset);
-      GenDivZeroCheck(RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3)));
+      GenDivZeroCheckWide(RegStorage::MakeRegPair(TargetReg(kArg2), TargetReg(kArg3)));
       LoadValueDirectWideFixed(rl_src1, r_tmp1);
       // NOTE: callout here is not a safepoint
       CallHelper(r_tgt, func_offset, false /* not safepoint */);
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index d827568..4aae16d 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1496,7 +1496,7 @@
         ((cu_->disable_opt & (1 << kNullCheckElimination)) != 0 ||
          (info->opt_flags & MIR_IGNORE_NULL_CHECK) == 0))  {
       RegLocation rl_obj = LoadValue(info->args[0], kCoreReg);
-      GenImmedCheck(kCondEq, rl_obj.reg, 0, kThrowNullPointer);
+      GenNullCheck(rl_obj.reg);
     }
     return;
   }
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 5089111..40641d6 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -131,7 +131,7 @@
     RegLocation GenDivRem(RegLocation rl_dest, RegStorage reg_lo, RegStorage reg_hi, bool is_div);
     RegLocation GenDivRemLit(RegLocation rl_dest, RegStorage reg_lo, int lit, bool is_div);
     void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    void GenDivZeroCheck(RegStorage reg);
+    void GenDivZeroCheckWide(RegStorage reg);
     void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
     void GenExitSequence();
     void GenSpecialExitSequence();
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 0492fdb..ac0847f 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -342,11 +342,11 @@
   }
 }
 
-void MipsMir2Lir::GenDivZeroCheck(RegStorage reg) {
+void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
   DCHECK(reg.IsPair());   // TODO: support k64BitSolo.
   RegStorage t_reg = AllocTemp();
   OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
-  AddDivZeroSlowPath(kCondEq, t_reg, 0);
+  GenDivZeroCheck(kCondEq);
   FreeTemp(t_reg);
 }
 
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 6dbeb34..65910e9 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -562,8 +562,12 @@
     void HandleThrowLaunchPads();
     void HandleSlowPaths();
     void GenBarrier();
-    void AddDivZeroSlowPath(ConditionCode c_code);
-    void AddDivZeroSlowPath(ConditionCode c_code, RegStorage reg, int imm_val);
+    void GenDivZeroException();
+    // c_code holds condition code that's generated from testing divisor against 0.
+    void GenDivZeroCheck(ConditionCode c_code);
+    // reg holds divisor.
+    void GenDivZeroCheck(RegStorage reg);
+    LIR* GenNullCheck(RegStorage reg);
     void MarkPossibleNullPointerException(int opt_flags);
     void MarkPossibleStackOverflowException();
     void ForceImplicitNullCheck(RegStorage reg, int opt_flags);
@@ -960,10 +964,9 @@
      * @brief Used for generating code that throws ArithmeticException if both registers are zero.
      * @details This is used for generating DivideByZero checks when divisor is held in two
      *  separate registers.
-     * @param reg_lo The register holding the lower 32-bits.
-     * @param reg_hi The register holding the upper 32-bits.
+     * @param reg The register holding the pair of 32-bit values.
      */
-    virtual void GenDivZeroCheck(RegStorage reg) = 0;
+    virtual void GenDivZeroCheckWide(RegStorage reg) = 0;
 
     virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) = 0;
     virtual void GenExitSequence() = 0;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index af2a140..0b9823d 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -135,7 +135,7 @@
     RegLocation GenDivRem(RegLocation rl_dest, RegStorage reg_lo, RegStorage reg_hi, bool is_div);
     RegLocation GenDivRemLit(RegLocation rl_dest, RegStorage reg_lo, int lit, bool is_div);
     void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    void GenDivZeroCheck(RegStorage reg);
+    void GenDivZeroCheckWide(RegStorage reg);
     void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
     void GenExitSequence();
     void GenSpecialExitSequence();
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index a5f3b61..4ffb9a4 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -629,7 +629,7 @@
 
   if (check_zero) {
     // Handle division by zero case.
-    AddDivZeroSlowPath(kCondEq, rs_r1, 0);
+    GenDivZeroCheck(rs_r1);
   }
 
   // Have to catch 0x80000000/-1 case, or we will get an exception!
@@ -876,7 +876,7 @@
   }
 }
 
-void X86Mir2Lir::GenDivZeroCheck(RegStorage reg) {
+void X86Mir2Lir::GenDivZeroCheckWide(RegStorage reg) {
   DCHECK(reg.IsPair());  // TODO: allow 64BitSolo.
   // We are not supposed to clobber the incoming storage, so allocate a temporary.
   RegStorage t_reg = AllocTemp();
@@ -885,7 +885,7 @@
   OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
 
   // In case of zero, throw ArithmeticException.
-  AddDivZeroSlowPath(kCondEq);
+  GenDivZeroCheck(kCondEq);
 
   // The temp is no longer needed so free it at this time.
   FreeTemp(t_reg);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 5a9d27c..dbde7c7 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -392,7 +392,7 @@
   SirtRef<mirror::DexCache> dex_cache(self, mh.GetDexCache());
   SirtRef<mirror::ClassLoader> class_loader(self, mh.GetClassLoader());
   MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
-                          mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false,
+                          mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true,
                           true);
   return verifier.FindInvokedMethodAtDexPc(dex_pc);
 }
@@ -3119,18 +3119,22 @@
          inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
   const RegType& actual_arg_type = reg_line->GetInvocationThis(inst, is_range);
   if (actual_arg_type.IsConflict()) {  // GetInvocationThis failed.
-    return NULL;
+    return nullptr;
   } else if (actual_arg_type.IsZero()) {  // Invoke on "null" instance: we can't go further.
-    return NULL;
+    return nullptr;
   }
   mirror::Class* this_class = NULL;
   if (!actual_arg_type.IsUnresolvedTypes()) {
     this_class = actual_arg_type.GetClass();
   } else {
     const std::string& descriptor(actual_arg_type.GetDescriptor());
-    // TODO: Precise or not?
-    this_class = reg_types_.FromDescriptor(class_loader_->get(), descriptor.c_str(),
-                                           false).GetClass();
+    // Try to resolve type.
+    const RegType& resolved_arg_type = reg_types_.FromDescriptor(class_loader_->get(),
+                                                                 descriptor.c_str(), false);
+    if (!resolved_arg_type.HasClass()) {
+      return nullptr;  // Resolution failed.
+    }
+    this_class = resolved_arg_type.GetClass();
     if (this_class == NULL) {
       Thread* self = Thread::Current();
       self->ClearException();
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 9dd57b8..111e867 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -156,15 +156,6 @@
   return klass;
 }
 
-void RegTypeCache::ClearException() {
-  if (can_load_classes_) {
-    DCHECK(Thread::Current()->IsExceptionPending());
-    Thread::Current()->ClearException();
-  } else {
-    DCHECK(!Thread::Current()->IsExceptionPending());
-  }
-}
-
 const RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descriptor,
                                   bool precise) {
   // Try looking up the class in the cache first.
@@ -199,7 +190,12 @@
   } else {  // Class not resolved.
     // We tried loading the class and failed, this might get an exception raised
     // so we want to clear it before we go on.
-    ClearException();
+    if (can_load_classes_) {
+      DCHECK(Thread::Current()->IsExceptionPending());
+      Thread::Current()->ClearException();
+    } else {
+      DCHECK(!Thread::Current()->IsExceptionPending());
+    }
     if (IsValidDescriptor(descriptor)) {
       RegType* entry = new UnresolvedReferenceType(descriptor, entries_.size());
       entries_.push_back(entry);
@@ -238,6 +234,14 @@
   }
 }
 
+RegTypeCache::RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) {
+  if (kIsDebugBuild && can_load_classes) {
+    Thread::Current()->AssertThreadSuspensionIsAllowable();
+  }
+  entries_.reserve(64);
+  FillPrimitiveAndSmallConstantTypes();
+}
+
 RegTypeCache::~RegTypeCache() {
   CHECK_LE(primitive_count_, entries_.size());
   // Delete only the non primitive types.
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index 4cc7e61..70d5f07 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -38,10 +38,7 @@
 
 class RegTypeCache {
  public:
-  explicit RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) {
-    entries_.reserve(64);
-    FillPrimitiveAndSmallConstantTypes();
-  }
+  explicit RegTypeCache(bool can_load_classes);
   ~RegTypeCache();
   static void Init() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     if (!RegTypeCache::primitive_initialized_) {
@@ -152,7 +149,6 @@
   void FillPrimitiveAndSmallConstantTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void ClearException();
   bool MatchDescriptor(size_t idx, const char* descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const ConstantType& FromCat1NonSmallConstant(int32_t value, bool precise)