Merge "ART: Fix typo in ArtMethod::FindCatchBlock"
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 1b70d59..8592aaa 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -82,6 +82,7 @@
 	optimizing/code_generator.cc \
 	optimizing/code_generator_arm.cc \
 	optimizing/code_generator_x86.cc \
+	optimizing/graph_visualizer.cc \
 	optimizing/nodes.cc \
 	optimizing/optimizing_compiler.cc \
 	optimizing/ssa_builder.cc \
diff --git a/compiler/compilers.h b/compiler/compilers.h
index 3ca78c9..e523d64 100644
--- a/compiler/compilers.h
+++ b/compiler/compilers.h
@@ -73,7 +73,7 @@
 
 class OptimizingCompiler FINAL : public QuickCompiler {
  public:
-  explicit OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) { }
+  explicit OptimizingCompiler(CompilerDriver* driver);
 
   CompiledMethod* Compile(const DexFile::CodeItem* code_item,
                           uint32_t access_flags,
@@ -92,6 +92,8 @@
                              const DexFile& dex_file) const;
 
  private:
+  UniquePtr<std::ostream> visualizer_output_;
+
   DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler);
 };
 
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index d3477c9..435242a 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -268,6 +268,7 @@
     MarkPossibleNullPointerException(opt_flags);
     LoadConstantNoClobber(rs_r3, 0);
     LIR* slow_unlock_branch = OpCmpBranch(kCondNe, rs_r1, rs_r2, NULL);
+    GenMemBarrier(kStoreLoad);
     Store32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r3);
     LIR* unlock_success_branch = OpUnconditionalBranch(NULL);
 
@@ -285,7 +286,6 @@
 
     LIR* success_target = NewLIR0(kPseudoTargetLabel);
     unlock_success_branch->target = success_target;
-    GenMemBarrier(kStoreLoad);
   } else {
     // Explicit null-check as slow-path is entered using an IT.
     GenNullCheck(rs_r0, opt_flags);
@@ -295,7 +295,8 @@
     LoadConstantNoClobber(rs_r3, 0);
     // Is lock unheld on lock or held by us (==thread_id) on unlock?
     OpRegReg(kOpCmp, rs_r1, rs_r2);
-    LIR* it = OpIT(kCondEq, "EE");
+    LIR* it = OpIT(kCondEq, "TEE");
+    GenMemBarrier(kStoreLoad);
     Store32Disp/*eq*/(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r3);
     // Go expensive route - UnlockObjectFromCode(obj);
     LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(),
@@ -304,7 +305,6 @@
     LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR);
     OpEndIT(it);
     MarkSafepointPC(call_inst);
-    GenMemBarrier(kStoreLoad);
   }
 }
 
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 7aaffcb..24ed4a3 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -801,8 +801,10 @@
                          const MethodReference& target_method,
                          uint32_t vtable_idx, uintptr_t direct_code,
                          uintptr_t direct_method, InvokeType type, bool skip_this) {
-  int last_arg_reg = TargetReg(kArg3).GetReg();
-  int next_reg = TargetReg(kArg1).GetReg();
+  int last_arg_reg = 3 - 1;
+  int arg_regs[3] = {TargetReg(kArg1).GetReg(), TargetReg(kArg2).GetReg(), TargetReg(kArg3).GetReg()};
+
+  int next_reg = 0;
   int next_arg = 0;
   if (skip_this) {
     next_reg++;
@@ -811,8 +813,8 @@
   for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
     RegLocation rl_arg = info->args[next_arg++];
     rl_arg = UpdateRawLoc(rl_arg);
-    if (rl_arg.wide && (next_reg <= TargetReg(kArg2).GetReg())) {
-      RegStorage r_tmp(RegStorage::k64BitPair, next_reg, next_reg + 1);
+    if (rl_arg.wide && (next_reg <= last_arg_reg - 1)) {
+      RegStorage r_tmp(RegStorage::k64BitPair, arg_regs[next_reg], arg_regs[next_reg + 1]);
       LoadValueDirectWideFixed(rl_arg, r_tmp);
       next_reg++;
       next_arg++;
@@ -821,7 +823,7 @@
         rl_arg = NarrowRegLoc(rl_arg);
         rl_arg.is_const = false;
       }
-      LoadValueDirectFixed(rl_arg, RegStorage::Solo32(next_reg));
+      LoadValueDirectFixed(rl_arg, RegStorage::Solo32(arg_regs[next_reg]));
     }
     call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                 direct_code, direct_method, type);
@@ -1571,7 +1573,7 @@
   RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (is_long) {
-    if (cu_->instruction_set == kX86) {
+    if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
       LoadBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_result.reg, k64);
     } else {
       RegStorage rl_temp_offset = AllocTemp();
@@ -1618,7 +1620,7 @@
   RegLocation rl_value;
   if (is_long) {
     rl_value = LoadValueWide(rl_src_value, kCoreReg);
-    if (cu_->instruction_set == kX86) {
+    if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
       StoreBaseIndexedDisp(rl_object.reg, rl_offset.reg, 0, 0, rl_value.reg, k64);
     } else {
       RegStorage rl_temp_offset = AllocTemp();
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 77119a4..2c4ca88 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -37,7 +37,7 @@
 }
 
 // TODO: needs revisit for 64-bit.
-RegStorage Mir2Lir::LoadArg(int in_position, bool wide) {
+RegStorage Mir2Lir::LoadArg(int in_position, RegisterClass reg_class, bool wide) {
   RegStorage reg_arg_low = GetArgMappingToPhysicalReg(in_position);
   RegStorage reg_arg_high = wide ? GetArgMappingToPhysicalReg(in_position + 1) :
       RegStorage::InvalidReg();
@@ -56,28 +56,45 @@
   if (wide && !reg_arg_high.Valid()) {
     // If the low part is not in a reg, we allocate a pair. Otherwise, we just load to high reg.
     if (!reg_arg_low.Valid()) {
-      RegStorage new_regs = AllocTypedTempWide(false, kAnyReg);
-      reg_arg_low = new_regs.GetLow();
-      reg_arg_high = new_regs.GetHigh();
+      RegStorage new_regs = AllocTypedTempWide(false, reg_class);
       LoadBaseDisp(TargetReg(kSp), offset, new_regs, k64);
+      return new_regs;  // The reg_class is OK, we can return.
     } else {
+      // Assume that no ABI allows splitting a wide fp reg between a narrow fp reg and memory,
+      // i.e. the low part is in a core reg. Load the second part in a core reg as well for now.
+      DCHECK(!reg_arg_low.IsFloat());
       reg_arg_high = AllocTemp();
       int offset_high = offset + sizeof(uint32_t);
       Load32Disp(TargetReg(kSp), offset_high, reg_arg_high);
+      // Continue below to check the reg_class.
     }
   }
 
   // If the low part is not in a register yet, we need to load it.
   if (!reg_arg_low.Valid()) {
-    reg_arg_low = AllocTemp();
+    // Assume that if the low part of a wide arg is passed in memory, so is the high part,
+    // thus we don't get here for wide args as it's handled above. Big-endian ABIs could
+    // conceivably break this assumption but Android supports only little-endian architectures.
+    DCHECK(!wide);
+    reg_arg_low = AllocTypedTemp(false, reg_class);
     Load32Disp(TargetReg(kSp), offset, reg_arg_low);
+    return reg_arg_low;  // The reg_class is OK, we can return.
   }
 
-  if (wide) {
-    return RegStorage::MakeRegPair(reg_arg_low, reg_arg_high);
-  } else {
-    return reg_arg_low;
+  RegStorage reg_arg = wide ? RegStorage::MakeRegPair(reg_arg_low, reg_arg_high) : reg_arg_low;
+  // Check if we need to copy the arg to a different reg_class.
+  if (!RegClassMatches(reg_class, reg_arg)) {
+    if (wide) {
+      RegStorage new_regs = AllocTypedTempWide(false, reg_class);
+      OpRegCopyWide(new_regs, reg_arg);
+      reg_arg = new_regs;
+    } else {
+      RegStorage new_reg = AllocTypedTemp(false, reg_class);
+      OpRegCopy(new_reg, reg_arg);
+      reg_arg = new_reg;
+    }
   }
+  return reg_arg;
 }
 
 void Mir2Lir::LoadArgDirect(int in_position, RegLocation rl_dest) {
@@ -138,16 +155,29 @@
   // Point of no return - no aborts after this
   GenPrintLabel(mir);
   LockArg(data.object_arg);
+  RegStorage reg_obj = LoadArg(data.object_arg, kCoreReg);
   RegLocation rl_dest = wide ? GetReturnWide(double_or_float) : GetReturn(double_or_float);
-  RegStorage reg_obj = LoadArg(data.object_arg);
+  RegisterClass reg_class = RegClassForFieldLoadStore(size, data.is_volatile);
+  RegStorage r_result = rl_dest.reg;
+  if (!RegClassMatches(reg_class, r_result)) {
+    r_result = wide ? AllocTypedTempWide(rl_dest.fp, reg_class)
+                    : AllocTypedTemp(rl_dest.fp, reg_class);
+  }
   if (data.is_volatile) {
-    LoadBaseDispVolatile(reg_obj, data.field_offset, rl_dest.reg, size);
+    LoadBaseDispVolatile(reg_obj, data.field_offset, r_result, size);
     // Without context sensitive analysis, we must issue the most conservative barriers.
     // In this case, either a load or store may follow so we issue both barriers.
     GenMemBarrier(kLoadLoad);
     GenMemBarrier(kLoadStore);
   } else {
-    LoadBaseDisp(reg_obj, data.field_offset, rl_dest.reg, size);
+    LoadBaseDisp(reg_obj, data.field_offset, r_result, size);
+  }
+  if (r_result != rl_dest.reg) {
+    if (wide) {
+      OpRegCopyWide(rl_dest.reg, r_result);
+    } else {
+      OpRegCopy(rl_dest.reg, r_result);
+    }
   }
   return true;
 }
@@ -175,8 +205,9 @@
   GenPrintLabel(mir);
   LockArg(data.object_arg);
   LockArg(data.src_arg, wide);
-  RegStorage reg_obj = LoadArg(data.object_arg);
-  RegStorage reg_src = LoadArg(data.src_arg, wide);
+  RegStorage reg_obj = LoadArg(data.object_arg, kCoreReg);
+  RegisterClass reg_class = RegClassForFieldLoadStore(size, data.is_volatile);
+  RegStorage reg_src = LoadArg(data.src_arg, reg_class, wide);
   if (data.is_volatile) {
     // There might have been a store before this volatile one so insert StoreStore barrier.
     GenMemBarrier(kStoreStore);
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 77e5649..6a0f3b2 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1397,7 +1397,7 @@
      * @param wide Whether the argument is 64-bit or not.
      * @return Returns the register (or register pair) for the loaded argument.
      */
-    RegStorage LoadArg(int in_position, bool wide = false);
+    RegStorage LoadArg(int in_position, RegisterClass reg_class, bool wide = false);
 
     /**
      * @brief Used to load a VR argument directly to a specified register location.
diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc
index eb9b230..aa4a5b2 100644
--- a/compiler/elf_writer_mclinker.cc
+++ b/compiler/elf_writer_mclinker.cc
@@ -361,8 +361,9 @@
       ClassLinker* linker = Runtime::Current()->GetClassLinker();
       // Unchecked as we hold mutator_lock_ on entry.
       ScopedObjectAccessUnchecked soa(Thread::Current());
-      Handle<mirror::DexCache> dex_cache(soa.Self(), linker->FindDexCache(dex_file));
-      Handle<mirror::ClassLoader> class_loader(soa.Self(), nullptr);
+      StackHandleScope<2> hs(soa.Self());
+      Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(dex_file)));
+      auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
       method = linker->ResolveMethod(dex_file, method_idx, dex_cache, class_loader, NULL, invoke_type);
       CHECK(method != NULL);
     }
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index b0aa63b..2c2564d 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -311,6 +311,10 @@
     }
   }
 
+  if (return_type == Primitive::kPrimDouble || return_type == Primitive::kPrimFloat) {
+    return false;
+  }
+
   DCHECK_EQ(argument_index, number_of_arguments);
   current_block_->AddInstruction(invoke);
   return true;
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index bbebd3a..beafbcc 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -47,7 +47,7 @@
   Bind(GetLabelOf(block));
   HGraphVisitor* location_builder = GetLocationBuilder();
   HGraphVisitor* instruction_visitor = GetInstructionVisitor();
-  for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     HInstruction* current = it.Current();
     current->Accept(location_builder);
     InitLocations(current);
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
new file mode 100644
index 0000000..a7604be
--- /dev/null
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "graph_visualizer.h"
+
+#include "driver/dex_compilation_unit.h"
+#include "nodes.h"
+
+namespace art {
+
+/**
+ * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
+ */
+class HGraphVisualizerPrinter : public HGraphVisitor {
+ public:
+  HGraphVisualizerPrinter(HGraph* graph, std::ostream& output)
+      : HGraphVisitor(graph), output_(output), indent_(0) {}
+
+  void StartTag(const char* name) {
+    AddIndent();
+    output_ << "begin_" << name << std::endl;
+    indent_++;
+  }
+
+  void EndTag(const char* name) {
+    indent_--;
+    AddIndent();
+    output_ << "end_" << name << std::endl;
+  }
+
+  void PrintProperty(const char* name, const char* property) {
+    AddIndent();
+    output_ << name << " \"" << property << "\"" << std::endl;
+  }
+
+  void PrintProperty(const char* name, const char* property, int id) {
+    AddIndent();
+    output_ << name << " \"" << property << id << "\"" << std::endl;
+  }
+
+  void PrintEmptyProperty(const char* name) {
+    AddIndent();
+    output_ << name << std::endl;
+  }
+
+  void PrintTime(const char* name) {
+    AddIndent();
+    output_ << name << " " << time(NULL) << std::endl;
+  }
+
+  void PrintInt(const char* name, int value) {
+    AddIndent();
+    output_ << name << " " << value << std::endl;
+  }
+
+  void AddIndent() {
+    for (size_t i = 0; i < indent_; ++i) {
+      output_ << "  ";
+    }
+  }
+
+  void PrintPredecessors(HBasicBlock* block) {
+    AddIndent();
+    output_ << "predecessors";
+    for (size_t i = 0, e = block->GetPredecessors().Size(); i < e; ++i) {
+      HBasicBlock* predecessor = block->GetPredecessors().Get(i);
+      output_ << " \"B" << predecessor->GetBlockId() << "\" ";
+    }
+    output_<< std::endl;
+  }
+
+  void PrintSuccessors(HBasicBlock* block) {
+    AddIndent();
+    output_ << "successors";
+    for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
+      HBasicBlock* successor = block->GetSuccessors().Get(i);
+      output_ << " \"B" << successor->GetBlockId() << "\" ";
+    }
+    output_<< std::endl;
+  }
+
+
+  void VisitInstruction(HInstruction* instruction) {
+    output_ << instruction->DebugName();
+    if (instruction->InputCount() > 0) {
+      output_ << " [ ";
+      for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
+        output_ << "v" << inputs.Current()->GetId() << " ";
+      }
+      output_ << "]";
+    }
+  }
+
+  void PrintInstructions(const HInstructionList& list) {
+    const char* kEndInstructionMarker = "<|@";
+    for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
+      HInstruction* instruction = it.Current();
+      AddIndent();
+      int bci = 0;
+      output_ << bci << " " << instruction->NumberOfUses() << " v" << instruction->GetId() << " ";
+      instruction->Accept(this);
+      output_ << kEndInstructionMarker << std::endl;
+    }
+  }
+
+  void Run(const char* pass_name) {
+    StartTag("cfg");
+    PrintProperty("name", pass_name);
+    VisitInsertionOrder();
+    EndTag("cfg");
+  }
+
+  void VisitBasicBlock(HBasicBlock* block) {
+    StartTag("block");
+    PrintProperty("name", "B", block->GetBlockId());
+    PrintInt("from_bci", -1);
+    PrintInt("to_bci", -1);
+    PrintPredecessors(block);
+    PrintSuccessors(block);
+    PrintEmptyProperty("xhandlers");
+    PrintEmptyProperty("flags");
+    if (block->GetDominator() != nullptr) {
+      PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
+    }
+
+    StartTag("states");
+    StartTag("locals");
+    PrintInt("size", 0);
+    PrintProperty("method", "None");
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+      AddIndent();
+      HInstruction* instruction = it.Current();
+      output_ << instruction->GetId() << " v" << instruction->GetId() << "[ ";
+      for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
+        output_ << inputs.Current()->GetId() << " ";
+      }
+      output_ << "]" << std::endl;
+    }
+    EndTag("locals");
+    EndTag("states");
+
+    StartTag("HIR");
+    PrintInstructions(block->GetPhis());
+    PrintInstructions(block->GetInstructions());
+    EndTag("HIR");
+    EndTag("block");
+  }
+
+ private:
+  std::ostream& output_;
+  size_t indent_;
+
+  DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
+};
+
+HGraphVisualizer::HGraphVisualizer(std::ostream* output,
+                                   HGraph* graph,
+                                   const char* string_filter,
+                                   const DexCompilationUnit& cu)
+    : output_(output), graph_(graph), is_enabled_(false) {
+  if (output == nullptr) {
+    return;
+  }
+  std::string pretty_name = PrettyMethod(cu.GetDexMethodIndex(), *cu.GetDexFile());
+  if (pretty_name.find(string_filter) == std::string::npos) {
+    return;
+  }
+
+  is_enabled_ = true;
+  HGraphVisualizerPrinter printer(graph, *output_);
+  printer.StartTag("compilation");
+  printer.PrintProperty("name", pretty_name.c_str());
+  printer.PrintProperty("method", pretty_name.c_str());
+  printer.PrintTime("date");
+  printer.EndTag("compilation");
+}
+
+void HGraphVisualizer::DumpGraph(const char* pass_name) {
+  if (!is_enabled_) {
+    return;
+  }
+  HGraphVisualizerPrinter printer(graph_, *output_);
+  printer.Run(pass_name);
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
new file mode 100644
index 0000000..433d55d
--- /dev/null
+++ b/compiler/optimizing/graph_visualizer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
+#define ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
+
+#include "utils/allocation.h"
+
+namespace art {
+
+class DexCompilationUnit;
+class HGraph;
+
+/**
+ * If enabled, emits compilation information suitable for the c1visualizer tool
+ * and IRHydra.
+ * Currently only works if the compiler is single threaded.
+ */
+class HGraphVisualizer : public ValueObject {
+ public:
+  /**
+   * If output is not null, and the method name of the dex compilation
+   * unit contains `string_filter`, the compilation information will be
+   * emitted.
+   */
+  HGraphVisualizer(std::ostream* output,
+                   HGraph* graph,
+                   const char* string_filter,
+                   const DexCompilationUnit& cu);
+
+  /**
+   * If this visualizer is enabled, emit the compilation information
+   * in `output_`.
+   */
+  void DumpGraph(const char* pass_name);
+
+ private:
+  std::ostream* const output_;
+  HGraph* const graph_;
+
+  // Is true when `output_` is not null, and the compiled method's name
+  // contains the string_filter given in the constructor.
+  bool is_enabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(HGraphVisualizer);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index cf2d1ee..afaedd7 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -37,10 +37,10 @@
       for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
         block->GetSuccessors().Get(j)->RemovePredecessor(block, false);
       }
-      for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+      for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
         block->RemovePhi(it.Current()->AsPhi());
       }
-      for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+      for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
         block->RemoveInstruction(it.Current());
       }
     }
@@ -420,10 +420,10 @@
 }
 
 void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
-  for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
     it.Current()->Accept(this);
   }
-  for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     it.Current()->Accept(this);
   }
 }
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 081c2bd..27b87ca 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -82,7 +82,7 @@
   void SimplifyCFG();
 
   // Find all natural loops in this graph. Aborts computation and returns false
-  // if one loop is not natural, that is the header does not dominated the back
+  // if one loop is not natural, that is the header does not dominate the back
   // edge.
   bool FindNaturalLoops() const;
 
@@ -268,8 +268,8 @@
 
   HInstruction* GetFirstInstruction() const { return instructions_.first_instruction_; }
   HInstruction* GetLastInstruction() const { return instructions_.last_instruction_; }
-  HInstructionList const* GetInstructions() const { return &instructions_; }
-  HInstructionList const* GetPhis() const { return &phis_; }
+  const HInstructionList& GetInstructions() const { return instructions_; }
+  const HInstructionList& GetPhis() const { return phis_; }
 
   void AddSuccessor(HBasicBlock* block) {
     successors_.Add(block);
@@ -444,6 +444,17 @@
 
   bool HasUses() const { return uses_ != nullptr || env_uses_ != nullptr; }
 
+  size_t NumberOfUses() const {
+    // TODO: Optimize this method if it is used outside of the HGraphTracer.
+    size_t result = 0;
+    HUseListNode<HInstruction>* current = uses_;
+    while (current != nullptr) {
+      current = current->GetTail();
+      ++result;
+    }
+    return result;
+  }
+
   int GetId() const { return id_; }
   void SetId(int id) { id_ = id; }
 
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index a5031e0..f435cb0 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <fstream>
 #include <stdint.h>
 
 #include "builder.h"
@@ -21,6 +22,7 @@
 #include "compilers.h"
 #include "driver/compiler_driver.h"
 #include "driver/dex_compilation_unit.h"
+#include "graph_visualizer.h"
 #include "nodes.h"
 #include "ssa_liveness_analysis.h"
 #include "utils/arena_allocator.h"
@@ -50,6 +52,22 @@
   DISALLOW_COPY_AND_ASSIGN(CodeVectorAllocator);
 };
 
+/**
+ * If set to true, generates a file suitable for the c1visualizer tool and IRHydra.
+ */
+static bool kIsVisualizerEnabled = false;
+
+/**
+ * Filter to apply to the visualizer. Methods whose name contain that filter will
+ * be in the file.
+ */
+static const char* kStringFilter = "";
+
+OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) {
+  if (kIsVisualizerEnabled) {
+    visualizer_output_.reset(new std::ofstream("art.cfg"));
+  }
+}
 
 CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
                                                uint32_t access_flags,
@@ -70,6 +88,7 @@
   ArenaPool pool;
   ArenaAllocator arena(&pool);
   HGraphBuilder builder(&arena, &dex_compilation_unit, &dex_file);
+
   HGraph* graph = builder.BuildGraph(*code_item);
   if (graph == nullptr) {
     if (shouldCompile) {
@@ -77,6 +96,8 @@
     }
     return nullptr;
   }
+  HGraphVisualizer visualizer(visualizer_output_.get(), graph, kStringFilter, dex_compilation_unit);
+  visualizer.DumpGraph("builder");
 
   InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet();
   // The optimizing compiler currently does not have a Thumb2 assembler.
@@ -104,6 +125,8 @@
   // Run these phases to get some test coverage.
   graph->BuildDominatorTree();
   graph->TransformToSSA();
+  visualizer.DumpGraph("ssa");
+
   graph->FindNaturalLoops();
   SsaLivenessAnalysis(*graph).Analyze();
 
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 1fc041c..50e3254 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -30,7 +30,7 @@
   // 2) Set inputs of loop phis.
   for (size_t i = 0; i < loop_headers_.Size(); i++) {
     HBasicBlock* block = loop_headers_.Get(i);
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       HPhi* phi = it.Current()->AsPhi();
       for (size_t pred = 0; pred < block->GetPredecessors().Size(); pred++) {
         phi->AddInput(ValueOfLocal(block->GetPredecessors().Get(pred), phi->GetRegNumber()));
@@ -40,7 +40,7 @@
 
   // 3) Clear locals.
   // TODO: Move this to a dead code eliminator phase.
-  for (HInstructionIterator it(*GetGraph()->GetEntryBlock()->GetInstructions());
+  for (HInstructionIterator it(GetGraph()->GetEntryBlock()->GetInstructions());
        !it.Done();
        it.Advance()) {
     HInstruction* current = it.Current();
@@ -106,7 +106,7 @@
   // - HStoreLocal: update current value of the local and remove the instruction.
   // - Instructions that require an environment: populate their environment
   //   with the current values of the locals.
-  for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+  for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     it.Current()->Accept(this);
   }
 }
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 0ab77ca..7c2ec39 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -29,14 +29,14 @@
   for (HReversePostOrderIterator it(graph_); !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
 
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasUses()) {
         current->SetSsaIndex(ssa_index++);
       }
     }
 
-    for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasUses()) {
         current->SetSsaIndex(ssa_index++);
@@ -73,7 +73,7 @@
     BitVector* kill = GetKillSet(*block);
     BitVector* live_in = GetLiveInSet(*block);
 
-    for (HBackwardInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+    for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasSsaIndex()) {
         kill->SetBit(current->GetSsaIndex());
@@ -99,7 +99,7 @@
       }
     }
 
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
       if (current->HasSsaIndex()) {
         kill->SetBit(current->GetSsaIndex());
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index 9be2197..415d146 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -66,10 +66,10 @@
   int id = 0;
   for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
     HBasicBlock* block = graph->GetBlocks().Get(i);
-    for (HInstructionIterator it(*block->GetPhis()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
       it.Current()->SetId(id++);
     }
-    for (HInstructionIterator it(*block->GetInstructions()); !it.Done(); it.Advance()) {
+    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       it.Current()->SetId(id++);
     }
   }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 7d7024a..ad796f8 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -958,9 +958,7 @@
   bool image = (!image_filename.empty());
   if (!image && boot_image_filename.empty()) {
     boot_image_filename += GetAndroidRoot();
-    boot_image_filename += "/framework/boot-";
-    boot_image_filename += GetInstructionSetString(instruction_set);
-    boot_image_filename += ".art";
+    boot_image_filename += "/framework/boot.art";
   }
   std::string boot_image_option;
   if (!boot_image_filename.empty()) {
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 4886561..5212576 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -399,7 +399,7 @@
     @ unlocked case - r2 holds thread id with count of 0
     strex  r3, r2, [r0, #LOCK_WORD_OFFSET]
     cbnz   r3, .Lstrex_fail           @ store failed, retry
-    dmb    ish                        @ full (LoadLoad) memory barrier
+    dmb    ish                        @ full (LoadLoad|LoadStore) memory barrier
     bx lr
 .Lstrex_fail:
     b .Lretry_lock                    @ unlikely forward branch, need to reload and recheck r1/r2
@@ -442,7 +442,7 @@
     cmp    r1, #65536
     bpl    .Lrecursive_thin_unlock
     @ transition to unlocked, r3 holds 0
-    dmb    ish                        @ full (StoreLoad) memory barrier
+    dmb    ish                        @ full (LoadStore|StoreStore) memory barrier
     str    r3, [r0, #LOCK_WORD_OFFSET]
     bx     lr
 .Lrecursive_thin_unlock:
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 2a21144..f2050b3 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1014,7 +1014,7 @@
     cbnz   w1, .Lnot_unlocked         // already thin locked
     stxr   w3, w2, [x4]
     cbnz   w3, .Lstrex_fail           // store failed, retry
-    dmb    ishld                      // full (LoadLoad) memory barrier, TODO: acquire-release
+    dmb    ishld                      // full (LoadLoad|LoadStore) memory barrier
     ret
 .Lstrex_fail:
     b .Lretry_lock                    // unlikely forward branch, need to reload and recheck r1/r2
@@ -1058,7 +1058,7 @@
     cmp    w1, #65536
     bpl    .Lrecursive_thin_unlock
     // transition to unlocked, w3 holds 0
-    dmb    ish                        // full (StoreLoad) memory barrier
+    dmb    ish                        // full (LoadStore|StoreStore) memory barrier
     str    w3, [x0, #LOCK_WORD_OFFSET]
     ret
 .Lrecursive_thin_unlock:
@@ -1444,7 +1444,7 @@
  * | RDI/Method*       |  <- X0
  * #-------------------#
  * | local ref cookie  | // 4B
- * |   handle scope size       | // 4B
+ * | handle scope size | // 4B
  * #-------------------#
  * | JNI Call Stack    |
  * #-------------------#    <--- SP on native call
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 73214ea..9c86c75 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1050,12 +1050,12 @@
  * | Return            |
  * | Callee-Save Data  |
  * #-------------------#
- * | handle scope              |
+ * | handle scope      |
  * #-------------------#
  * | Method*           |    <--- (1)
  * #-------------------#
  * | local ref cookie  | // 4B
- * | handle scope size         | // 4B   TODO: roll into call stack alignment?
+ * | handle scope size | // 4B   TODO: roll into call stack alignment?
  * #-------------------#
  * | JNI Call Stack    |
  * #-------------------#    <--- SP on native call
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 0d5a805..cfd0c00 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -179,7 +179,7 @@
   // times, so using "java.lang.Thread" instead of "java/lang/Thread" might work in some
   // circumstances, but this is incorrect.
   void CheckClassName(const char* class_name) {
-    if (!IsValidJniClassName(class_name)) {
+    if ((class_name == nullptr) || !IsValidJniClassName(class_name)) {
       JniAbortF(function_name_,
                 "illegal class name '%s'\n"
                 "    (should be of the form 'package/Class', [Lpackage/Class;' or '[[B')",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3d268e4..9034560 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2215,7 +2215,10 @@
     DCHECK(self->IsExceptionPending());
     return nullptr;
   }
-
+  if (UNLIKELY(component_type->IsPrimitiveVoid())) {
+    ThrowNoClassDefFoundError("Attempt to create array of void primitive type");
+    return nullptr;
+  }
   // See if the component type is already loaded.  Array classes are
   // always associated with the class loader of their underlying
   // element type -- an array of Strings goes with the loader for
diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h
index b9b51fd..634f2be 100644
--- a/runtime/handle_scope-inl.h
+++ b/runtime/handle_scope-inl.h
@@ -25,7 +25,7 @@
 namespace art {
 
 template<size_t kNumReferences>
-StackHandleScope<kNumReferences>::StackHandleScope(Thread* self)
+inline StackHandleScope<kNumReferences>::StackHandleScope(Thread* self)
     : HandleScope(kNumReferences), self_(self), pos_(0) {
   // TODO: Figure out how to use a compile assert.
   DCHECK_EQ(OFFSETOF_MEMBER(HandleScope, references_),
@@ -37,7 +37,7 @@
 }
 
 template<size_t kNumReferences>
-StackHandleScope<kNumReferences>::~StackHandleScope() {
+inline StackHandleScope<kNumReferences>::~StackHandleScope() {
   HandleScope* top_handle_scope = self_->PopHandleScope();
   DCHECK_EQ(top_handle_scope, this);
 }
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 4634971..21dab8d 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -518,16 +518,28 @@
   SafeMap<std::string, SharedLibrary*> libraries_;
 };
 
-#define CHECK_NON_NULL_ARGUMENT(value) CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value)
+#define CHECK_NON_NULL_ARGUMENT(value) \
+    CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value, nullptr)
 
-#define CHECK_NON_NULL_ARGUMENT_FN_NAME(name, value) \
+#define CHECK_NON_NULL_ARGUMENT_RETURN_VOID(value) \
+    CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value, )
+
+#define CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(value) \
+    CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value, 0)
+
+#define CHECK_NON_NULL_ARGUMENT_RETURN(value, return_val) \
+    CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value, return_val)
+
+#define CHECK_NON_NULL_ARGUMENT_FN_NAME(name, value, return_val) \
   if (UNLIKELY(value == nullptr)) { \
     JniAbortF(name, #value " == null"); \
+    return return_val; \
   }
 
 #define CHECK_NON_NULL_MEMCPY_ARGUMENT(length, value) \
   if (UNLIKELY(length != 0 && value == nullptr)) { \
     JniAbortF(__FUNCTION__, #value " == null"); \
+    return; \
   }
 
 class JNI {
@@ -614,8 +626,8 @@
   }
 
   static jboolean IsAssignableFrom(JNIEnv* env, jclass java_class1, jclass java_class2) {
-    CHECK_NON_NULL_ARGUMENT(java_class1);
-    CHECK_NON_NULL_ARGUMENT(java_class2);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_class1, JNI_FALSE);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_class2, JNI_FALSE);
     ScopedObjectAccess soa(env);
     mirror::Class* c1 = soa.Decode<mirror::Class*>(java_class1);
     mirror::Class* c2 = soa.Decode<mirror::Class*>(java_class2);
@@ -623,7 +635,7 @@
   }
 
   static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass java_class) {
-    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_class, JNI_FALSE);
     if (jobj == nullptr) {
       // Note: JNI is different from regular Java instanceof in this respect
       return JNI_TRUE;
@@ -647,7 +659,7 @@
   }
 
   static jint ThrowNew(JNIEnv* env, jclass c, const char* msg) {
-    CHECK_NON_NULL_ARGUMENT(c);
+    CHECK_NON_NULL_ARGUMENT_RETURN(c, JNI_ERR);
     return ThrowNewException(env, c, msg, nullptr);
   }
 
@@ -914,8 +926,8 @@
   static jboolean CallBooleanMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -923,15 +935,15 @@
   }
 
   static jboolean CallBooleanMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetZ();
   }
 
   static jboolean CallBooleanMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetZ();
@@ -940,8 +952,8 @@
   static jbyte CallByteMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -949,15 +961,15 @@
   }
 
   static jbyte CallByteMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetB();
   }
 
   static jbyte CallByteMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetB();
@@ -966,8 +978,8 @@
   static jchar CallCharMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -975,15 +987,15 @@
   }
 
   static jchar CallCharMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetC();
   }
 
   static jchar CallCharMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetC();
@@ -992,8 +1004,8 @@
   static jdouble CallDoubleMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1001,15 +1013,15 @@
   }
 
   static jdouble CallDoubleMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetD();
   }
 
   static jdouble CallDoubleMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetD();
@@ -1018,8 +1030,8 @@
   static jfloat CallFloatMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1027,15 +1039,15 @@
   }
 
   static jfloat CallFloatMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetF();
   }
 
   static jfloat CallFloatMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetF();
@@ -1044,8 +1056,8 @@
   static jint CallIntMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1053,15 +1065,15 @@
   }
 
   static jint CallIntMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetI();
   }
 
   static jint CallIntMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetI();
@@ -1070,8 +1082,8 @@
   static jlong CallLongMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1079,15 +1091,15 @@
   }
 
   static jlong CallLongMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetJ();
   }
 
   static jlong CallLongMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetJ();
@@ -1096,8 +1108,8 @@
   static jshort CallShortMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1105,15 +1117,15 @@
   }
 
   static jshort CallShortMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetS();
   }
 
   static jshort CallShortMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetS();
@@ -1122,23 +1134,23 @@
   static void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap);
     va_end(ap);
   }
 
   static void CallVoidMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args);
   }
 
   static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args);
   }
@@ -1177,8 +1189,8 @@
                                               ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1187,16 +1199,16 @@
 
   static jboolean CallNonvirtualBooleanMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                                va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetZ();
   }
 
   static jboolean CallNonvirtualBooleanMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                                jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetZ();
   }
@@ -1204,8 +1216,8 @@
   static jbyte CallNonvirtualByteMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1214,16 +1226,16 @@
 
   static jbyte CallNonvirtualByteMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetB();
   }
 
   static jbyte CallNonvirtualByteMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetB();
   }
@@ -1231,8 +1243,8 @@
   static jchar CallNonvirtualCharMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1241,16 +1253,16 @@
 
   static jchar CallNonvirtualCharMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetC();
   }
 
   static jchar CallNonvirtualCharMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetC();
   }
@@ -1258,8 +1270,8 @@
   static jshort CallNonvirtualShortMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1268,16 +1280,16 @@
 
   static jshort CallNonvirtualShortMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetS();
   }
 
   static jshort CallNonvirtualShortMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetS();
   }
@@ -1285,8 +1297,8 @@
   static jint CallNonvirtualIntMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1295,16 +1307,16 @@
 
   static jint CallNonvirtualIntMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                        va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetI();
   }
 
   static jint CallNonvirtualIntMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                        jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetI();
   }
@@ -1312,8 +1324,8 @@
   static jlong CallNonvirtualLongMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1322,16 +1334,16 @@
 
   static jlong CallNonvirtualLongMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetJ();
   }
 
   static jlong CallNonvirtualLongMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetJ();
   }
@@ -1339,8 +1351,8 @@
   static jfloat CallNonvirtualFloatMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1349,16 +1361,16 @@
 
   static jfloat CallNonvirtualFloatMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetF();
   }
 
   static jfloat CallNonvirtualFloatMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetF();
   }
@@ -1366,8 +1378,8 @@
   static jdouble CallNonvirtualDoubleMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1376,16 +1388,16 @@
 
   static jdouble CallNonvirtualDoubleMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                              va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetD();
   }
 
   static jdouble CallNonvirtualDoubleMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                              jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetD();
   }
@@ -1393,8 +1405,8 @@
   static void CallNonvirtualVoidMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, obj, mid, ap);
     va_end(ap);
@@ -1402,16 +1414,16 @@
 
   static void CallNonvirtualVoidMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                         va_list args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, obj, mid, args);
   }
 
   static void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                         jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(obj);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(obj);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args);
   }
@@ -1450,8 +1462,8 @@
   }
 
   static void SetObjectField(JNIEnv* env, jobject java_object, jfieldID fid, jobject java_value) {
-    CHECK_NON_NULL_ARGUMENT(java_object);
-    CHECK_NON_NULL_ARGUMENT(fid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_object);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid);
     ScopedObjectAccess soa(env);
     mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
@@ -1460,7 +1472,7 @@
   }
 
   static void SetStaticObjectField(JNIEnv* env, jclass, jfieldID fid, jobject java_value) {
-    CHECK_NON_NULL_ARGUMENT(fid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid);
     ScopedObjectAccess soa(env);
     mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
     mirror::ArtField* f = soa.DecodeField(fid);
@@ -1468,29 +1480,29 @@
   }
 
 #define GET_PRIMITIVE_FIELD(fn, instance) \
-  CHECK_NON_NULL_ARGUMENT(instance); \
-  CHECK_NON_NULL_ARGUMENT(fid); \
+  CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(instance); \
+  CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \
   ScopedObjectAccess soa(env); \
   mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   return f->Get ##fn (o)
 
 #define GET_STATIC_PRIMITIVE_FIELD(fn) \
-  CHECK_NON_NULL_ARGUMENT(fid); \
+  CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \
   ScopedObjectAccess soa(env); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   return f->Get ##fn (f->GetDeclaringClass())
 
 #define SET_PRIMITIVE_FIELD(fn, instance, value) \
-  CHECK_NON_NULL_ARGUMENT(instance); \
-  CHECK_NON_NULL_ARGUMENT(fid); \
+  CHECK_NON_NULL_ARGUMENT_RETURN_VOID(instance); \
+  CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \
   ScopedObjectAccess soa(env); \
   mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   f->Set ##fn <false>(o, value)
 
 #define SET_STATIC_PRIMITIVE_FIELD(fn, value) \
-  CHECK_NON_NULL_ARGUMENT(fid); \
+  CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \
   ScopedObjectAccess soa(env); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   f->Set ##fn <false>(f->GetDeclaringClass(), value)
@@ -1651,7 +1663,7 @@
   static jboolean CallStaticBooleanMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1659,13 +1671,13 @@
   }
 
   static jboolean CallStaticBooleanMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetZ();
   }
 
   static jboolean CallStaticBooleanMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetZ();
   }
@@ -1673,7 +1685,7 @@
   static jbyte CallStaticByteMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1681,13 +1693,13 @@
   }
 
   static jbyte CallStaticByteMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetB();
   }
 
   static jbyte CallStaticByteMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetB();
   }
@@ -1695,7 +1707,7 @@
   static jchar CallStaticCharMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1703,13 +1715,13 @@
   }
 
   static jchar CallStaticCharMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetC();
   }
 
   static jchar CallStaticCharMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetC();
   }
@@ -1717,7 +1729,7 @@
   static jshort CallStaticShortMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1725,13 +1737,13 @@
   }
 
   static jshort CallStaticShortMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetS();
   }
 
   static jshort CallStaticShortMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetS();
   }
@@ -1739,7 +1751,7 @@
   static jint CallStaticIntMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1747,13 +1759,13 @@
   }
 
   static jint CallStaticIntMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetI();
   }
 
   static jint CallStaticIntMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetI();
   }
@@ -1761,7 +1773,7 @@
   static jlong CallStaticLongMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1769,13 +1781,13 @@
   }
 
   static jlong CallStaticLongMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetJ();
   }
 
   static jlong CallStaticLongMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetJ();
   }
@@ -1783,7 +1795,7 @@
   static jfloat CallStaticFloatMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1791,13 +1803,13 @@
   }
 
   static jfloat CallStaticFloatMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetF();
   }
 
   static jfloat CallStaticFloatMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetF();
   }
@@ -1805,7 +1817,7 @@
   static jdouble CallStaticDoubleMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1813,13 +1825,13 @@
   }
 
   static jdouble CallStaticDoubleMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetD();
   }
 
   static jdouble CallStaticDoubleMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetD();
   }
@@ -1827,20 +1839,20 @@
   static void CallStaticVoidMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, nullptr, mid, ap);
     va_end(ap);
   }
 
   static void CallStaticVoidMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, nullptr, mid, args);
   }
 
   static void CallStaticVoidMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(mid);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
     ScopedObjectAccess soa(env);
     InvokeWithJValues(soa, nullptr, mid, args);
   }
@@ -1869,20 +1881,20 @@
   }
 
   static jsize GetStringLength(JNIEnv* env, jstring java_string) {
-    CHECK_NON_NULL_ARGUMENT(java_string);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_string);
     ScopedObjectAccess soa(env);
     return soa.Decode<mirror::String*>(java_string)->GetLength();
   }
 
   static jsize GetStringUTFLength(JNIEnv* env, jstring java_string) {
-    CHECK_NON_NULL_ARGUMENT(java_string);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_string);
     ScopedObjectAccess soa(env);
     return soa.Decode<mirror::String*>(java_string)->GetUtfLength();
   }
 
   static void GetStringRegion(JNIEnv* env, jstring java_string, jsize start, jsize length,
                               jchar* buf) {
-    CHECK_NON_NULL_ARGUMENT(java_string);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
     mirror::String* s = soa.Decode<mirror::String*>(java_string);
     if (start < 0 || length < 0 || start + length > s->GetLength()) {
@@ -1896,7 +1908,7 @@
 
   static void GetStringUTFRegion(JNIEnv* env, jstring java_string, jsize start, jsize length,
                                  char* buf) {
-    CHECK_NON_NULL_ARGUMENT(java_string);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     ScopedObjectAccess soa(env);
     mirror::String* s = soa.Decode<mirror::String*>(java_string);
     if (start < 0 || length < 0 || start + length > s->GetLength()) {
@@ -1928,7 +1940,7 @@
   }
 
   static void ReleaseStringChars(JNIEnv* env, jstring java_string, const jchar* chars) {
-    CHECK_NON_NULL_ARGUMENT(java_string);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
     delete[] chars;
     ScopedObjectAccess soa(env);
     UnpinPrimitiveArray(soa, soa.Decode<mirror::String*>(java_string)->GetCharArray());
@@ -1965,7 +1977,7 @@
   }
 
   static jsize GetArrayLength(JNIEnv* env, jarray java_array) {
-    CHECK_NON_NULL_ARGUMENT(java_array);
+    CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_array);
     ScopedObjectAccess soa(env);
     mirror::Object* obj = soa.Decode<mirror::Object*>(java_array);
     if (UNLIKELY(!obj->IsArrayInstance())) {
@@ -1985,7 +1997,7 @@
 
   static void SetObjectArrayElement(JNIEnv* env, jobjectArray java_array, jsize index,
                                     jobject java_value) {
-    CHECK_NON_NULL_ARGUMENT(java_array);
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
     ScopedObjectAccess soa(env);
     mirror::ObjectArray<mirror::Object>* array =
         soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
@@ -1994,38 +2006,31 @@
   }
 
   static jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jbooleanArray, mirror::BooleanArray>(soa, length);
+    return NewPrimitiveArray<jbooleanArray, mirror::BooleanArray>(env, length);
   }
 
   static jbyteArray NewByteArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jbyteArray, mirror::ByteArray>(soa, length);
+    return NewPrimitiveArray<jbyteArray, mirror::ByteArray>(env, length);
   }
 
   static jcharArray NewCharArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jcharArray, mirror::CharArray>(soa, length);
+    return NewPrimitiveArray<jcharArray, mirror::CharArray>(env, length);
   }
 
   static jdoubleArray NewDoubleArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jdoubleArray, mirror::DoubleArray>(soa, length);
+    return NewPrimitiveArray<jdoubleArray, mirror::DoubleArray>(env, length);
   }
 
   static jfloatArray NewFloatArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jfloatArray, mirror::FloatArray>(soa, length);
+    return NewPrimitiveArray<jfloatArray, mirror::FloatArray>(env, length);
   }
 
   static jintArray NewIntArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jintArray, mirror::IntArray>(soa, length);
+    return NewPrimitiveArray<jintArray, mirror::IntArray>(env, length);
   }
 
   static jlongArray NewLongArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jlongArray, mirror::LongArray>(soa, length);
+    return NewPrimitiveArray<jlongArray, mirror::LongArray>(env, length);
   }
 
   static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass element_jclass,
@@ -2034,6 +2039,7 @@
       JniAbortF("NewObjectArray", "negative array length: %d", length);
       return nullptr;
     }
+    CHECK_NON_NULL_ARGUMENT(element_jclass);
 
     // Compute the array class corresponding to the given element class.
     ScopedObjectAccess soa(env);
@@ -2075,14 +2081,18 @@
   }
 
   static jshortArray NewShortArray(JNIEnv* env, jsize length) {
-    ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jshortArray, mirror::ShortArray>(soa, length);
+    return NewPrimitiveArray<jshortArray, mirror::ShortArray>(env, length);
   }
 
   static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray java_array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(java_array);
     ScopedObjectAccess soa(env);
     mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
+    if (UNLIKELY(!array->GetClass()->IsPrimitiveArray())) {
+      JniAbortF("GetPrimitiveArrayCritical", "expected primitive array, given %s",
+                PrettyDescriptor(array->GetClass()).c_str());
+      return nullptr;
+    }
     gc::Heap* heap = Runtime::Current()->GetHeap();
     if (heap->IsMovableObject(array)) {
       heap->IncrementDisableMovingGC(soa.Self());
@@ -2096,196 +2106,174 @@
     return array->GetRawData(array->GetClass()->GetComponentSize(), 0);
   }
 
-  static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* elements, jint mode) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ReleasePrimitiveArray(env, array, elements, mode);
+  static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray java_array, void* elements,
+                                            jint mode) {
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
+    ScopedObjectAccess soa(env);
+    mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
+    if (UNLIKELY(!array->GetClass()->IsPrimitiveArray())) {
+      JniAbortF("ReleasePrimitiveArrayCritical", "expected primitive array, given %s",
+                PrettyDescriptor(array->GetClass()).c_str());
+      return;
+    }
+    const size_t component_size = array->GetClass()->GetComponentSize();
+    ReleasePrimitiveArray(soa, array, component_size, elements, mode);
   }
 
   static jboolean* GetBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jbooleanArray, jboolean*, mirror::BooleanArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jbooleanArray, jboolean, mirror::BooleanArray>(env, array, is_copy);
   }
 
   static jbyte* GetByteArrayElements(JNIEnv* env, jbyteArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jbyteArray, jbyte*, mirror::ByteArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jbyteArray, jbyte, mirror::ByteArray>(env, array, is_copy);
   }
 
   static jchar* GetCharArrayElements(JNIEnv* env, jcharArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jcharArray, jchar*, mirror::CharArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jcharArray, jchar, mirror::CharArray>(env, array, is_copy);
   }
 
   static jdouble* GetDoubleArrayElements(JNIEnv* env, jdoubleArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jdoubleArray, jdouble*, mirror::DoubleArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jdoubleArray, jdouble, mirror::DoubleArray>(env, array, is_copy);
   }
 
   static jfloat* GetFloatArrayElements(JNIEnv* env, jfloatArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jfloatArray, jfloat*, mirror::FloatArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jfloatArray, jfloat, mirror::FloatArray>(env, array, is_copy);
   }
 
   static jint* GetIntArrayElements(JNIEnv* env, jintArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jintArray, jint*, mirror::IntArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jintArray, jint, mirror::IntArray>(env, array, is_copy);
   }
 
   static jlong* GetLongArrayElements(JNIEnv* env, jlongArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jlongArray, jlong*, mirror::LongArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jlongArray, jlong, mirror::LongArray>(env, array, is_copy);
   }
 
   static jshort* GetShortArrayElements(JNIEnv* env, jshortArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(array);
-    ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jshortArray, jshort*, mirror::ShortArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jshortArray, jshort, mirror::ShortArray>(env, array, is_copy);
   }
 
   static void ReleaseBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* elements,
                                           jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jbooleanArray, jboolean, mirror::BooleanArray>(env, array, elements,
+                                                                         mode);
   }
 
   static void ReleaseByteArrayElements(JNIEnv* env, jbyteArray array, jbyte* elements, jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jbyteArray, jbyte, mirror::ByteArray>(env, array, elements, mode);
   }
 
   static void ReleaseCharArrayElements(JNIEnv* env, jcharArray array, jchar* elements, jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jcharArray, jchar, mirror::CharArray>(env, array, elements, mode);
   }
 
   static void ReleaseDoubleArrayElements(JNIEnv* env, jdoubleArray array, jdouble* elements,
                                          jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jdoubleArray, jdouble, mirror::DoubleArray>(env, array, elements, mode);
   }
 
   static void ReleaseFloatArrayElements(JNIEnv* env, jfloatArray array, jfloat* elements,
                                         jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jfloatArray, jfloat, mirror::FloatArray>(env, array, elements, mode);
   }
 
   static void ReleaseIntArrayElements(JNIEnv* env, jintArray array, jint* elements, jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jintArray, jint, mirror::IntArray>(env, array, elements, mode);
   }
 
   static void ReleaseLongArrayElements(JNIEnv* env, jlongArray array, jlong* elements, jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jlongArray, jlong, mirror::LongArray>(env, array, elements, mode);
   }
 
   static void ReleaseShortArrayElements(JNIEnv* env, jshortArray array, jshort* elements,
                                         jint mode) {
-    ReleasePrimitiveArray(env, array, elements, mode);
+    ReleasePrimitiveArray<jshortArray, jshort, mirror::ShortArray>(env, array, elements, mode);
   }
 
   static void GetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize length,
                                     jboolean* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(soa, array, start,
+    GetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(env, array, start,
                                                                            length, buf);
   }
 
   static void GetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize length,
                                  jbyte* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(env, array, start, length, buf);
   }
 
   static void GetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize length,
                                  jchar* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(env, array, start, length, buf);
   }
 
   static void GetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize length,
                                    jdouble* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(soa, array, start, length,
+    GetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(env, array, start, length,
                                                                         buf);
   }
 
   static void GetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize length,
                                   jfloat* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(soa, array, start, length,
+    GetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(env, array, start, length,
                                                                      buf);
   }
 
   static void GetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize length,
                                 jint* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(env, array, start, length, buf);
   }
 
   static void GetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize length,
                                  jlong* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(env, array, start, length, buf);
   }
 
   static void GetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize length,
                                   jshort* buf) {
-    ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(soa, array, start, length,
+    GetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(env, array, start, length,
                                                                      buf);
   }
 
   static void SetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize length,
                                     const jboolean* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(soa, array, start,
+    SetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(env, array, start,
                                                                            length, buf);
   }
 
   static void SetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize length,
                                  const jbyte* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(env, array, start, length, buf);
   }
 
   static void SetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize length,
                                  const jchar* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(env, array, start, length, buf);
   }
 
   static void SetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize length,
                                    const jdouble* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(soa, array, start, length,
+    SetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(env, array, start, length,
                                                                         buf);
   }
 
   static void SetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize length,
                                   const jfloat* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(soa, array, start, length,
+    SetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(env, array, start, length,
                                                                      buf);
   }
 
   static void SetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize length,
                                 const jint* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(env, array, start, length, buf);
   }
 
   static void SetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize length,
                                  const jlong* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(env, array, start, length, buf);
   }
 
   static void SetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize length,
                                   const jshort* buf) {
-    ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(soa, array, start, length,
+    SetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(env, array, start, length,
                                                                      buf);
   }
 
@@ -2300,7 +2288,7 @@
       JniAbortF("RegisterNatives", "negative method count: %d", method_count);
       return JNI_ERR;  // Not reached.
     }
-    CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", java_class);
+    CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", java_class, JNI_ERR);
     ScopedObjectAccess soa(env);
     mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
     if (UNLIKELY(method_count == 0)) {
@@ -2308,7 +2296,7 @@
           << PrettyDescriptor(c);
       return JNI_OK;
     }
-    CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", methods);
+    CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", methods, JNI_ERR);
     for (jint i = 0; i < method_count; ++i) {
       const char* name = methods[i].name;
       const char* sig = methods[i].signature;
@@ -2345,30 +2333,37 @@
   }
 
   static jint UnregisterNatives(JNIEnv* env, jclass java_class) {
-    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_class, JNI_ERR);
     ScopedObjectAccess soa(env);
     mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
 
     VLOG(jni) << "[Unregistering JNI native methods for " << PrettyClass(c) << "]";
 
+    size_t unregistered_count = 0;
     for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
       mirror::ArtMethod* m = c->GetDirectMethod(i);
       if (m->IsNative()) {
         m->UnregisterNative(soa.Self());
+        unregistered_count++;
       }
     }
     for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
       mirror::ArtMethod* m = c->GetVirtualMethod(i);
       if (m->IsNative()) {
         m->UnregisterNative(soa.Self());
+        unregistered_count++;
       }
     }
 
+    if (unregistered_count == 0) {
+      LOG(WARNING) << "JNI UnregisterNatives: attempt to unregister native methods of class '"
+          << PrettyDescriptor(c) << "' that contains no native methods";
+    }
     return JNI_OK;
   }
 
   static jint MonitorEnter(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
-    CHECK_NON_NULL_ARGUMENT(java_object);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNI_ERR);
     ScopedObjectAccess soa(env);
     mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     o = o->MonitorEnter(soa.Self());
@@ -2380,7 +2375,7 @@
   }
 
   static jint MonitorExit(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
-    CHECK_NON_NULL_ARGUMENT(java_object);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNI_ERR);
     ScopedObjectAccess soa(env);
     mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     o->MonitorExit(soa.Self());
@@ -2392,7 +2387,7 @@
   }
 
   static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
-    CHECK_NON_NULL_ARGUMENT(vm);
+    CHECK_NON_NULL_ARGUMENT_RETURN(vm, JNI_ERR);
     Runtime* runtime = Runtime::Current();
     if (runtime != nullptr) {
       *vm = runtime->GetJavaVM();
@@ -2432,7 +2427,7 @@
   }
 
   static jobjectRefType GetObjectRefType(JNIEnv* env, jobject java_object) {
-    CHECK_NON_NULL_ARGUMENT(java_object);
+    CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNIInvalidRefType);
 
     // Do we definitely know what kind of reference this is?
     IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
@@ -2479,51 +2474,82 @@
   }
 
   template<typename JniT, typename ArtT>
-  static JniT NewPrimitiveArray(const ScopedObjectAccess& soa, jsize length)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  static JniT NewPrimitiveArray(JNIEnv* env, jsize length) {
     if (UNLIKELY(length < 0)) {
       JniAbortF("NewPrimitiveArray", "negative array length: %d", length);
       return nullptr;
     }
+    ScopedObjectAccess soa(env);
     ArtT* result = ArtT::Alloc(soa.Self(), length);
     return soa.AddLocalReference<JniT>(result);
   }
 
-  template <typename ArrayT, typename CArrayT, typename ArtArrayT>
-  static CArrayT GetPrimitiveArray(ScopedObjectAccess& soa, ArrayT java_array,
-                                   jboolean* is_copy)
+  template <typename JArrayT, typename ElementT, typename ArtArrayT>
+  static ArtArrayT* DecodeAndCheckArrayType(ScopedObjectAccess& soa, JArrayT java_array,
+                                           const char* fn_name, const char* operation)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     ArtArrayT* array = soa.Decode<ArtArrayT*>(java_array);
+    if (UNLIKELY(ArtArrayT::GetArrayClass() != array->GetClass())) {
+      JniAbortF(fn_name, "attempt to %s %s primitive array elements with an object of type %s",
+                operation, PrettyDescriptor(ArtArrayT::GetArrayClass()->GetComponentType()).c_str(),
+                PrettyDescriptor(array->GetClass()).c_str());
+      return nullptr;
+    }
+    DCHECK_EQ(sizeof(ElementT), array->GetClass()->GetComponentSize());
+    return array;
+  }
+
+  template <typename ArrayT, typename ElementT, typename ArtArrayT>
+  static ElementT* GetPrimitiveArray(JNIEnv* env, ArrayT java_array, jboolean* is_copy) {
+    CHECK_NON_NULL_ARGUMENT(java_array);
+    ScopedObjectAccess soa(env);
+    ArtArrayT* array = DecodeAndCheckArrayType<ArrayT, ElementT, ArtArrayT>(soa, java_array,
+                                                                            "GetArrayElements",
+                                                                            "get");
+    if (UNLIKELY(array == nullptr)) {
+      return nullptr;
+    }
     PinPrimitiveArray(soa, array);
     // Only make a copy if necessary.
     if (Runtime::Current()->GetHeap()->IsMovableObject(array)) {
       if (is_copy != nullptr) {
         *is_copy = JNI_TRUE;
       }
-      static const size_t component_size = array->GetClass()->GetComponentSize();
+      const size_t component_size = sizeof(ElementT);
       size_t size = array->GetLength() * component_size;
       void* data = new uint64_t[RoundUp(size, 8) / 8];
       memcpy(data, array->GetData(), size);
-      return reinterpret_cast<CArrayT>(data);
+      return reinterpret_cast<ElementT*>(data);
     } else {
       if (is_copy != nullptr) {
         *is_copy = JNI_FALSE;
       }
-      return reinterpret_cast<CArrayT>(array->GetData());
+      return reinterpret_cast<ElementT*>(array->GetData());
     }
   }
 
-  template <typename ArrayT, typename ElementT>
+  template <typename ArrayT, typename ElementT, typename ArtArrayT>
   static void ReleasePrimitiveArray(JNIEnv* env, ArrayT java_array, ElementT* elements, jint mode) {
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
     ScopedObjectAccess soa(env);
-    mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
-    size_t component_size = array->GetClass()->GetComponentSize();
+    ArtArrayT* array = DecodeAndCheckArrayType<ArrayT, ElementT, ArtArrayT>(soa, java_array,
+                                                                            "ReleaseArrayElements",
+                                                                            "release");
+    if (array == nullptr) {
+      return;
+    }
+    ReleasePrimitiveArray(soa, array, sizeof(ElementT), elements, mode);
+  }
+
+  static void ReleasePrimitiveArray(ScopedObjectAccess& soa, mirror::Array* array,
+                                    size_t component_size, void* elements, jint mode)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     void* array_data = array->GetRawData(component_size, 0);
     gc::Heap* heap = Runtime::Current()->GetHeap();
-    bool is_copy = array_data != reinterpret_cast<void*>(elements);
+    bool is_copy = array_data != elements;
     size_t bytes = array->GetLength() * component_size;
-    VLOG(heap) << "Release primitive array " << env << " array_data " << array_data
-               << " elements " << reinterpret_cast<void*>(elements);
+    VLOG(heap) << "Release primitive array " << soa.Env() << " array_data " << array_data
+               << " elements " << elements;
     if (is_copy) {
       // Sanity check: If elements is not the same as the java array's data, it better not be a
       // heap address. TODO: This might be slow to check, may be worth keeping track of which
@@ -2549,33 +2575,43 @@
     }
   }
 
-  template <typename JavaArrayT, typename JavaT, typename ArrayT>
-  static void GetPrimitiveArrayRegion(ScopedObjectAccess& soa, JavaArrayT java_array,
-                                      jsize start, jsize length, JavaT* buf)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CHECK_NON_NULL_ARGUMENT(java_array);
-    ArrayT* array = soa.Decode<ArrayT*>(java_array);
-    if (start < 0 || length < 0 || start + length > array->GetLength()) {
-      ThrowAIOOBE(soa, array, start, length, "src");
-    } else {
-      CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
-      JavaT* data = array->GetData();
-      memcpy(buf, data + start, length * sizeof(JavaT));
+  template <typename JArrayT, typename ElementT, typename ArtArrayT>
+  static void GetPrimitiveArrayRegion(JNIEnv* env, JArrayT java_array,
+                                      jsize start, jsize length, ElementT* buf) {
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
+    ScopedObjectAccess soa(env);
+    ArtArrayT* array =
+        DecodeAndCheckArrayType<JArrayT, ElementT, ArtArrayT>(soa, java_array,
+                                                              "GetPrimitiveArrayRegion",
+                                                              "get region of");
+    if (array != nullptr) {
+      if (start < 0 || length < 0 || start + length > array->GetLength()) {
+        ThrowAIOOBE(soa, array, start, length, "src");
+      } else {
+        CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
+        ElementT* data = array->GetData();
+        memcpy(buf, data + start, length * sizeof(ElementT));
+      }
     }
   }
 
-  template <typename JavaArrayT, typename JavaT, typename ArrayT>
-  static void SetPrimitiveArrayRegion(ScopedObjectAccess& soa, JavaArrayT java_array,
-                                      jsize start, jsize length, const JavaT* buf)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CHECK_NON_NULL_ARGUMENT(java_array);
-    ArrayT* array = soa.Decode<ArrayT*>(java_array);
-    if (start < 0 || length < 0 || start + length > array->GetLength()) {
-      ThrowAIOOBE(soa, array, start, length, "dst");
-    } else {
-      CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
-      JavaT* data = array->GetData();
-      memcpy(data + start, buf, length * sizeof(JavaT));
+  template <typename JArrayT, typename ElementT, typename ArtArrayT>
+  static void SetPrimitiveArrayRegion(JNIEnv* env, JArrayT java_array,
+                                      jsize start, jsize length, const ElementT* buf) {
+    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
+    ScopedObjectAccess soa(env);
+    ArtArrayT* array =
+        DecodeAndCheckArrayType<JArrayT, ElementT, ArtArrayT>(soa, java_array,
+                                                              "SetPrimitiveArrayRegion",
+                                                              "set region of");
+    if (array != nullptr) {
+      if (start < 0 || length < 0 || start + length > array->GetLength()) {
+        ThrowAIOOBE(soa, array, start, length, "dst");
+      } else {
+        CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
+        ElementT* data = array->GetData();
+        memcpy(data + start, buf, length * sizeof(ElementT));
+      }
     }
   }
 };
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 778b9e5..83e9b10 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -33,35 +33,54 @@
     // Turn on -verbose:jni for the JNI tests.
     // gLogVerbosity.jni = true;
 
-    vm_->AttachCurrentThread(&env_, NULL);
+    vm_->AttachCurrentThread(&env_, nullptr);
 
     ScopedLocalRef<jclass> aioobe(env_,
                                   env_->FindClass("java/lang/ArrayIndexOutOfBoundsException"));
-    CHECK(aioobe.get() != NULL);
+    CHECK(aioobe.get() != nullptr);
     aioobe_ = reinterpret_cast<jclass>(env_->NewGlobalRef(aioobe.get()));
 
     ScopedLocalRef<jclass> ase(env_, env_->FindClass("java/lang/ArrayStoreException"));
-    CHECK(ase.get() != NULL);
+    CHECK(ase.get() != nullptr);
     ase_ = reinterpret_cast<jclass>(env_->NewGlobalRef(ase.get()));
 
     ScopedLocalRef<jclass> sioobe(env_,
                                   env_->FindClass("java/lang/StringIndexOutOfBoundsException"));
-    CHECK(sioobe.get() != NULL);
+    CHECK(sioobe.get() != nullptr);
     sioobe_ = reinterpret_cast<jclass>(env_->NewGlobalRef(sioobe.get()));
   }
 
+  void ExpectException(jclass exception_class) {
+    EXPECT_TRUE(env_->ExceptionCheck());
+    jthrowable exception = env_->ExceptionOccurred();
+    EXPECT_NE(nullptr, exception);
+    env_->ExceptionClear();
+    EXPECT_TRUE(env_->IsInstanceOf(exception, exception_class));
+  }
+
+  void ExpectClassFound(const char* name) {
+    EXPECT_NE(env_->FindClass(name), nullptr) << name;
+    EXPECT_FALSE(env_->ExceptionCheck()) << name;
+  }
+
+  void ExpectClassNotFound(const char* name) {
+    EXPECT_EQ(env_->FindClass(name), nullptr) << name;
+    EXPECT_TRUE(env_->ExceptionCheck()) << name;
+    env_->ExceptionClear();
+  }
+
   void CleanUpJniEnv() {
-    if (aioobe_ != NULL) {
+    if (aioobe_ != nullptr) {
       env_->DeleteGlobalRef(aioobe_);
-      aioobe_ = NULL;
+      aioobe_ = nullptr;
     }
-    if (ase_ != NULL) {
+    if (ase_ != nullptr) {
       env_->DeleteGlobalRef(ase_);
-      ase_ = NULL;
+      ase_ = nullptr;
     }
-    if (sioobe_ != NULL) {
+    if (sioobe_ != nullptr) {
       env_->DeleteGlobalRef(sioobe_);
-      sioobe_ = NULL;
+      sioobe_ = nullptr;
     }
   }
 
@@ -86,9 +105,9 @@
 
 TEST_F(JniInternalTest, AllocObject) {
   jclass c = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   jobject o = env_->AllocObject(c);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
 
   // We have an instance of the class we asked for...
   ASSERT_TRUE(env_->IsInstanceOf(o, c));
@@ -96,139 +115,152 @@
   // we didn't call a constructor.
   ASSERT_EQ(0, env_->GetIntField(o, env_->GetFieldID(c, "count", "I")));
   ASSERT_EQ(0, env_->GetIntField(o, env_->GetFieldID(c, "offset", "I")));
-  ASSERT_TRUE(env_->GetObjectField(o, env_->GetFieldID(c, "value", "[C")) == NULL);
+  ASSERT_TRUE(env_->GetObjectField(o, env_->GetFieldID(c, "value", "[C")) == nullptr);
 }
 
 TEST_F(JniInternalTest, GetVersion) {
   ASSERT_EQ(JNI_VERSION_1_6, env_->GetVersion());
 }
 
-#define EXPECT_CLASS_FOUND(NAME) \
-  EXPECT_TRUE(env_->FindClass(NAME) != NULL); \
-  EXPECT_FALSE(env_->ExceptionCheck())
-
-#define EXPECT_CLASS_NOT_FOUND(NAME) \
-  EXPECT_TRUE(env_->FindClass(NAME) == NULL); \
-  EXPECT_TRUE(env_->ExceptionCheck()); \
-  env_->ExceptionClear()
-
 TEST_F(JniInternalTest, FindClass) {
   // Reference types...
-  EXPECT_CLASS_FOUND("java/lang/String");
+  ExpectClassFound("java/lang/String");
   // ...for arrays too, where you must include "L;".
-  EXPECT_CLASS_FOUND("[Ljava/lang/String;");
+  ExpectClassFound("[Ljava/lang/String;");
   // Primitive arrays are okay too, if the primitive type is valid.
-  EXPECT_CLASS_FOUND("[C");
+  ExpectClassFound("[C");
 
   {
-    // We support . as well as / for compatibility, if -Xcheck:jni is off.
     CheckJniAbortCatcher check_jni_abort_catcher;
-    EXPECT_CLASS_FOUND("java.lang.String");
+    env_->FindClass(nullptr);
+    check_jni_abort_catcher.Check("name == null");
+
+    // We support . as well as / for compatibility, if -Xcheck:jni is off.
+    ExpectClassFound("java.lang.String");
     check_jni_abort_catcher.Check("illegal class name 'java.lang.String'");
-    EXPECT_CLASS_NOT_FOUND("Ljava.lang.String;");
+    ExpectClassNotFound("Ljava.lang.String;");
     check_jni_abort_catcher.Check("illegal class name 'Ljava.lang.String;'");
-    EXPECT_CLASS_FOUND("[Ljava.lang.String;");
+    ExpectClassFound("[Ljava.lang.String;");
     check_jni_abort_catcher.Check("illegal class name '[Ljava.lang.String;'");
-    EXPECT_CLASS_NOT_FOUND("[java.lang.String");
+    ExpectClassNotFound("[java.lang.String");
     check_jni_abort_catcher.Check("illegal class name '[java.lang.String'");
 
     // You can't include the "L;" in a JNI class descriptor.
-    EXPECT_CLASS_NOT_FOUND("Ljava/lang/String;");
+    ExpectClassNotFound("Ljava/lang/String;");
     check_jni_abort_catcher.Check("illegal class name 'Ljava/lang/String;'");
 
     // But you must include it for an array of any reference type.
-    EXPECT_CLASS_NOT_FOUND("[java/lang/String");
+    ExpectClassNotFound("[java/lang/String");
     check_jni_abort_catcher.Check("illegal class name '[java/lang/String'");
 
-    EXPECT_CLASS_NOT_FOUND("[K");
+    ExpectClassNotFound("[K");
     check_jni_abort_catcher.Check("illegal class name '[K'");
+
+    // Void arrays aren't allowed.
+    ExpectClassNotFound("[V");
+    check_jni_abort_catcher.Check("illegal class name '[V'");
   }
 
   // But primitive types aren't allowed...
-  EXPECT_CLASS_NOT_FOUND("C");
-  EXPECT_CLASS_NOT_FOUND("K");
+  ExpectClassNotFound("C");
+  ExpectClassNotFound("V");
+  ExpectClassNotFound("K");
 }
 
-#define EXPECT_EXCEPTION(exception_class) \
-  do { \
-    EXPECT_TRUE(env_->ExceptionCheck()); \
-    jthrowable exception = env_->ExceptionOccurred(); \
-    EXPECT_NE(static_cast<jthrowable>(NULL), exception); \
-    env_->ExceptionClear(); \
-    EXPECT_TRUE(env_->IsInstanceOf(exception, exception_class)); \
-  } while (false)
-
 TEST_F(JniInternalTest, GetFieldID) {
   jclass jlnsfe = env_->FindClass("java/lang/NoSuchFieldError");
-  ASSERT_TRUE(jlnsfe != NULL);
+  ASSERT_NE(jlnsfe, nullptr);
   jclass c = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
 
   // Wrong type.
   jfieldID fid = env_->GetFieldID(c, "count", "J");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Wrong type where type doesn't exist.
   fid = env_->GetFieldID(c, "count", "Lrod/jane/freddy;");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Wrong name.
   fid = env_->GetFieldID(c, "Count", "I");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Good declared field lookup.
   fid = env_->GetFieldID(c, "count", "I");
-  EXPECT_NE(static_cast<jfieldID>(NULL), fid);
-  EXPECT_TRUE(fid != NULL);
+  EXPECT_NE(nullptr, fid);
   EXPECT_FALSE(env_->ExceptionCheck());
 
   // Good superclass field lookup.
   c = env_->FindClass("java/lang/StringBuilder");
   fid = env_->GetFieldID(c, "count", "I");
-  EXPECT_NE(static_cast<jfieldID>(NULL), fid);
-  EXPECT_TRUE(fid != NULL);
+  EXPECT_NE(nullptr, fid);
+  EXPECT_NE(fid, nullptr);
   EXPECT_FALSE(env_->ExceptionCheck());
 
   // Not instance.
   fid = env_->GetFieldID(c, "CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  fid = env_->GetFieldID(nullptr, "count", "I");
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("java_class == null");
+  fid = env_->GetFieldID(c, nullptr, "I");
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("name == null");
+  fid = env_->GetFieldID(c, "count", nullptr);
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("sig == null");
 }
 
 TEST_F(JniInternalTest, GetStaticFieldID) {
   jclass jlnsfe = env_->FindClass("java/lang/NoSuchFieldError");
-  ASSERT_TRUE(jlnsfe != NULL);
+  ASSERT_NE(jlnsfe, nullptr);
   jclass c = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
 
   // Wrong type.
   jfieldID fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", "J");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Wrong type where type doesn't exist.
   fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", "Lrod/jane/freddy;");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Wrong name.
   fid = env_->GetStaticFieldID(c, "cASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
 
   // Good declared field lookup.
   fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
-  EXPECT_NE(static_cast<jfieldID>(NULL), fid);
-  EXPECT_TRUE(fid != NULL);
+  EXPECT_NE(nullptr, fid);
+  EXPECT_NE(fid, nullptr);
   EXPECT_FALSE(env_->ExceptionCheck());
 
   // Not static.
   fid = env_->GetStaticFieldID(c, "count", "I");
-  EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
-  EXPECT_EXCEPTION(jlnsfe);
+  EXPECT_EQ(nullptr, fid);
+  ExpectException(jlnsfe);
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  fid = env_->GetStaticFieldID(nullptr, "CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("java_class == null");
+  fid = env_->GetStaticFieldID(c, nullptr, "Ljava/util/Comparator;");
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("name == null");
+  fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", nullptr);
+  EXPECT_EQ(nullptr, fid);
+  check_jni_abort_catcher.Check("sig == null");
 }
 
 TEST_F(JniInternalTest, GetMethodID) {
@@ -242,24 +274,36 @@
   // Check that java.lang.Object.foo() doesn't exist and NoSuchMethodError is
   // a pending exception
   jmethodID method = env_->GetMethodID(jlobject, "foo", "()V");
-  EXPECT_EQ(static_cast<jmethodID>(NULL), method);
-  EXPECT_EXCEPTION(jlnsme);
+  EXPECT_EQ(nullptr, method);
+  ExpectException(jlnsme);
 
   // Check that java.lang.Object.equals() does exist
   method = env_->GetMethodID(jlobject, "equals", "(Ljava/lang/Object;)Z");
-  EXPECT_NE(static_cast<jmethodID>(NULL), method);
+  EXPECT_NE(nullptr, method);
   EXPECT_FALSE(env_->ExceptionCheck());
 
   // Check that GetMethodID for java.lang.String.valueOf(int) fails as the
   // method is static
   method = env_->GetMethodID(jlstring, "valueOf", "(I)Ljava/lang/String;");
-  EXPECT_EQ(static_cast<jmethodID>(NULL), method);
-  EXPECT_EXCEPTION(jlnsme);
+  EXPECT_EQ(nullptr, method);
+  ExpectException(jlnsme);
 
   // Check that GetMethodID for java.lang.NoSuchMethodError.<init>(String) finds the constructor
   method = env_->GetMethodID(jlnsme, "<init>", "(Ljava/lang/String;)V");
-  EXPECT_NE(static_cast<jmethodID>(NULL), method);
+  EXPECT_NE(nullptr, method);
   EXPECT_FALSE(env_->ExceptionCheck());
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  method = env_->GetMethodID(nullptr, "<init>", "(Ljava/lang/String;)V");
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("java_class == null");
+  method = env_->GetMethodID(jlnsme, nullptr, "(Ljava/lang/String;)V");
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("name == null");
+  method = env_->GetMethodID(jlnsme, "<init>", nullptr);
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("sig == null");
 }
 
 TEST_F(JniInternalTest, GetStaticMethodID) {
@@ -272,93 +316,155 @@
   // Check that java.lang.Object.foo() doesn't exist and NoSuchMethodError is
   // a pending exception
   jmethodID method = env_->GetStaticMethodID(jlobject, "foo", "()V");
-  EXPECT_EQ(static_cast<jmethodID>(NULL), method);
-  EXPECT_EXCEPTION(jlnsme);
+  EXPECT_EQ(nullptr, method);
+  ExpectException(jlnsme);
 
   // Check that GetStaticMethodID for java.lang.Object.equals(Object) fails as
   // the method is not static
   method = env_->GetStaticMethodID(jlobject, "equals", "(Ljava/lang/Object;)Z");
-  EXPECT_EQ(static_cast<jmethodID>(NULL), method);
-  EXPECT_EXCEPTION(jlnsme);
+  EXPECT_EQ(nullptr, method);
+  ExpectException(jlnsme);
 
   // Check that java.lang.String.valueOf(int) does exist
   jclass jlstring = env_->FindClass("java/lang/String");
-  method = env_->GetStaticMethodID(jlstring, "valueOf",
-                                   "(I)Ljava/lang/String;");
-  EXPECT_NE(static_cast<jmethodID>(NULL), method);
+  method = env_->GetStaticMethodID(jlstring, "valueOf", "(I)Ljava/lang/String;");
+  EXPECT_NE(nullptr, method);
   EXPECT_FALSE(env_->ExceptionCheck());
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  method = env_->GetStaticMethodID(nullptr, "valueOf", "(I)Ljava/lang/String;");
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("java_class == null");
+  method = env_->GetStaticMethodID(jlstring, nullptr, "(I)Ljava/lang/String;");
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("name == null");
+  method = env_->GetStaticMethodID(jlstring, "valueOf", nullptr);
+  EXPECT_EQ(nullptr, method);
+  check_jni_abort_catcher.Check("sig == null");
 }
 
 TEST_F(JniInternalTest, FromReflectedField_ToReflectedField) {
   jclass jlrField = env_->FindClass("java/lang/reflect/Field");
   jclass c = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   jfieldID fid = env_->GetFieldID(c, "count", "I");
-  ASSERT_TRUE(fid != NULL);
+  ASSERT_NE(fid, nullptr);
   // Turn the fid into a java.lang.reflect.Field...
   jobject field = env_->ToReflectedField(c, fid, JNI_FALSE);
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   ASSERT_TRUE(env_->IsInstanceOf(field, jlrField));
   // ...and back again.
   jfieldID fid2 = env_->FromReflectedField(field);
-  ASSERT_TRUE(fid2 != NULL);
+  ASSERT_NE(fid2, nullptr);
   // Make sure we can actually use it.
   jstring s = env_->NewStringUTF("poop");
   ASSERT_EQ(4, env_->GetIntField(s, fid2));
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  field = env_->ToReflectedField(c, nullptr, JNI_FALSE);
+  EXPECT_EQ(field, nullptr);
+  check_jni_abort_catcher.Check("fid == null");
+  fid2 = env_->FromReflectedField(nullptr);
+  ASSERT_EQ(fid2, nullptr);
+  check_jni_abort_catcher.Check("jlr_field == null");
 }
 
 TEST_F(JniInternalTest, FromReflectedMethod_ToReflectedMethod) {
   jclass jlrMethod = env_->FindClass("java/lang/reflect/Method");
   jclass c = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   jmethodID mid = env_->GetMethodID(c, "length", "()I");
-  ASSERT_TRUE(mid != NULL);
+  ASSERT_NE(mid, nullptr);
   // Turn the mid into a java.lang.reflect.Method...
   jobject method = env_->ToReflectedMethod(c, mid, JNI_FALSE);
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   ASSERT_TRUE(env_->IsInstanceOf(method, jlrMethod));
   // ...and back again.
   jmethodID mid2 = env_->FromReflectedMethod(method);
-  ASSERT_TRUE(mid2 != NULL);
+  ASSERT_NE(mid2, nullptr);
   // Make sure we can actually use it.
   jstring s = env_->NewStringUTF("poop");
   ASSERT_EQ(4, env_->CallIntMethod(s, mid2));
+
+  // Bad arguments.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  method = env_->ToReflectedMethod(c, nullptr, JNI_FALSE);
+  EXPECT_EQ(method, nullptr);
+  check_jni_abort_catcher.Check("mid == null");
+  mid2 = env_->FromReflectedMethod(method);
+  ASSERT_EQ(mid2, nullptr);
+  check_jni_abort_catcher.Check("jlr_method == null");
 }
 
-void BogusMethod() {
-  // You can't pass NULL function pointers to RegisterNatives.
+static void BogusMethod() {
+  // You can't pass nullptr function pointers to RegisterNatives.
 }
 
-TEST_F(JniInternalTest, RegisterNatives) {
+TEST_F(JniInternalTest, RegisterAndUnregisterNatives) {
   jclass jlobject = env_->FindClass("java/lang/Object");
   jclass jlnsme = env_->FindClass("java/lang/NoSuchMethodError");
 
-  // Sanity check that no exceptions are pending
+  // Sanity check that no exceptions are pending.
   ASSERT_FALSE(env_->ExceptionCheck());
 
-  // Check that registering to a non-existent java.lang.Object.foo() causes a
-  // NoSuchMethodError
+  // Check that registering to a non-existent java.lang.Object.foo() causes a NoSuchMethodError.
   {
-    JNINativeMethod methods[] = { { "foo", "()V", NULL } };
-    env_->RegisterNatives(jlobject, methods, 1);
+    JNINativeMethod methods[] = { { "foo", "()V", nullptr } };
+    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
   }
-  EXPECT_EXCEPTION(jlnsme);
+  ExpectException(jlnsme);
 
-  // Check that registering non-native methods causes a NoSuchMethodError
+  // Check that registering non-native methods causes a NoSuchMethodError.
   {
-    JNINativeMethod methods[] = { { "equals", "(Ljava/lang/Object;)Z", NULL } };
-    env_->RegisterNatives(jlobject, methods, 1);
+    JNINativeMethod methods[] = { { "equals", "(Ljava/lang/Object;)Z", nullptr } };
+    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_ERR);
   }
-  EXPECT_EXCEPTION(jlnsme);
+  ExpectException(jlnsme);
 
-  // Check that registering native methods is successful
+  // Check that registering native methods is successful.
   {
     JNINativeMethod methods[] = { { "notify", "()V", reinterpret_cast<void*>(BogusMethod) } };
-    env_->RegisterNatives(jlobject, methods, 1);
+    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 1), JNI_OK);
+  }
+  EXPECT_FALSE(env_->ExceptionCheck());
+  EXPECT_EQ(env_->UnregisterNatives(jlobject), JNI_OK);
+
+  // Check that registering no methods isn't a failure.
+  {
+    JNINativeMethod methods[] = { };
+    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, 0), JNI_OK);
+  }
+  EXPECT_FALSE(env_->ExceptionCheck());
+  EXPECT_EQ(env_->UnregisterNatives(jlobject), JNI_OK);
+
+  // Check that registering a -ve number of methods is a failure.
+  CheckJniAbortCatcher check_jni_abort_catcher;
+  for (int i = -10; i < 0; ++i) {
+    JNINativeMethod methods[] = { };
+    EXPECT_EQ(env_->RegisterNatives(jlobject, methods, i), JNI_ERR);
+    check_jni_abort_catcher.Check("negative method count: ");
   }
   EXPECT_FALSE(env_->ExceptionCheck());
 
-  env_->UnregisterNatives(jlobject);
+  // Passing a class of null is a failure.
+  {
+    JNINativeMethod methods[] = { };
+    EXPECT_EQ(env_->RegisterNatives(nullptr, methods, 0), JNI_ERR);
+    check_jni_abort_catcher.Check("java_class == null");
+  }
+
+  // Passing methods as null is a failure.
+  EXPECT_EQ(env_->RegisterNatives(jlobject, nullptr, 1), JNI_ERR);
+  check_jni_abort_catcher.Check("methods == null");
+
+  // Unregisters null is a failure.
+  EXPECT_EQ(env_->UnregisterNatives(nullptr), JNI_ERR);
+  check_jni_abort_catcher.Check("java_class == null");
+
+  // Unregistering a class with no natives is a warning.
+  EXPECT_EQ(env_->UnregisterNatives(jlnsme), JNI_OK);
 }
 
 #define EXPECT_PRIMITIVE_ARRAY(new_fn, \
@@ -368,52 +474,69 @@
                                release_elements_fn, \
                                scalar_type, \
                                expected_class_descriptor) \
+  jsize size = 4; \
+  \
   { \
     CheckJniAbortCatcher jni_abort_catcher; \
     /* Allocate an negative sized array and check it has the right failure type. */ \
-    env_->new_fn(-1); \
+    EXPECT_EQ(env_->new_fn(-1), nullptr); \
     jni_abort_catcher.Check("negative array length: -1"); \
-    env_->new_fn(std::numeric_limits<jint>::min()); \
+    EXPECT_EQ(env_->new_fn(std::numeric_limits<jint>::min()), nullptr); \
     jni_abort_catcher.Check("negative array length: -2147483648"); \
+    /* Pass the array as null. */ \
+    EXPECT_EQ(0, env_->GetArrayLength(nullptr)); \
+    jni_abort_catcher.Check("java_array == null"); \
+    env_->get_region_fn(nullptr, 0, 0, nullptr); \
+    jni_abort_catcher.Check("java_array == null"); \
+    env_->set_region_fn(nullptr, 0, 0, nullptr); \
+    jni_abort_catcher.Check("java_array == null"); \
+    env_->get_elements_fn(nullptr, nullptr); \
+    jni_abort_catcher.Check("java_array == null"); \
+    env_->release_elements_fn(nullptr, nullptr, 0); \
+    jni_abort_catcher.Check("java_array == null"); \
+    /* Pass the elements for region as null. */ \
+    scalar_type ## Array a = env_->new_fn(size); \
+    env_->get_region_fn(a, 0, size, nullptr); \
+    jni_abort_catcher.Check("buf == null"); \
+    env_->set_region_fn(a, 0, size, nullptr); \
+    jni_abort_catcher.Check("buf == null"); \
   } \
-  jsize size = 4; \
-  \
   /* Allocate an array and check it has the right type and length. */ \
   scalar_type ## Array a = env_->new_fn(size); \
-  EXPECT_TRUE(a != NULL); \
+  EXPECT_NE(a, nullptr); \
   EXPECT_TRUE(env_->IsInstanceOf(a, env_->FindClass(expected_class_descriptor))); \
   EXPECT_EQ(size, env_->GetArrayLength(a)); \
   \
   /* GetPrimitiveArrayRegion/SetPrimitiveArrayRegion */ \
   /* AIOOBE for negative start offset. */ \
-  env_->get_region_fn(a, -1, 1, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
-  env_->set_region_fn(a, -1, 1, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
+  env_->get_region_fn(a, -1, 1, nullptr); \
+  ExpectException(aioobe_); \
+  env_->set_region_fn(a, -1, 1, nullptr); \
+  ExpectException(aioobe_); \
   \
   /* AIOOBE for negative length. */ \
-  env_->get_region_fn(a, 0, -1, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
-  env_->set_region_fn(a, 0, -1, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
+  env_->get_region_fn(a, 0, -1, nullptr); \
+  ExpectException(aioobe_); \
+  env_->set_region_fn(a, 0, -1, nullptr); \
+  ExpectException(aioobe_); \
   \
   /* AIOOBE for buffer overrun. */ \
-  env_->get_region_fn(a, size - 1, size, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
-  env_->set_region_fn(a, size - 1, size, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
+  env_->get_region_fn(a, size - 1, size, nullptr); \
+  ExpectException(aioobe_); \
+  env_->set_region_fn(a, size - 1, size, nullptr); \
+  ExpectException(aioobe_); \
   \
-  /* It's okay for the buffer to be NULL as long as the length is 0. */ \
-  env_->get_region_fn(a, 2, 0, NULL); \
+  /* It's okay for the buffer to be nullptr as long as the length is 0. */ \
+  env_->get_region_fn(a, 2, 0, nullptr); \
   /* Even if the offset is invalid... */ \
-  env_->get_region_fn(a, 123, 0, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
+  env_->get_region_fn(a, 123, 0, nullptr); \
+  ExpectException(aioobe_); \
   \
-  /* It's okay for the buffer to be NULL as long as the length is 0. */ \
-  env_->set_region_fn(a, 2, 0, NULL); \
+  /* It's okay for the buffer to be nullptr as long as the length is 0. */ \
+  env_->set_region_fn(a, 2, 0, nullptr); \
   /* Even if the offset is invalid... */ \
-  env_->set_region_fn(a, 123, 0, NULL); \
-  EXPECT_EXCEPTION(aioobe_); \
+  env_->set_region_fn(a, 123, 0, nullptr); \
+  ExpectException(aioobe_); \
   \
   /* Prepare a couple of buffers. */ \
   UniquePtr<scalar_type[]> src_buf(new scalar_type[size]); \
@@ -437,12 +560,12 @@
   EXPECT_EQ(memcmp(&src_buf[0], &dst_buf[0], size * sizeof(scalar_type)), 0) \
     << "full copy not equal"; \
   /* GetPrimitiveArrayCritical */ \
-  void* v = env_->GetPrimitiveArrayCritical(a, NULL); \
+  void* v = env_->GetPrimitiveArrayCritical(a, nullptr); \
   EXPECT_EQ(memcmp(&src_buf[0], v, size * sizeof(scalar_type)), 0) \
     << "GetPrimitiveArrayCritical not equal"; \
   env_->ReleasePrimitiveArrayCritical(a, v, 0); \
   /* GetXArrayElements */ \
-  scalar_type* xs = env_->get_elements_fn(a, NULL); \
+  scalar_type* xs = env_->get_elements_fn(a, nullptr); \
   EXPECT_EQ(memcmp(&src_buf[0], xs, size * sizeof(scalar_type)), 0) \
     << # get_elements_fn " not equal"; \
   env_->release_elements_fn(a, xs, 0); \
@@ -480,31 +603,206 @@
                          GetShortArrayElements, ReleaseShortArrayElements, jshort, "[S");
 }
 
+TEST_F(JniInternalTest, GetPrimitiveArrayElementsOfWrongType) {
+  CheckJniAbortCatcher jni_abort_catcher;
+  jbooleanArray array = env_->NewBooleanArray(10);
+  jboolean is_copy;
+  EXPECT_EQ(env_->GetByteArrayElements(reinterpret_cast<jbyteArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get byte primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetShortArrayElements(reinterpret_cast<jshortArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get short primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetCharArrayElements(reinterpret_cast<jcharArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get char primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetIntArrayElements(reinterpret_cast<jintArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get int primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetLongArrayElements(reinterpret_cast<jlongArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get long primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetFloatArrayElements(reinterpret_cast<jfloatArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get float primitive array elements with an object of type boolean[]");
+  EXPECT_EQ(env_->GetDoubleArrayElements(reinterpret_cast<jdoubleArray>(array), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get double primitive array elements with an object of type boolean[]");
+  jbyteArray array2 = env_->NewByteArray(10);
+  EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get boolean primitive array elements with an object of type byte[]");
+  jobject object = env_->NewStringUTF("Test String");
+  EXPECT_EQ(env_->GetBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), &is_copy), nullptr);
+  jni_abort_catcher.Check(
+      "attempt to get boolean primitive array elements with an object of type java.lang.String");
+}
+
+TEST_F(JniInternalTest, ReleasePrimitiveArrayElementsOfWrongType) {
+  CheckJniAbortCatcher jni_abort_catcher;
+  jbooleanArray array = env_->NewBooleanArray(10);
+  ASSERT_TRUE(array != nullptr);
+  jboolean is_copy;
+  jboolean* elements = env_->GetBooleanArrayElements(array, &is_copy);
+  ASSERT_TRUE(elements != nullptr);
+  env_->ReleaseByteArrayElements(reinterpret_cast<jbyteArray>(array),
+                                 reinterpret_cast<jbyte*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release byte primitive array elements with an object of type boolean[]");
+  env_->ReleaseShortArrayElements(reinterpret_cast<jshortArray>(array),
+                                  reinterpret_cast<jshort*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release short primitive array elements with an object of type boolean[]");
+  env_->ReleaseCharArrayElements(reinterpret_cast<jcharArray>(array),
+                                 reinterpret_cast<jchar*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release char primitive array elements with an object of type boolean[]");
+  env_->ReleaseIntArrayElements(reinterpret_cast<jintArray>(array),
+                                reinterpret_cast<jint*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release int primitive array elements with an object of type boolean[]");
+  env_->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array),
+                                 reinterpret_cast<jlong*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release long primitive array elements with an object of type boolean[]");
+  env_->ReleaseFloatArrayElements(reinterpret_cast<jfloatArray>(array),
+                                  reinterpret_cast<jfloat*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release float primitive array elements with an object of type boolean[]");
+  env_->ReleaseDoubleArrayElements(reinterpret_cast<jdoubleArray>(array),
+                                  reinterpret_cast<jdouble*>(elements), 0);
+  jni_abort_catcher.Check(
+      "attempt to release double primitive array elements with an object of type boolean[]");
+  jbyteArray array2 = env_->NewByteArray(10);
+  env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), elements, 0);
+  jni_abort_catcher.Check(
+      "attempt to release boolean primitive array elements with an object of type byte[]");
+  jobject object = env_->NewStringUTF("Test String");
+  env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), elements, 0);
+  jni_abort_catcher.Check(
+      "attempt to release boolean primitive array elements with an object of type java.lang.String");
+}
+TEST_F(JniInternalTest, GetReleasePrimitiveArrayCriticalOfWrongType) {
+  CheckJniAbortCatcher jni_abort_catcher;
+  jobject object = env_->NewStringUTF("Test String");
+  jboolean is_copy;
+  void* elements = env_->GetPrimitiveArrayCritical(reinterpret_cast<jarray>(object), &is_copy);
+  jni_abort_catcher.Check("expected primitive array, given java.lang.String");
+  env_->ReleasePrimitiveArrayCritical(reinterpret_cast<jarray>(object), elements, 0);
+  jni_abort_catcher.Check("expected primitive array, given java.lang.String");
+}
+
+TEST_F(JniInternalTest, GetPrimitiveArrayRegionElementsOfWrongType) {
+  CheckJniAbortCatcher jni_abort_catcher;
+  constexpr size_t kLength = 10;
+  jbooleanArray array = env_->NewBooleanArray(kLength);
+  ASSERT_TRUE(array != nullptr);
+  jboolean elements[kLength];
+  env_->GetByteArrayRegion(reinterpret_cast<jbyteArray>(array), 0, kLength,
+                           reinterpret_cast<jbyte*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of byte primitive array elements with an object of type boolean[]");
+  env_->GetShortArrayRegion(reinterpret_cast<jshortArray>(array), 0, kLength,
+                            reinterpret_cast<jshort*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of short primitive array elements with an object of type boolean[]");
+  env_->GetCharArrayRegion(reinterpret_cast<jcharArray>(array), 0, kLength,
+                           reinterpret_cast<jchar*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of char primitive array elements with an object of type boolean[]");
+  env_->GetIntArrayRegion(reinterpret_cast<jintArray>(array), 0, kLength,
+                          reinterpret_cast<jint*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of int primitive array elements with an object of type boolean[]");
+  env_->GetLongArrayRegion(reinterpret_cast<jlongArray>(array), 0, kLength,
+                           reinterpret_cast<jlong*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of long primitive array elements with an object of type boolean[]");
+  env_->GetFloatArrayRegion(reinterpret_cast<jfloatArray>(array), 0, kLength,
+                            reinterpret_cast<jfloat*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of float primitive array elements with an object of type boolean[]");
+  env_->GetDoubleArrayRegion(reinterpret_cast<jdoubleArray>(array), 0, kLength,
+                           reinterpret_cast<jdouble*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of double primitive array elements with an object of type boolean[]");
+  jbyteArray array2 = env_->NewByteArray(10);
+  env_->GetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(array2), 0, kLength,
+                              reinterpret_cast<jboolean*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of boolean primitive array elements with an object of type byte[]");
+  jobject object = env_->NewStringUTF("Test String");
+  env_->GetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(object), 0, kLength,
+                              reinterpret_cast<jboolean*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to get region of boolean primitive array elements with an object of type java.lang.String");
+}
+
+TEST_F(JniInternalTest, SetPrimitiveArrayRegionElementsOfWrongType) {
+  CheckJniAbortCatcher jni_abort_catcher;
+  constexpr size_t kLength = 10;
+  jbooleanArray array = env_->NewBooleanArray(kLength);
+  ASSERT_TRUE(array != nullptr);
+  jboolean elements[kLength];
+  env_->SetByteArrayRegion(reinterpret_cast<jbyteArray>(array), 0, kLength,
+                           reinterpret_cast<jbyte*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of byte primitive array elements with an object of type boolean[]");
+  env_->SetShortArrayRegion(reinterpret_cast<jshortArray>(array), 0, kLength,
+                            reinterpret_cast<jshort*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of short primitive array elements with an object of type boolean[]");
+  env_->SetCharArrayRegion(reinterpret_cast<jcharArray>(array), 0, kLength,
+                           reinterpret_cast<jchar*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of char primitive array elements with an object of type boolean[]");
+  env_->SetIntArrayRegion(reinterpret_cast<jintArray>(array), 0, kLength,
+                          reinterpret_cast<jint*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of int primitive array elements with an object of type boolean[]");
+  env_->SetLongArrayRegion(reinterpret_cast<jlongArray>(array), 0, kLength,
+                           reinterpret_cast<jlong*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of long primitive array elements with an object of type boolean[]");
+  env_->SetFloatArrayRegion(reinterpret_cast<jfloatArray>(array), 0, kLength,
+                            reinterpret_cast<jfloat*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of float primitive array elements with an object of type boolean[]");
+  env_->SetDoubleArrayRegion(reinterpret_cast<jdoubleArray>(array), 0, kLength,
+                           reinterpret_cast<jdouble*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of double primitive array elements with an object of type boolean[]");
+  jbyteArray array2 = env_->NewByteArray(10);
+  env_->SetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(array2), 0, kLength,
+                              reinterpret_cast<jboolean*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of boolean primitive array elements with an object of type byte[]");
+  jobject object = env_->NewStringUTF("Test String");
+  env_->SetBooleanArrayRegion(reinterpret_cast<jbooleanArray>(object), 0, kLength,
+                              reinterpret_cast<jboolean*>(elements));
+  jni_abort_catcher.Check(
+      "attempt to set region of boolean primitive array elements with an object of type java.lang.String");
+}
+
 TEST_F(JniInternalTest, NewObjectArray) {
   jclass element_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(element_class != nullptr);
+  ASSERT_NE(element_class, nullptr);
   jclass array_class = env_->FindClass("[Ljava/lang/String;");
-  ASSERT_TRUE(array_class != nullptr);
+  ASSERT_NE(array_class, nullptr);
 
   jobjectArray a = env_->NewObjectArray(0, element_class, nullptr);
-  EXPECT_TRUE(a != nullptr);
+  EXPECT_NE(a, nullptr);
   EXPECT_TRUE(env_->IsInstanceOf(a, array_class));
   EXPECT_EQ(0, env_->GetArrayLength(a));
 
   a = env_->NewObjectArray(1, element_class, nullptr);
-  EXPECT_TRUE(a != nullptr);
+  EXPECT_NE(a, nullptr);
   EXPECT_TRUE(env_->IsInstanceOf(a, array_class));
   EXPECT_EQ(1, env_->GetArrayLength(a));
   EXPECT_TRUE(env_->IsSameObject(env_->GetObjectArrayElement(a, 0), nullptr));
-}
 
-TEST_F(JniInternalTest, NewObjectArrayWithNegativeLength) {
-  jclass element_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(element_class != nullptr);
-  jclass array_class = env_->FindClass("[Ljava/lang/String;");
-  ASSERT_TRUE(array_class != nullptr);
+  // Negative array length checks.
   CheckJniAbortCatcher jni_abort_catcher;
-
   env_->NewObjectArray(-1, element_class, nullptr);
   jni_abort_catcher.Check("negative array length: -1");
 
@@ -521,6 +819,8 @@
 
   CheckJniAbortCatcher jni_abort_catcher;
   for (size_t i = 0; i < strlen(primitive_descriptors); ++i) {
+    env_->NewObjectArray(0, nullptr, nullptr);
+    jni_abort_catcher.Check("element_jclass == null");
     jclass primitive_class = GetPrimitiveClass(primitive_descriptors[i]);
     env_->NewObjectArray(1, primitive_class, nullptr);
     std::string error_msg(StringPrintf("not an object type: %s", primitive_names[i]));
@@ -530,13 +830,13 @@
 
 TEST_F(JniInternalTest, NewObjectArrayWithInitialValue) {
   jclass element_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(element_class != nullptr);
+  ASSERT_NE(element_class, nullptr);
   jclass array_class = env_->FindClass("[Ljava/lang/String;");
-  ASSERT_TRUE(array_class != nullptr);
+  ASSERT_NE(array_class, nullptr);
 
   jstring s = env_->NewStringUTF("poop");
   jobjectArray a = env_->NewObjectArray(2, element_class, s);
-  EXPECT_TRUE(a != nullptr);
+  EXPECT_NE(a, nullptr);
   EXPECT_TRUE(env_->IsInstanceOf(a, array_class));
   EXPECT_EQ(2, env_->GetArrayLength(a));
   EXPECT_TRUE(env_->IsSameObject(env_->GetObjectArrayElement(a, 0), s));
@@ -555,9 +855,9 @@
 
 TEST_F(JniInternalTest, GetObjectClass) {
   jclass string_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(string_class != NULL);
+  ASSERT_NE(string_class, nullptr);
   jclass class_class = env_->FindClass("java/lang/Class");
-  ASSERT_TRUE(class_class != NULL);
+  ASSERT_NE(class_class, nullptr);
 
   jstring s = env_->NewStringUTF("poop");
   jclass c = env_->GetObjectClass(s);
@@ -565,33 +865,50 @@
 
   jclass c2 = env_->GetObjectClass(c);
   ASSERT_TRUE(env_->IsSameObject(class_class, env_->GetObjectClass(c2)));
+
+  // Null as object should fail.
+  CheckJniAbortCatcher jni_abort_catcher;
+  EXPECT_EQ(env_->GetObjectClass(nullptr), nullptr);
+  jni_abort_catcher.Check("java_object == null");
 }
 
 TEST_F(JniInternalTest, GetSuperclass) {
   jclass object_class = env_->FindClass("java/lang/Object");
-  ASSERT_TRUE(object_class != NULL);
+  ASSERT_NE(object_class, nullptr);
   jclass string_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(string_class != NULL);
+  ASSERT_NE(string_class, nullptr);
   jclass runnable_interface = env_->FindClass("java/lang/Runnable");
-  ASSERT_TRUE(runnable_interface != NULL);
+  ASSERT_NE(runnable_interface, nullptr);
   ASSERT_TRUE(env_->IsSameObject(object_class, env_->GetSuperclass(string_class)));
-  ASSERT_TRUE(env_->GetSuperclass(object_class) == NULL);
+  ASSERT_EQ(env_->GetSuperclass(object_class), nullptr);
   ASSERT_TRUE(env_->IsSameObject(object_class, env_->GetSuperclass(runnable_interface)));
+
+  // Null as class should fail.
+  CheckJniAbortCatcher jni_abort_catcher;
+  EXPECT_EQ(env_->GetSuperclass(nullptr), nullptr);
+  jni_abort_catcher.Check("java_class == null");
 }
 
 TEST_F(JniInternalTest, IsAssignableFrom) {
   jclass object_class = env_->FindClass("java/lang/Object");
-  ASSERT_TRUE(object_class != NULL);
+  ASSERT_NE(object_class, nullptr);
   jclass string_class = env_->FindClass("java/lang/String");
-  ASSERT_TRUE(string_class != NULL);
+  ASSERT_NE(string_class, nullptr);
 
   ASSERT_TRUE(env_->IsAssignableFrom(object_class, string_class));
   ASSERT_FALSE(env_->IsAssignableFrom(string_class, object_class));
+
+  // Null as either class should fail.
+  CheckJniAbortCatcher jni_abort_catcher;
+  EXPECT_EQ(env_->IsAssignableFrom(nullptr, string_class), JNI_FALSE);
+  jni_abort_catcher.Check("java_class1 == null");
+  EXPECT_EQ(env_->IsAssignableFrom(object_class, nullptr), JNI_FALSE);
+  jni_abort_catcher.Check("java_class2 == null");
 }
 
 TEST_F(JniInternalTest, GetObjectRefType) {
   jclass local = env_->FindClass("java/lang/Object");
-  ASSERT_TRUE(local != NULL);
+  ASSERT_TRUE(local != nullptr);
   EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(local));
 
   jobject global = env_->NewGlobalRef(local);
@@ -604,33 +921,38 @@
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(invalid));
 
   // TODO: invoke a native method and test that its arguments are considered local references.
+
+  // Null as object should fail.
+  CheckJniAbortCatcher jni_abort_catcher;
+  EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(nullptr));
+  jni_abort_catcher.Check("java_object == null");
 }
 
 TEST_F(JniInternalTest, StaleWeakGlobal) {
   jclass java_lang_Class = env_->FindClass("java/lang/Class");
-  ASSERT_TRUE(java_lang_Class != NULL);
-  jobjectArray local_ref = env_->NewObjectArray(1, java_lang_Class, NULL);
-  ASSERT_TRUE(local_ref != NULL);
+  ASSERT_NE(java_lang_Class, nullptr);
+  jobjectArray local_ref = env_->NewObjectArray(1, java_lang_Class, nullptr);
+  ASSERT_NE(local_ref, nullptr);
   jweak weak_global = env_->NewWeakGlobalRef(local_ref);
-  ASSERT_TRUE(weak_global != NULL);
+  ASSERT_NE(weak_global, nullptr);
   env_->DeleteLocalRef(local_ref);
   Runtime::Current()->GetHeap()->CollectGarbage(false);  // GC should clear the weak global.
   jobject new_global_ref = env_->NewGlobalRef(weak_global);
-  EXPECT_TRUE(new_global_ref == NULL);
+  EXPECT_EQ(new_global_ref, nullptr);
   jobject new_local_ref = env_->NewLocalRef(weak_global);
-  EXPECT_TRUE(new_local_ref == NULL);
+  EXPECT_EQ(new_local_ref, nullptr);
 }
 
 TEST_F(JniInternalTest, NewStringUTF) {
-  EXPECT_TRUE(env_->NewStringUTF(NULL) == NULL);
+  EXPECT_EQ(env_->NewStringUTF(nullptr), nullptr);
   jstring s;
 
   s = env_->NewStringUTF("");
-  EXPECT_TRUE(s != NULL);
+  EXPECT_NE(s, nullptr);
   EXPECT_EQ(0, env_->GetStringLength(s));
   EXPECT_EQ(0, env_->GetStringUTFLength(s));
   s = env_->NewStringUTF("hello");
-  EXPECT_TRUE(s != NULL);
+  EXPECT_NE(s, nullptr);
   EXPECT_EQ(5, env_->GetStringLength(s));
   EXPECT_EQ(5, env_->GetStringUTFLength(s));
 
@@ -641,11 +963,11 @@
   jchar chars[] = { 'h', 'i' };
   jstring s;
   s = env_->NewString(chars, 0);
-  EXPECT_TRUE(s != NULL);
+  EXPECT_NE(s, nullptr);
   EXPECT_EQ(0, env_->GetStringLength(s));
   EXPECT_EQ(0, env_->GetStringUTFLength(s));
   s = env_->NewString(chars, 2);
-  EXPECT_TRUE(s != NULL);
+  EXPECT_NE(s, nullptr);
   EXPECT_EQ(2, env_->GetStringLength(s));
   EXPECT_EQ(2, env_->GetStringUTFLength(s));
 
@@ -654,7 +976,7 @@
 
 TEST_F(JniInternalTest, NewStringNullCharsZeroLength) {
   jstring s = env_->NewString(nullptr, 0);
-  EXPECT_TRUE(s != nullptr);
+  EXPECT_NE(s, nullptr);
   EXPECT_EQ(0, env_->GetStringLength(s));
 }
 
@@ -678,16 +1000,16 @@
 
 TEST_F(JniInternalTest, GetStringRegion_GetStringUTFRegion) {
   jstring s = env_->NewStringUTF("hello");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_TRUE(s != nullptr);
 
-  env_->GetStringRegion(s, -1, 0, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringRegion(s, 0, -1, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringRegion(s, 0, 10, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringRegion(s, 10, 1, NULL);
-  EXPECT_EXCEPTION(sioobe_);
+  env_->GetStringRegion(s, -1, 0, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringRegion(s, 0, -1, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringRegion(s, 0, 10, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringRegion(s, 10, 1, nullptr);
+  ExpectException(sioobe_);
 
   jchar chars[4] = { 'x', 'x', 'x', 'x' };
   env_->GetStringRegion(s, 1, 2, &chars[1]);
@@ -696,20 +1018,20 @@
   EXPECT_EQ('l', chars[2]);
   EXPECT_EQ('x', chars[3]);
 
-  // It's okay for the buffer to be NULL as long as the length is 0.
-  env_->GetStringRegion(s, 2, 0, NULL);
+  // It's okay for the buffer to be nullptr as long as the length is 0.
+  env_->GetStringRegion(s, 2, 0, nullptr);
   // Even if the offset is invalid...
-  env_->GetStringRegion(s, 123, 0, NULL);
-  EXPECT_EXCEPTION(sioobe_);
+  env_->GetStringRegion(s, 123, 0, nullptr);
+  ExpectException(sioobe_);
 
-  env_->GetStringUTFRegion(s, -1, 0, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringUTFRegion(s, 0, -1, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringUTFRegion(s, 0, 10, NULL);
-  EXPECT_EXCEPTION(sioobe_);
-  env_->GetStringUTFRegion(s, 10, 1, NULL);
-  EXPECT_EXCEPTION(sioobe_);
+  env_->GetStringUTFRegion(s, -1, 0, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringUTFRegion(s, 0, -1, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringUTFRegion(s, 0, 10, nullptr);
+  ExpectException(sioobe_);
+  env_->GetStringUTFRegion(s, 10, 1, nullptr);
+  ExpectException(sioobe_);
 
   char bytes[4] = { 'x', 'x', 'x', 'x' };
   env_->GetStringUTFRegion(s, 1, 2, &bytes[1]);
@@ -718,25 +1040,25 @@
   EXPECT_EQ('l', bytes[2]);
   EXPECT_EQ('x', bytes[3]);
 
-  // It's okay for the buffer to be NULL as long as the length is 0.
-  env_->GetStringUTFRegion(s, 2, 0, NULL);
+  // It's okay for the buffer to be nullptr as long as the length is 0.
+  env_->GetStringUTFRegion(s, 2, 0, nullptr);
   // Even if the offset is invalid...
-  env_->GetStringUTFRegion(s, 123, 0, NULL);
-  EXPECT_EXCEPTION(sioobe_);
+  env_->GetStringUTFRegion(s, 123, 0, nullptr);
+  ExpectException(sioobe_);
 }
 
 TEST_F(JniInternalTest, GetStringUTFChars_ReleaseStringUTFChars) {
-  // Passing in a NULL jstring is ignored normally, but caught by -Xcheck:jni.
+  // Passing in a nullptr jstring is ignored normally, but caught by -Xcheck:jni.
   {
     CheckJniAbortCatcher check_jni_abort_catcher;
-    EXPECT_TRUE(env_->GetStringUTFChars(NULL, NULL) == NULL);
+    EXPECT_EQ(env_->GetStringUTFChars(nullptr, nullptr), nullptr);
     check_jni_abort_catcher.Check("GetStringUTFChars received null jstring");
   }
 
   jstring s = env_->NewStringUTF("hello");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_TRUE(s != nullptr);
 
-  const char* utf = env_->GetStringUTFChars(s, NULL);
+  const char* utf = env_->GetStringUTFChars(s, nullptr);
   EXPECT_STREQ("hello", utf);
   env_->ReleaseStringUTFChars(s, utf);
 
@@ -749,10 +1071,10 @@
 
 TEST_F(JniInternalTest, GetStringChars_ReleaseStringChars) {
   jstring s = env_->NewStringUTF("hello");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_TRUE(s != nullptr);
 
   jchar expected[] = { 'h', 'e', 'l', 'l', 'o' };
-  const jchar* chars = env_->GetStringChars(s, NULL);
+  const jchar* chars = env_->GetStringChars(s, nullptr);
   EXPECT_EQ(expected[0], chars[0]);
   EXPECT_EQ(expected[1], chars[1]);
   EXPECT_EQ(expected[2], chars[2]);
@@ -773,10 +1095,10 @@
 
 TEST_F(JniInternalTest, GetStringCritical_ReleaseStringCritical) {
   jstring s = env_->NewStringUTF("hello");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_TRUE(s != nullptr);
 
   jchar expected[] = { 'h', 'e', 'l', 'l', 'o' };
-  const jchar* chars = env_->GetStringCritical(s, NULL);
+  const jchar* chars = env_->GetStringCritical(s, nullptr);
   EXPECT_EQ(expected[0], chars[0]);
   EXPECT_EQ(expected[1], chars[1]);
   EXPECT_EQ(expected[2], chars[2]);
@@ -798,45 +1120,72 @@
 
 TEST_F(JniInternalTest, GetObjectArrayElement_SetObjectArrayElement) {
   jclass java_lang_Class = env_->FindClass("java/lang/Class");
-  ASSERT_TRUE(java_lang_Class != NULL);
+  ASSERT_TRUE(java_lang_Class != nullptr);
 
-  jobjectArray array = env_->NewObjectArray(1, java_lang_Class, NULL);
-  EXPECT_TRUE(array != NULL);
-  EXPECT_TRUE(env_->GetObjectArrayElement(array, 0) == NULL);
+  jobjectArray array = env_->NewObjectArray(1, java_lang_Class, nullptr);
+  EXPECT_NE(array, nullptr);
+  EXPECT_EQ(env_->GetObjectArrayElement(array, 0), nullptr);
   env_->SetObjectArrayElement(array, 0, java_lang_Class);
   EXPECT_TRUE(env_->IsSameObject(env_->GetObjectArrayElement(array, 0), java_lang_Class));
 
   // ArrayIndexOutOfBounds for negative index.
   env_->SetObjectArrayElement(array, -1, java_lang_Class);
-  EXPECT_EXCEPTION(aioobe_);
+  ExpectException(aioobe_);
 
   // ArrayIndexOutOfBounds for too-large index.
   env_->SetObjectArrayElement(array, 1, java_lang_Class);
-  EXPECT_EXCEPTION(aioobe_);
+  ExpectException(aioobe_);
 
   // ArrayStoreException thrown for bad types.
   env_->SetObjectArrayElement(array, 0, env_->NewStringUTF("not a jclass!"));
-  EXPECT_EXCEPTION(ase_);
+  ExpectException(ase_);
+
+  // Null as array should fail.
+  CheckJniAbortCatcher jni_abort_catcher;
+  EXPECT_EQ(nullptr, env_->GetObjectArrayElement(nullptr, 0));
+  jni_abort_catcher.Check("java_array == null");
+  env_->SetObjectArrayElement(nullptr, 0, nullptr);
+  jni_abort_catcher.Check("java_array == null");
 }
 
 #define EXPECT_STATIC_PRIMITIVE_FIELD(type, field_name, sig, value1, value2) \
   do { \
     jfieldID fid = env_->GetStaticFieldID(c, field_name, sig); \
-    EXPECT_TRUE(fid != NULL); \
+    EXPECT_NE(fid, nullptr); \
     env_->SetStatic ## type ## Field(c, fid, value1); \
-    EXPECT_TRUE(value1 == env_->GetStatic ## type ## Field(c, fid)); \
+    EXPECT_EQ(value1, env_->GetStatic ## type ## Field(c, fid)); \
     env_->SetStatic ## type ## Field(c, fid, value2); \
-    EXPECT_TRUE(value2 == env_->GetStatic ## type ## Field(c, fid)); \
+    EXPECT_EQ(value2, env_->GetStatic ## type ## Field(c, fid)); \
+    \
+    CheckJniAbortCatcher jni_abort_catcher; \
+    env_->GetStatic ## type ## Field(nullptr, fid); \
+    jni_abort_catcher.Check("received null jclass"); \
+    env_->SetStatic ## type ## Field(nullptr, fid, value1); \
+    jni_abort_catcher.Check("received null jclass"); \
+    env_->GetStatic ## type ## Field(c, nullptr); \
+    jni_abort_catcher.Check("fid == null"); \
+    env_->SetStatic ## type ## Field(c, nullptr, value1); \
+    jni_abort_catcher.Check("fid == null"); \
   } while (false)
 
 #define EXPECT_PRIMITIVE_FIELD(instance, type, field_name, sig, value1, value2) \
   do { \
     jfieldID fid = env_->GetFieldID(c, field_name, sig); \
-    EXPECT_TRUE(fid != NULL); \
+    EXPECT_NE(fid, nullptr); \
     env_->Set ## type ## Field(instance, fid, value1); \
-    EXPECT_TRUE(value1 == env_->Get ## type ## Field(instance, fid)); \
+    EXPECT_EQ(value1, env_->Get ## type ## Field(instance, fid)); \
     env_->Set ## type ## Field(instance, fid, value2); \
-    EXPECT_TRUE(value2 == env_->Get ## type ## Field(instance, fid)); \
+    EXPECT_EQ(value2, env_->Get ## type ## Field(instance, fid)); \
+    \
+    CheckJniAbortCatcher jni_abort_catcher; \
+    env_->Get ## type ## Field(nullptr, fid); \
+    jni_abort_catcher.Check("obj == null"); \
+    env_->Set ## type ## Field(nullptr, fid, value1); \
+    jni_abort_catcher.Check("obj == null"); \
+    env_->Get ## type ## Field(instance, nullptr); \
+    jni_abort_catcher.Check("fid == null"); \
+    env_->Set ## type ## Field(instance, nullptr, value1); \
+    jni_abort_catcher.Check("fid == null"); \
   } while (false)
 
 
@@ -845,14 +1194,14 @@
   Thread::Current()->TransitionFromSuspendedToRunnable();
   LoadDex("AllFields");
   bool started = runtime_->Start();
-  CHECK(started);
+  ASSERT_TRUE(started);
 
   jclass c = env_->FindClass("AllFields");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   jobject o = env_->AllocObject(c);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
 
-  EXPECT_STATIC_PRIMITIVE_FIELD(Boolean, "sZ", "Z", true, false);
+  EXPECT_STATIC_PRIMITIVE_FIELD(Boolean, "sZ", "Z", JNI_TRUE, JNI_FALSE);
   EXPECT_STATIC_PRIMITIVE_FIELD(Byte, "sB", "B", 1, 2);
   EXPECT_STATIC_PRIMITIVE_FIELD(Char, "sC", "C", 'a', 'b');
   EXPECT_STATIC_PRIMITIVE_FIELD(Double, "sD", "D", 1.0, 2.0);
@@ -861,7 +1210,7 @@
   EXPECT_STATIC_PRIMITIVE_FIELD(Long, "sJ", "J", 1, 2);
   EXPECT_STATIC_PRIMITIVE_FIELD(Short, "sS", "S", 1, 2);
 
-  EXPECT_PRIMITIVE_FIELD(o, Boolean, "iZ", "Z", true, false);
+  EXPECT_PRIMITIVE_FIELD(o, Boolean, "iZ", "Z", JNI_TRUE, JNI_FALSE);
   EXPECT_PRIMITIVE_FIELD(o, Byte, "iB", "B", 1, 2);
   EXPECT_PRIMITIVE_FIELD(o, Char, "iC", "C", 'a', 'b');
   EXPECT_PRIMITIVE_FIELD(o, Double, "iD", "D", 1.0, 2.0);
@@ -878,19 +1227,19 @@
   runtime_->Start();
 
   jclass c = env_->FindClass("AllFields");
-  ASSERT_TRUE(c != NULL);
+  ASSERT_NE(c, nullptr);
   jobject o = env_->AllocObject(c);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
 
   jstring s1 = env_->NewStringUTF("hello");
-  ASSERT_TRUE(s1 != NULL);
+  ASSERT_NE(s1, nullptr);
   jstring s2 = env_->NewStringUTF("world");
-  ASSERT_TRUE(s2 != NULL);
+  ASSERT_NE(s2, nullptr);
 
   jfieldID s_fid = env_->GetStaticFieldID(c, "sObject", "Ljava/lang/Object;");
-  ASSERT_TRUE(s_fid != NULL);
+  ASSERT_NE(s_fid, nullptr);
   jfieldID i_fid = env_->GetFieldID(c, "iObject", "Ljava/lang/Object;");
-  ASSERT_TRUE(i_fid != NULL);
+  ASSERT_NE(i_fid, nullptr);
 
   env_->SetStaticObjectField(c, s_fid, s1);
   ASSERT_TRUE(env_->IsSameObject(s1, env_->GetStaticObjectField(c, s_fid)));
@@ -903,27 +1252,27 @@
   ASSERT_TRUE(env_->IsSameObject(s2, env_->GetObjectField(o, i_fid)));
 }
 
-TEST_F(JniInternalTest, NewLocalRef_NULL) {
-  EXPECT_TRUE(env_->NewLocalRef(NULL) == NULL);
+TEST_F(JniInternalTest, NewLocalRef_nullptr) {
+  EXPECT_EQ(env_->NewLocalRef(nullptr), nullptr);
 }
 
 TEST_F(JniInternalTest, NewLocalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
   jobject o = env_->NewLocalRef(s);
-  EXPECT_TRUE(o != NULL);
-  EXPECT_TRUE(o != s);
+  EXPECT_NE(o, nullptr);
+  EXPECT_NE(o, s);
 
   EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(o));
 }
 
-TEST_F(JniInternalTest, DeleteLocalRef_NULL) {
-  env_->DeleteLocalRef(NULL);
+TEST_F(JniInternalTest, DeleteLocalRef_nullptr) {
+  env_->DeleteLocalRef(nullptr);
 }
 
 TEST_F(JniInternalTest, DeleteLocalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
   env_->DeleteLocalRef(s);
 
   // Currently, deleting an already-deleted reference is just a CheckJNI warning.
@@ -937,9 +1286,9 @@
   }
 
   s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
   jobject o = env_->NewLocalRef(s);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
 
   env_->DeleteLocalRef(s);
   env_->DeleteLocalRef(o);
@@ -951,7 +1300,7 @@
   // Android historically treated it, and it's how the RI treats it. It's also the more useful
   // interpretation!
   ASSERT_EQ(JNI_OK, env_->PushLocalFrame(0));
-  env_->PopLocalFrame(NULL);
+  env_->PopLocalFrame(nullptr);
 
   // Negative capacities are not allowed.
   ASSERT_EQ(JNI_ERR, env_->PushLocalFrame(-1));
@@ -962,7 +1311,7 @@
 
 TEST_F(JniInternalTest, PushLocalFrame_PopLocalFrame) {
   jobject original = env_->NewStringUTF("");
-  ASSERT_TRUE(original != NULL);
+  ASSERT_NE(original, nullptr);
 
   jobject outer;
   jobject inner1, inner2;
@@ -988,7 +1337,7 @@
     // gets a new local reference...
     EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(inner2));
 
-    env_->PopLocalFrame(NULL);
+    env_->PopLocalFrame(nullptr);
   }
   EXPECT_EQ(JNILocalRefType, env_->GetObjectRefType(original));
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(outer));
@@ -996,30 +1345,30 @@
   EXPECT_EQ(JNIInvalidRefType, env_->GetObjectRefType(inner2));
 }
 
-TEST_F(JniInternalTest, NewGlobalRef_NULL) {
-  EXPECT_TRUE(env_->NewGlobalRef(NULL) == NULL);
+TEST_F(JniInternalTest, NewGlobalRef_nullptr) {
+  EXPECT_EQ(env_->NewGlobalRef(nullptr), nullptr);
 }
 
 TEST_F(JniInternalTest, NewGlobalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
   jobject o = env_->NewGlobalRef(s);
-  EXPECT_TRUE(o != NULL);
-  EXPECT_TRUE(o != s);
+  EXPECT_NE(o, nullptr);
+  EXPECT_NE(o, s);
 
-  // TODO: check that o is a global reference.
+  EXPECT_EQ(env_->GetObjectRefType(o), JNIGlobalRefType);
 }
 
-TEST_F(JniInternalTest, DeleteGlobalRef_NULL) {
-  env_->DeleteGlobalRef(NULL);
+TEST_F(JniInternalTest, DeleteGlobalRef_nullptr) {
+  env_->DeleteGlobalRef(nullptr);
 }
 
 TEST_F(JniInternalTest, DeleteGlobalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
 
   jobject o = env_->NewGlobalRef(s);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
   env_->DeleteGlobalRef(o);
 
   // Currently, deleting an already-deleted reference is just a CheckJNI warning.
@@ -1033,38 +1382,38 @@
   }
 
   jobject o1 = env_->NewGlobalRef(s);
-  ASSERT_TRUE(o1 != NULL);
+  ASSERT_NE(o1, nullptr);
   jobject o2 = env_->NewGlobalRef(s);
-  ASSERT_TRUE(o2 != NULL);
+  ASSERT_NE(o2, nullptr);
 
   env_->DeleteGlobalRef(o1);
   env_->DeleteGlobalRef(o2);
 }
 
-TEST_F(JniInternalTest, NewWeakGlobalRef_NULL) {
-  EXPECT_TRUE(env_->NewWeakGlobalRef(NULL) == NULL);
+TEST_F(JniInternalTest, NewWeakGlobalRef_nullptr) {
+  EXPECT_EQ(env_->NewWeakGlobalRef(nullptr),   nullptr);
 }
 
 TEST_F(JniInternalTest, NewWeakGlobalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
   jobject o = env_->NewWeakGlobalRef(s);
-  EXPECT_TRUE(o != NULL);
-  EXPECT_TRUE(o != s);
+  EXPECT_NE(o, nullptr);
+  EXPECT_NE(o, s);
 
-  // TODO: check that o is a weak global reference.
+  EXPECT_EQ(env_->GetObjectRefType(o), JNIWeakGlobalRefType);
 }
 
-TEST_F(JniInternalTest, DeleteWeakGlobalRef_NULL) {
-  env_->DeleteWeakGlobalRef(NULL);
+TEST_F(JniInternalTest, DeleteWeakGlobalRef_nullptr) {
+  env_->DeleteWeakGlobalRef(nullptr);
 }
 
 TEST_F(JniInternalTest, DeleteWeakGlobalRef) {
   jstring s = env_->NewStringUTF("");
-  ASSERT_TRUE(s != NULL);
+  ASSERT_NE(s, nullptr);
 
   jobject o = env_->NewWeakGlobalRef(s);
-  ASSERT_TRUE(o != NULL);
+  ASSERT_NE(o, nullptr);
   env_->DeleteWeakGlobalRef(o);
 
   // Currently, deleting an already-deleted reference is just a CheckJNI warning.
@@ -1078,21 +1427,21 @@
   }
 
   jobject o1 = env_->NewWeakGlobalRef(s);
-  ASSERT_TRUE(o1 != NULL);
+  ASSERT_NE(o1, nullptr);
   jobject o2 = env_->NewWeakGlobalRef(s);
-  ASSERT_TRUE(o2 != NULL);
+  ASSERT_NE(o2, nullptr);
 
   env_->DeleteWeakGlobalRef(o1);
   env_->DeleteWeakGlobalRef(o2);
 }
 
 TEST_F(JniInternalTest, Throw) {
-  EXPECT_EQ(JNI_ERR, env_->Throw(NULL));
+  EXPECT_EQ(JNI_ERR, env_->Throw(nullptr));
 
   jclass exception_class = env_->FindClass("java/lang/RuntimeException");
-  ASSERT_TRUE(exception_class != NULL);
+  ASSERT_TRUE(exception_class != nullptr);
   jthrowable exception = reinterpret_cast<jthrowable>(env_->AllocObject(exception_class));
-  ASSERT_TRUE(exception != NULL);
+  ASSERT_TRUE(exception != nullptr);
 
   EXPECT_EQ(JNI_OK, env_->Throw(exception));
   EXPECT_TRUE(env_->ExceptionCheck());
@@ -1102,10 +1451,10 @@
 }
 
 TEST_F(JniInternalTest, ThrowNew) {
-  EXPECT_EQ(JNI_ERR, env_->Throw(NULL));
+  EXPECT_EQ(JNI_ERR, env_->Throw(nullptr));
 
   jclass exception_class = env_->FindClass("java/lang/RuntimeException");
-  ASSERT_TRUE(exception_class != NULL);
+  ASSERT_TRUE(exception_class != nullptr);
 
   jthrowable thrown_exception;
 
@@ -1115,7 +1464,7 @@
   env_->ExceptionClear();
   EXPECT_TRUE(env_->IsInstanceOf(thrown_exception, exception_class));
 
-  EXPECT_EQ(JNI_OK, env_->ThrowNew(exception_class, NULL));
+  EXPECT_EQ(JNI_OK, env_->ThrowNew(exception_class, nullptr));
   EXPECT_TRUE(env_->ExceptionCheck());
   thrown_exception = env_->ExceptionOccurred();
   env_->ExceptionClear();
@@ -1141,26 +1490,26 @@
   ASSERT_TRUE(started);
 
   jclass buffer_class = env_->FindClass("java/nio/Buffer");
-  ASSERT_TRUE(buffer_class != NULL);
+  ASSERT_NE(buffer_class, nullptr);
 
   char bytes[1024];
   jobject buffer = env_->NewDirectByteBuffer(bytes, sizeof(bytes));
-  ASSERT_TRUE(buffer != NULL);
+  ASSERT_NE(buffer, nullptr);
   ASSERT_TRUE(env_->IsInstanceOf(buffer, buffer_class));
-  ASSERT_TRUE(env_->GetDirectBufferAddress(buffer) == bytes);
-  ASSERT_TRUE(env_->GetDirectBufferCapacity(buffer) == sizeof(bytes));
+  ASSERT_EQ(env_->GetDirectBufferAddress(buffer), bytes);
+  ASSERT_EQ(env_->GetDirectBufferCapacity(buffer), static_cast<jlong>(sizeof(bytes)));
 }
 
 TEST_F(JniInternalTest, MonitorEnterExit) {
-  // Create an object to torture
+  // Create an object to torture.
   jclass object_class = env_->FindClass("java/lang/Object");
-  ASSERT_TRUE(object_class != NULL);
+  ASSERT_NE(object_class, nullptr);
   jobject object = env_->AllocObject(object_class);
-  ASSERT_TRUE(object != NULL);
+  ASSERT_NE(object, nullptr);
 
   // Expected class of exceptions
   jclass imse_class = env_->FindClass("java/lang/IllegalMonitorStateException");
-  ASSERT_TRUE(imse_class != NULL);
+  ASSERT_NE(imse_class, nullptr);
 
   jthrowable thrown_exception;
 
@@ -1197,13 +1546,13 @@
   env_->ExceptionClear();
   EXPECT_TRUE(env_->IsInstanceOf(thrown_exception, imse_class));
 
-  // It's an error to call MonitorEnter or MonitorExit on NULL.
+  // It's an error to call MonitorEnter or MonitorExit on nullptr.
   {
     CheckJniAbortCatcher check_jni_abort_catcher;
-    env_->MonitorEnter(NULL);
+    env_->MonitorEnter(nullptr);
     check_jni_abort_catcher.Check("in call to MonitorEnter");
 
-    env_->MonitorExit(NULL);
+    env_->MonitorExit(nullptr);
     check_jni_abort_catcher.Check("in call to MonitorExit");
   }
 }
@@ -1215,7 +1564,7 @@
 
   jint err = vm_->DetachCurrentThread();
   EXPECT_EQ(JNI_ERR, err);
-  vm_->AttachCurrentThread(&env_, NULL);  // need attached thread for CommonRuntimeTest::TearDown
+  vm_->AttachCurrentThread(&env_, nullptr);  // need attached thread for CommonRuntimeTest::TearDown
 }
 
 }  // namespace art
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 238506e..1b8106e 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -155,14 +155,19 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static void SetArrayClass(Class* array_class) {
-    CHECK(array_class_ == NULL);
-    CHECK(array_class != NULL);
+    CHECK(array_class_ == nullptr);
+    CHECK(array_class != nullptr);
     array_class_ = array_class;
   }
 
+  static Class* GetArrayClass() {
+    DCHECK(array_class_ != nullptr);
+    return array_class_;
+  }
+
   static void ResetArrayClass() {
-    CHECK(array_class_ != NULL);
-    array_class_ = NULL;
+    CHECK(array_class_ != nullptr);
+    array_class_ = nullptr;
   }
 
   static void VisitRoots(RootCallback* callback, void* arg)
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 822e0fb..64edba8 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -642,21 +642,22 @@
   } else {
     ThreadList* thread_list = Runtime::Current()->GetThreadList();
     // Suspend the owner, inflate. First change to blocked and give up mutator_lock_.
-    ScopedThreadStateChange tsc(self, kBlocked);
     self->SetMonitorEnterObject(obj.Get());
-    if (lock_word == obj->GetLockWord(true)) {  // If lock word hasn't changed.
-      bool timed_out;
-      Thread* owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out);
-      if (owner != nullptr) {
-        // We succeeded in suspending the thread, check the lock's status didn't change.
-        lock_word = obj->GetLockWord(true);
-        if (lock_word.GetState() == LockWord::kThinLocked &&
-            lock_word.ThinLockOwner() == owner_thread_id) {
-          // Go ahead and inflate the lock.
-          Inflate(self, owner, obj.Get(), hash_code);
-        }
-        thread_list->Resume(owner, false);
+    bool timed_out;
+    Thread* owner;
+    {
+      ScopedThreadStateChange tsc(self, kBlocked);
+      owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out);
+    }
+    if (owner != nullptr) {
+      // We succeeded in suspending the thread, check the lock's status didn't change.
+      lock_word = obj->GetLockWord(true);
+      if (lock_word.GetState() == LockWord::kThinLocked &&
+          lock_word.ThinLockOwner() == owner_thread_id) {
+        // Go ahead and inflate the lock.
+        Inflate(self, owner, obj.Get(), hash_code);
       }
+      thread_list->Resume(owner, false);
     }
     self->SetMonitorEnterObject(nullptr);
   }
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 50a8e47..8d183da 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -66,10 +66,6 @@
     ThrowNullPointerException(NULL, "element class == null");
     return nullptr;
   }
-  if (UNLIKELY(element_class->IsPrimitiveVoid())) {
-    ThrowIllegalArgumentException(NULL, "Can't allocate an array of void");
-    return nullptr;
-  }
   Runtime* runtime = Runtime::Current();
   mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), element_class);
   if (UNLIKELY(array_class == nullptr)) {
@@ -93,10 +89,6 @@
     ThrowNullPointerException(NULL, "element class == null");
     return nullptr;
   }
-  if (UNLIKELY(element_class->IsPrimitiveVoid())) {
-    ThrowIllegalArgumentException(NULL, "Can't allocate an array of void");
-    return nullptr;
-  }
   Runtime* runtime = Runtime::Current();
   mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), element_class);
   if (UNLIKELY(array_class == nullptr)) {
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 623b0c6..55b6a27 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -689,9 +689,7 @@
 
   if (compiler_callbacks_ == nullptr && image_.empty()) {
     image_ += GetAndroidRoot();
-    image_ += "/framework/boot-";
-    image_ += GetInstructionSetString(image_isa_);
-    image_ += ".art";
+    image_ += "/framework/boot.art";
   }
   if (heap_growth_limit_ == 0) {
     heap_growth_limit_ = heap_maximum_size_;
diff --git a/test/Android.mk b/test/Android.mk
index aacd7b4..6e37af3 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -78,7 +78,7 @@
     LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
     LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
     include $(BUILD_JAVA_LIBRARY)
-    
+
     ART_TEST_TARGET_DEX_FILES += $$(LOCAL_INSTALLED_MODULE)
     ART_TEST_TARGET_DEX_FILES$(ART_PHONY_TEST_TARGET_SUFFIX) += $$(LOCAL_INSTALLED_MODULE)
 
@@ -88,7 +88,7 @@
       # TODO: make this a simple copy
 $(4)/$(1)-$(2).jar: $(3)/$(1)-$(2).jar $(4)
 	cp $$< $(4)/
-    endif    
+    endif
   endif
 
   ifeq ($(ART_BUILD_HOST),true)
@@ -108,6 +108,9 @@
 $(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-dex,art-test-dex,$(dir),$(ART_NATIVETEST_OUT),$(2ND_ART_NATIVETEST_OUT))))
 $(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call build-art-test-dex,oat-test-dex,$(dir),$(ART_TEST_OUT),$(2ND_ART_TEST_OUT))))
 
+# Used outside the art project to get a list of the current tests
+ART_TEST_DEX_MAKE_TARGETS := $(addprefix art-test-dex-, $(TEST_DEX_DIRECTORIES))
+
 # Rules to explicitly create 2nd-arch test directories, as we use a "cp" for them
 # instead of BUILD_JAVA_LIBRARY
 ifneq ($(2ND_ART_NATIVETEST_OUT),)
@@ -151,7 +154,7 @@
   $(call declare-test-art-oat-targets-impl,$(1),)
 
 $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).odex: $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar $(HOST_CORE_IMG_OUT) | $(DEX2OATD)
-	$(DEX2OATD) $(DEX2OAT_FLAGS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$(PWD)/$$< --oat-file=$(PWD)/$$@ --instruction-set=$(ART_HOST_ARCH) --host --android-root=$(HOST_OUT)
+	$(DEX2OATD) $(DEX2OAT_FLAGS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --boot-image=$(HOST_CORE_IMG_OUT) --dex-file=$$(realpath $$<) --oat-file=$$(realpath $(HOST_OUT_JAVA_LIBRARIES))/oat-test-dex-$(1).odex --instruction-set=$(ART_HOST_ARCH) --host --android-root=$(HOST_OUT)
 
 .PHONY: test-art-host-oat-default-$(1)
 test-art-host-oat-default-$(1): $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).odex test-art-host-dependencies
@@ -159,7 +162,7 @@
 	ANDROID_DATA=/tmp/android-data/test-art-host-oat-default-$(1) \
 	  ANDROID_ROOT=$(HOST_OUT) \
 	  LD_LIBRARY_PATH=$(HOST_OUT_SHARED_LIBRARIES) \
-	  $(HOST_OUT_EXECUTABLES)/dalvikvm $(DALVIKVM_FLAGS) -XXlib:libartd.so -Ximage:$(shell pwd)/$(HOST_CORE_IMG_OUT) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
+	  $(HOST_OUT_EXECUTABLES)/dalvikvm $(DALVIKVM_FLAGS) -XXlib:libartd.so -Ximage:$$(realpath $(HOST_CORE_IMG_OUT)) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
           && echo test-art-host-oat-default-$(1) PASSED || (echo test-art-host-oat-default-$(1) FAILED && exit 1)
 	$(hide) rm -r /tmp/android-data/test-art-host-oat-default-$(1)
 
@@ -169,7 +172,7 @@
 	ANDROID_DATA=/tmp/android-data/test-art-host-oat-interpreter-$(1) \
 	  ANDROID_ROOT=$(HOST_OUT) \
 	  LD_LIBRARY_PATH=$(HOST_OUT_SHARED_LIBRARIES) \
-	  $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd.so -Ximage:$(shell pwd)/$(HOST_CORE_IMG_OUT) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
+	  $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd.so -Ximage:$$(realpath $(HOST_CORE_IMG_OUT)) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
           && echo test-art-host-oat-interpreter-$(1) PASSED || (echo test-art-host-oat-interpreter-$(1) FAILED && exit 1)
 	$(hide) rm -r /tmp/android-data/test-art-host-oat-interpreter-$(1)