Run time illegal access checks on static and direct methods

Fixes test 075.

Change-Id: I28b20451dcae8000dc0e2cb9068dfa5166659d43
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 853c4d2..dd8a483 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -60,7 +60,7 @@
 	dalvik/libdex
 
 art_cflags := \
-	-O2 \
+	-O0 \
 	-ggdb3 \
 	-Wall \
 	-Werror \
@@ -127,6 +127,7 @@
 	src/calling_convention_arm.cc \
 	src/calling_convention_x86.cc \
 	src/card_table.cc \
+	src/constants.cc \
 	src/context.cc \
 	src/context_arm.cc.arm \
 	src/context_x86.cc \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index d8bf664..449bb53 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -83,7 +83,7 @@
                             const StringPiece& signature) {
   ClassHelper kh(c);
   std::ostringstream msg;
-  msg << "no " << (is_direct ? "direct" : "virtual") << " method " << name << "." << signature
+  msg << "no " << (is_direct ? "direct" : "virtual") << " method " << name << signature
       << " in class " << kh.GetDescriptor() << " or its superclasses";
   std::string location(kh.GetLocation());
   if (!location.empty()) {
diff --git a/src/compiler.cc b/src/compiler.cc
index 35108bb..08c6cc4 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -71,19 +71,36 @@
   LOG(INFO) << Percentage(x, y) << "% of " << str << " for " << (x + y) << " cases";
 }
 
-void AOTCompilationStats::Dump() {
-  DumpStat(types_in_dex_cache_, types_not_in_dex_cache_, "types known to be in dex cache");
-  DumpStat(strings_in_dex_cache_, strings_not_in_dex_cache_, "strings known to be in dex cache");
-  DumpStat(resolved_types_, unresolved_types_, "types resolved");
-  DumpStat(resolved_instance_fields_, unresolved_instance_fields_, "instance fields resolved");
-  DumpStat(resolved_local_static_fields_ + resolved_static_fields_, unresolved_static_fields_,
-           "static fields resolved");
-  DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
-           "static fields local to a class");
-  DumpStat(resolved_virtual_methods_, unresolved_virtual_methods_, "resolved virtual methods");
-  DumpStat(resolved_super_methods_, unresolved_super_methods_, "resolved super-class methods");
-  DumpStat(resolved_interface_methods_, unresolved_interface_methods_, "resolved interface methods");
-}
+class AOTCompilationStats {
+ public:
+  AOTCompilationStats() : stats_lock_("AOT compilation statistics lock"),
+     types_in_dex_cache_(0), types_not_in_dex_cache_(0),
+     strings_in_dex_cache_(0), strings_not_in_dex_cache_(0),
+     resolved_types_(0), unresolved_types_(0),
+     resolved_instance_fields_(0), unresolved_instance_fields_(0),
+     resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0) {
+    for (size_t i = 0; i < kMaxInvokeType; i++) {
+      resolved_methods_[i] = 0;
+      unresolved_methods_[i] = 0;
+    }
+  }
+
+  void Dump() {
+    DumpStat(types_in_dex_cache_, types_not_in_dex_cache_, "types known to be in dex cache");
+    DumpStat(strings_in_dex_cache_, strings_not_in_dex_cache_, "strings known to be in dex cache");
+    DumpStat(resolved_types_, unresolved_types_, "types resolved");
+    DumpStat(resolved_instance_fields_, unresolved_instance_fields_, "instance fields resolved");
+    DumpStat(resolved_local_static_fields_ + resolved_static_fields_, unresolved_static_fields_,
+             "static fields resolved");
+    DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
+             "static fields local to a class");
+
+    for (size_t i = 0; i < kMaxInvokeType; i++) {
+      std::ostringstream oss;
+      oss << "resolved " << static_cast<InvokeType>(i) << " methods";
+      DumpStat(resolved_methods_[i], unresolved_methods_[i], oss.str().c_str());
+    }
+  }
 
 // Allow lossy statistics in non-debug builds
 #ifndef NDEBUG
@@ -92,82 +109,97 @@
 #define STATS_LOCK()
 #endif
 
-void AOTCompilationStats::TypeInDexCache() {
-  STATS_LOCK();
-  types_in_dex_cache_++;
-}
-
-void AOTCompilationStats::TypeNotInDexCache() {
-  STATS_LOCK();
-  types_not_in_dex_cache_++;
-}
-
-void AOTCompilationStats::StringInDexCache() {
-  STATS_LOCK();
-  strings_in_dex_cache_++;
-}
-
-void AOTCompilationStats::StringNotInDexCache() {
-  STATS_LOCK();
-  strings_not_in_dex_cache_++;
-}
-
-void AOTCompilationStats::TypeDoesntNeedAccessCheck() {
-  STATS_LOCK();
-  resolved_types_++;
-}
-
-void AOTCompilationStats::TypeNeedsAccessCheck() {
-  STATS_LOCK();
-  unresolved_types_++;
-}
-
-void AOTCompilationStats::ResolvedInstanceField() {
-  STATS_LOCK();
-  resolved_instance_fields_++;
-}
-
-void AOTCompilationStats::UnresolvedInstanceField(){
-  STATS_LOCK();
-  unresolved_instance_fields_++;
-}
-
-void AOTCompilationStats::ResolvedLocalStaticField() {
-  STATS_LOCK();
-  resolved_local_static_fields_++;
-}
-
-void AOTCompilationStats::ResolvedStaticField() {
-  STATS_LOCK();
-  resolved_static_fields_++;
-}
-
-void AOTCompilationStats::UnresolvedStaticField() {
-  STATS_LOCK();
-  unresolved_static_fields_++;
-}
-
-void AOTCompilationStats::ResolvedMethod(bool is_interface, bool is_super) {
-  STATS_LOCK();
-  if (is_interface) {
-    resolved_interface_methods_++;
-  } else if (is_super) {
-    resolved_super_methods_++;
-  } else {
-    resolved_virtual_methods_++;
+  void TypeInDexCache() {
+    STATS_LOCK();
+    types_in_dex_cache_++;
   }
-}
 
-void AOTCompilationStats::UnresolvedMethod(bool is_interface, bool is_super) {
-  STATS_LOCK();
-  if (is_interface) {
-    unresolved_interface_methods_++;
-  } else if (is_super) {
-    unresolved_super_methods_++;
-  } else {
-    unresolved_virtual_methods_++;
+  void TypeNotInDexCache() {
+    STATS_LOCK();
+    types_not_in_dex_cache_++;
   }
-}
+
+  void StringInDexCache() {
+    STATS_LOCK();
+    strings_in_dex_cache_++;
+  }
+
+  void StringNotInDexCache() {
+    STATS_LOCK();
+    strings_not_in_dex_cache_++;
+  }
+
+  void TypeDoesntNeedAccessCheck() {
+    STATS_LOCK();
+    resolved_types_++;
+  }
+
+  void TypeNeedsAccessCheck() {
+    STATS_LOCK();
+    unresolved_types_++;
+  }
+
+  void ResolvedInstanceField() {
+    STATS_LOCK();
+    resolved_instance_fields_++;
+  }
+
+  void UnresolvedInstanceField(){
+    STATS_LOCK();
+    unresolved_instance_fields_++;
+  }
+
+  void ResolvedLocalStaticField() {
+    STATS_LOCK();
+    resolved_local_static_fields_++;
+  }
+
+  void ResolvedStaticField() {
+    STATS_LOCK();
+    resolved_static_fields_++;
+  }
+
+  void UnresolvedStaticField() {
+    STATS_LOCK();
+    unresolved_static_fields_++;
+  }
+
+  void ResolvedMethod(InvokeType type) {
+    DCHECK_LE(type, kMaxInvokeType);
+    STATS_LOCK();
+    resolved_methods_[type]++;
+  }
+
+  void UnresolvedMethod(InvokeType type) {
+    DCHECK_LE(type, kMaxInvokeType);
+    STATS_LOCK();
+    unresolved_methods_[type]++;
+  }
+
+ private:
+  Mutex stats_lock_;
+
+  size_t types_in_dex_cache_;
+  size_t types_not_in_dex_cache_;
+
+  size_t strings_in_dex_cache_;
+  size_t strings_not_in_dex_cache_;
+
+  size_t resolved_types_;
+  size_t unresolved_types_;
+
+  size_t resolved_instance_fields_;
+  size_t unresolved_instance_fields_;
+
+  size_t resolved_local_static_fields_;
+  size_t resolved_static_fields_;
+  size_t unresolved_static_fields_;
+
+  size_t resolved_methods_[kMaxInvokeType + 1];
+  size_t unresolved_methods_[kMaxInvokeType + 1];
+
+  DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);;
+};
 
 Compiler::Compiler(InstructionSet instruction_set, bool image, size_t thread_count,
                    const std::set<std::string>* image_classes)
@@ -178,6 +210,7 @@
       compiled_invoke_stubs_lock_("compiled invoke stubs lock"),
       image_(image),
       thread_count_(thread_count),
+      stats_(new AOTCompilationStats),
       image_classes_(image_classes)
 #if defined(ART_USE_LLVM_COMPILER)
       ,
@@ -257,7 +290,7 @@
     timings.Dump();
   }
 
-  stats_.Dump();
+  stats_->Dump();
 }
 
 void Compiler::CompileOne(const Method* method) {
@@ -320,19 +353,19 @@
 bool Compiler::CanAssumeTypeIsPresentInDexCache(const DexCache* dex_cache,
                                                 uint32_t type_idx) {
   if (!IsImage()) {
-    stats_.TypeNotInDexCache();
+    stats_->TypeNotInDexCache();
     return false;
   }
   Class* resolved_class = dex_cache->GetResolvedType(type_idx);
   if (resolved_class == NULL) {
-    stats_.TypeNotInDexCache();
+    stats_->TypeNotInDexCache();
     return false;
   }
   bool result = IsImageClass(ClassHelper(resolved_class).GetDescriptor());
   if (result) {
-    stats_.TypeInDexCache();
+    stats_->TypeInDexCache();
   } else {
-    stats_.TypeNotInDexCache();
+    stats_->TypeNotInDexCache();
   }
   return result;
 }
@@ -346,9 +379,9 @@
   // image classes then we can assume the string is present in the dex cache if it is there now
   bool result = IsImage() && image_classes_ == NULL && dex_cache->GetResolvedString(string_idx) != NULL;
   if (result) {
-    stats_.StringInDexCache();
+    stats_->StringInDexCache();
   } else {
-    stats_.StringNotInDexCache();
+    stats_->StringNotInDexCache();
   }
   return result;
 }
@@ -358,22 +391,22 @@
   // Get type from dex cache assuming it was populated by the verifier
   Class* resolved_class = dex_cache->GetResolvedType(type_idx);
   if (resolved_class == NULL) {
-    stats_.TypeNeedsAccessCheck();
+    stats_->TypeNeedsAccessCheck();
     return false;  // Unknown class needs access checks.
   }
   const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
   Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
   if (referrer_class == NULL) {
-    stats_.TypeNeedsAccessCheck();
+    stats_->TypeNeedsAccessCheck();
     return false;  // Incomplete referrer knowledge needs access check.
   }
   // Perform access check, will return true if access is ok or false if we're going to have to
   // check this at runtime (for example for class loaders).
   bool result = referrer_class->CanAccess(resolved_class);
   if (result) {
-    stats_.TypeDoesntNeedAccessCheck();
+    stats_->TypeDoesntNeedAccessCheck();
   } else {
-    stats_.TypeNeedsAccessCheck();
+    stats_->TypeNeedsAccessCheck();
   }
   return result;
 }
@@ -385,22 +418,22 @@
   // Get type from dex cache assuming it was populated by the verifier.
   Class* resolved_class = dex_cache->GetResolvedType(type_idx);
   if (resolved_class == NULL) {
-    stats_.TypeNeedsAccessCheck();
+    stats_->TypeNeedsAccessCheck();
     return false;  // Unknown class needs access checks.
   }
   const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
   Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
   if (referrer_class == NULL) {
-    stats_.TypeNeedsAccessCheck();
+    stats_->TypeNeedsAccessCheck();
     return false;  // Incomplete referrer knowledge needs access check.
   }
   // Perform access and instantiable checks, will return true if access is ok or false if we're
   // going to have to check this at runtime (for example for class loaders).
   bool result = referrer_class->CanAccess(resolved_class) && resolved_class->IsInstantiable();
   if (result) {
-    stats_.TypeDoesntNeedAccessCheck();
+    stats_->TypeDoesntNeedAccessCheck();
   } else {
-    stats_.TypeNeedsAccessCheck();
+    stats_->TypeNeedsAccessCheck();
   }
   return result;
 }
@@ -439,7 +472,7 @@
                                         resolved_field->GetAccessFlags())) {
       field_offset = resolved_field->GetOffset().Int32Value();
       is_volatile = resolved_field->IsVolatile();
-      stats_.ResolvedInstanceField();
+      stats_->ResolvedInstanceField();
       return true;  // Fast path.
     }
   }
@@ -448,7 +481,7 @@
   if (thread->IsExceptionPending()) {
       thread->ClearException();
   }
-  stats_.UnresolvedInstanceField();
+  stats_->UnresolvedInstanceField();
   return false;  // Incomplete knowledge needs slow path.
 }
 
@@ -470,7 +503,7 @@
         is_referrers_class = true;  // implies no worrying about class initialization
         field_offset = resolved_field->GetOffset().Int32Value();
         is_volatile = resolved_field->IsVolatile();
-        stats_.ResolvedLocalStaticField();
+        stats_->ResolvedLocalStaticField();
         return true;  // fast path
       } else {
         Class* fields_class = resolved_field->GetDeclaringClass();
@@ -487,7 +520,7 @@
             ssb_index = fields_class->GetDexTypeIndex();
             field_offset = resolved_field->GetOffset().Int32Value();
             is_volatile = resolved_field->IsVolatile();
-            stats_.ResolvedStaticField();
+            stats_->ResolvedStaticField();
             return true;
           }
           // Search dex file for localized ssb index
@@ -502,7 +535,7 @@
               ssb_index = cUnit->dex_file->GetIndexForTypeId(*type_id);
               field_offset = resolved_field->GetOffset().Int32Value();
               is_volatile = resolved_field->IsVolatile();
-              stats_.ResolvedStaticField();
+              stats_->ResolvedStaticField();
               return true;
             }
           }
@@ -515,12 +548,11 @@
   if (thread->IsExceptionPending()) {
       thread->ClearException();
   }
-  stats_.UnresolvedStaticField();
+  stats_->UnresolvedStaticField();
   return false;  // Incomplete knowledge needs slow path.
 }
 
-bool Compiler::ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit,
-                                 bool is_interface, bool is_super,
+bool Compiler::ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit, InvokeType type,
                                  int& vtable_idx) {
   vtable_idx = -1;
   Method* resolved_method = ComputeReferrerMethod(cUnit, method_idx);
@@ -545,15 +577,15 @@
           referrer_class->CanAccessMember(methods_class,
                                           resolved_method->GetAccessFlags())) {
         vtable_idx = resolved_method->GetMethodIndex();
-        if (is_interface || !is_super) {
-          // nothing left to do for virtual/interface dispatch
-          stats_.ResolvedMethod(is_interface, is_super);
+        if (type != kSuper) {
+          // nothing left to do for static/direct/virtual/interface dispatch
+          stats_->ResolvedMethod(type);
           return true;
         } else {
           // ensure the vtable index will be correct to dispatch in the vtable of the super class
           if (referrer_class->IsSubClass(methods_class) &&
               vtable_idx < methods_class->GetVTable()->GetLength()) {
-            stats_.ResolvedMethod(is_interface, is_super);
+            stats_->ResolvedMethod(type);
             return true;
           }
         }
@@ -565,7 +597,7 @@
   if (thread->IsExceptionPending()) {
       thread->ClearException();
   }
-  stats_.UnresolvedMethod(is_interface, is_super);
+  stats_->UnresolvedMethod(type);
   return false;  // Incomplete knowledge needs slow path.
 }
 
diff --git a/src/compiler.h b/src/compiler.h
index 186d433..0c6b2bf 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -37,72 +37,11 @@
 
 namespace art {
 
+class AOTCompilationStats;
 class Context;
 class TimingLogger;
 typedef struct CompilationUnit CompilationUnit;
-class AOTCompilationStats {
- public:
-  AOTCompilationStats() : stats_lock_("AOT compilation statistics lock"),
-     types_in_dex_cache_(0), types_not_in_dex_cache_(0),
-     strings_in_dex_cache_(0), strings_not_in_dex_cache_(0),
-     resolved_types_(0), unresolved_types_(0),
-     resolved_instance_fields_(0), unresolved_instance_fields_(0),
-     resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0),
-     resolved_virtual_methods_(0), unresolved_virtual_methods_(0),
-     resolved_super_methods_(0), unresolved_super_methods_(0),
-     resolved_interface_methods_(0), unresolved_interface_methods_(0) {}
 
-  void Dump();
-
-  void TypeInDexCache();
-  void TypeNotInDexCache();
-
-  void StringInDexCache();
-  void StringNotInDexCache();
-
-  void TypeDoesntNeedAccessCheck();
-  void TypeNeedsAccessCheck();
-
-  void ResolvedInstanceField();
-  void UnresolvedInstanceField();
-
-  void ResolvedLocalStaticField();
-  void ResolvedStaticField();
-  void UnresolvedStaticField();
-
-  void ResolvedMethod(bool is_interface, bool is_super);
-  void UnresolvedMethod(bool is_interface, bool is_super);
-
- private:
-  Mutex stats_lock_;
-
-  size_t types_in_dex_cache_;
-  size_t types_not_in_dex_cache_;
-
-  size_t strings_in_dex_cache_;
-  size_t strings_not_in_dex_cache_;
-
-  size_t resolved_types_;
-  size_t unresolved_types_;
-
-  size_t resolved_instance_fields_;
-  size_t unresolved_instance_fields_;
-
-  size_t resolved_local_static_fields_;
-  size_t resolved_static_fields_;
-  size_t unresolved_static_fields_;
-
-  size_t resolved_virtual_methods_;
-  size_t unresolved_virtual_methods_;
-
-  size_t resolved_super_methods_;
-  size_t unresolved_super_methods_;
-
-  size_t resolved_interface_methods_;
-  size_t unresolved_interface_methods_;
-
-  DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);;
-};
 
 class Compiler {
  public:
@@ -177,8 +116,8 @@
                               bool& is_referrers_class, bool& is_volatile);
 
   // Can we fastpath a interface, super class or virtual method call? Computes method's vtable index
-  bool ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit, bool is_interface,
-                         bool is_super, int& vtable_idx);
+  bool ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit, InvokeType type,
+                         int& vtable_idx);
 
 #if defined(ART_USE_LLVM_COMPILER)
   compiler_llvm::CompilerLLVM* GetCompilerLLVM() const {
@@ -250,11 +189,10 @@
   size_t thread_count_;
   uint64_t start_ns_;
 
-  AOTCompilationStats stats_;
+  UniquePtr<AOTCompilationStats> stats_;
 
   const std::set<std::string>* image_classes_;
 
-
 #if defined(ART_USE_LLVM_COMPILER)
   UniquePtr<compiler_llvm::CompilerLLVM> compiler_llvm_;
 #endif
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index cbf5867..a1793e0 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -469,29 +469,14 @@
     return state + 1;
 }
 
-STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir,
-                                  bool accessCheck, bool isInterface,
-                                  bool isSuper, int state, uint32_t dexIdx,
-                                  uint32_t methodIdx)
+STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, int trampoline,
+                            int state, uint32_t dexIdx, uint32_t methodIdx)
 {
     /*
      * This handles the case in which the base method is not fully
      * resolved at compile time, we bail to a runtime helper.
      */
     if (state == 0) {
-        int trampoline;
-        if (!accessCheck) {
-          DCHECK(isInterface);
-          trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
-        } else {
-          if (isInterface) {
-            trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
-          } else if (isSuper) {
-            trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
-          } else {
-            trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
-          }
-        }
         // Load trampoline target
         loadWordDisp(cUnit, rSELF, trampoline, rLR);
         // Load r0 with method index
@@ -501,18 +486,32 @@
     return -1;
 }
 
+STATIC int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                                int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                                int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
 STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
                                int state, uint32_t dexIdx, uint32_t methodIdx)
 {
-  return nextInvokeInsnSP(cUnit, mir, true, false, true, state, dexIdx,
-                          methodIdx);
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
 }
 
 STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
                            int state, uint32_t dexIdx, uint32_t methodIdx)
 {
-  return nextInvokeInsnSP(cUnit, mir, true, false, false, state, dexIdx,
-                          methodIdx);
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
 }
 
 /*
@@ -522,7 +521,8 @@
 STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
                                  int state, uint32_t dexIdx, uint32_t unused)
 {
-  return nextInvokeInsnSP(cUnit, mir, false, true, false, state, dexIdx, 0);
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
 }
 
 STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
@@ -530,7 +530,8 @@
                                                 uint32_t dexIdx,
                                                 uint32_t unused)
 {
-  return nextInvokeInsnSP(cUnit, mir, true, true, false, state, dexIdx, 0);
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
 }
 
 STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
@@ -569,9 +570,9 @@
  */
 STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
                                 DecodedInstruction* dInsn, int callState,
-                                ArmLIR** pcrLabel, bool isRange,
-                                NextCallInsn nextCallInsn, uint32_t dexIdx,
-                                uint32_t methodIdx, bool skipThis)
+                                ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
+                                uint32_t dexIdx, uint32_t methodIdx,
+                                bool skipThis)
 {
     RegLocation rlArg;
 
@@ -676,7 +677,7 @@
     // If we can treat it as non-range (Jumbo ops will use range form)
     if (numArgs <= 5)
         return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
-                                    true, nextCallInsn, dexIdx, methodIdx,
+                                    nextCallInsn, dexIdx, methodIdx,
                                     skipThis);
     /*
      * Make sure range list doesn't span the break between in normal
@@ -766,45 +767,13 @@
     branchOver->generic.target = (LIR*)target;
 }
 
-STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
-                                  bool direct, bool range)
+STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir,
+                      InvokeType type, bool isRange)
 {
     DecodedInstruction* dInsn = &mir->dalvikInsn;
     int callState = 0;
     ArmLIR* nullCk;
-    ArmLIR** pNullCk = direct ? &nullCk : NULL;
-    NextCallInsn nextCallInsn = nextSDCallInsn;
-    oatFlushAllRegs(cUnit);    /* Everything to home location */
-
-    // Explicit register usage
-    oatLockCallTemps(cUnit);
-
-    uint32_t dexMethodIdx = mir->dalvikInsn.vB;
-
-    if (range) {
-        callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
-                                       nextCallInsn, dexMethodIdx, 0, false);
-    } else {
-        callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
-                                         false, nextCallInsn, dexMethodIdx,
-                                         0, false);
-    }
-    // Finish up any of the call sequence not interleaved in arg loading
-    while (callState >= 0) {
-        callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx, 0);
-    }
-    if (DISPLAY_MISSING_TARGETS) {
-        genShowTarget(cUnit);
-    }
-    opReg(cUnit, kOpBlx, rLR);
-    oatClobberCalleeSave(cUnit);
-}
-
-STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir, bool isInterface,
-                      bool isSuper, bool isRange)
-{
-    DecodedInstruction* dInsn = &mir->dalvikInsn;
-    int callState = 0;
+    ArmLIR** pNullCk = NULL;
     NextCallInsn nextCallInsn;
     oatFlushAllRegs(cUnit);    /* Everything to home location */
     // Explicit register usage
@@ -812,25 +781,38 @@
 
     uint32_t dexMethodIdx = dInsn->vB;
     int vtableIdx;
+    bool skipThis;
     bool fastPath =
-        cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit,
-                                           isInterface, isSuper, vtableIdx)
+        cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit, type,
+                                           vtableIdx)
         && !SLOW_INVOKE_PATH;
-    if (isInterface) {
+    if (type == kInterface) {
       nextCallInsn = fastPath ? nextInterfaceCallInsn
                               : nextInterfaceCallInsnWithAccessCheck;
-    } else if (isSuper) {
+      skipThis = false;
+    } else if (type == kDirect) {
+      if (fastPath) {
+        pNullCk = &nullCk;
+      }
+      nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP;
+      skipThis = false;
+    } else if (type == kStatic) {
+      nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP;
+      skipThis = false;
+    } else if (type == kSuper) {
       nextCallInsn = fastPath ? nextSuperCallInsn : nextSuperCallInsnSP;
+      skipThis = fastPath;
     } else {
+      DCHECK_EQ(type, kVirtual);
       nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
+      skipThis = fastPath;
     }
-    bool skipThis = fastPath && !isInterface;
     if (!isRange) {
-        callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
-                                         false, nextCallInsn, dexMethodIdx,
+        callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
+                                         nextCallInsn, dexMethodIdx,
                                          vtableIdx, skipThis);
     } else {
-        callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
+        callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
                                        nextCallInsn, dexMethodIdx, vtableIdx,
                                        skipThis);
     }
@@ -1296,48 +1278,38 @@
             break;
 
         case OP_INVOKE_STATIC_RANGE:
-            genInvokeStaticDirect(cUnit, mir, false /*direct*/,
-                                  true /*range*/);
+            genInvoke(cUnit, mir, kStatic, true /*range*/);
             break;
         case OP_INVOKE_STATIC:
-            genInvokeStaticDirect(cUnit, mir, false /*direct*/,
-                                  false /*range*/);
+            genInvoke(cUnit, mir, kStatic, false /*range*/);
             break;
 
         case OP_INVOKE_DIRECT:
-            genInvokeStaticDirect(cUnit, mir, true /*direct*/,
-                                  false /*range*/);
+            genInvoke(cUnit, mir, kDirect, false /*range*/);
             break;
         case OP_INVOKE_DIRECT_RANGE:
-            genInvokeStaticDirect(cUnit, mir, true /*direct*/,
-                                  true /*range*/);
+            genInvoke(cUnit, mir, kDirect, true /*range*/);
             break;
 
         case OP_INVOKE_VIRTUAL:
-            genInvoke(cUnit, mir, false /*interface*/, false /*super*/,
-                      false /*range*/);
+            genInvoke(cUnit, mir, kVirtual, false /*range*/);
             break;
         case OP_INVOKE_VIRTUAL_RANGE:
-            genInvoke(cUnit, mir, false /*interface*/, false /*super*/,
-                      true /*range*/);
+            genInvoke(cUnit, mir, kVirtual, true /*range*/);
             break;
 
         case OP_INVOKE_SUPER:
-            genInvoke(cUnit, mir, false /*interface*/, true /*super*/,
-                      false /*range*/);
+            genInvoke(cUnit, mir, kSuper, false /*range*/);
             break;
         case OP_INVOKE_SUPER_RANGE:
-            genInvoke(cUnit, mir, false /*interface*/, true /*super*/,
-                      true /*range*/);
+            genInvoke(cUnit, mir, kSuper, true /*range*/);
             break;
 
         case OP_INVOKE_INTERFACE:
-            genInvoke(cUnit, mir, true /*interface*/, false /*super*/,
-                      false /*range*/);
+            genInvoke(cUnit, mir, kInterface, false /*range*/);
             break;
         case OP_INVOKE_INTERFACE_RANGE:
-            genInvoke(cUnit, mir, true /*interface*/, false /*super*/,
-                      true /*range*/);
+            genInvoke(cUnit, mir, kInterface, true /*range*/);
             break;
 
         case OP_NEG_INT:
diff --git a/src/constants.cc b/src/constants.cc
new file mode 100644
index 0000000..c32f136
--- /dev/null
+++ b/src/constants.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * 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 "constants.h"
+
+namespace art {
+
+std::ostream& operator<<(std::ostream& os, const InvokeType& rhs) {
+  switch (rhs) {
+    case kStatic: os << "static"; break;
+    case kDirect: os << "direct"; break;
+    case kVirtual: os << "virtual"; break;
+    case kSuper: os << "super"; break;
+    case kInterface: os << "interface"; break;
+    default: os << "InvokeType[" << static_cast<int>(rhs) << "]"; break;
+  }
+  return os;
+}
+
+}  // namespace art
diff --git a/src/constants.h b/src/constants.h
index 778d646..5c1323f 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -17,6 +17,8 @@
 #ifndef ART_SRC_CONSTANTS_H_
 #define ART_SRC_CONSTANTS_H_
 
+#include <iosfwd>
+
 namespace art {
 
 enum InstructionSet {
@@ -26,6 +28,13 @@
   kX86
 };
 
+enum InvokeType {
+  kStatic, kDirect, kVirtual, kSuper, kInterface,
+  kMaxInvokeType = kInterface
+};
+
+std::ostream& operator<<(std::ostream& os, const InvokeType& rhs);
+
 }  // namespace art
 
 #include "constants_x86.h"
diff --git a/src/object.cc b/src/object.cc
index 27b85b0..3aba5c8 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1506,7 +1506,7 @@
     }
   }
   Throwable* cause = GetFieldObject<Throwable*>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), false);
-  if (cause != NULL) {
+  if (cause != NULL && cause != this) {  // Constructor makes cause == this by default.
     result += "Caused by: ";
     result += cause->Dump();
   }
diff --git a/src/object.h b/src/object.h
index a7e012f..f9c8eb7 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1016,7 +1016,12 @@
 
 template<class T>
 ObjectArray<T>* ObjectArray<T>::Alloc(Class* object_array_class, int32_t length) {
-  return Array::Alloc(object_array_class, length, sizeof(uint32_t))->AsObjectArray<T>();
+  Array* array = Array::Alloc(object_array_class, length, sizeof(uint32_t));
+  if (UNLIKELY(array == NULL)) {
+    return NULL;
+  } else {
+    return array->AsObjectArray<T>();
+  }
 }
 
 template<class T>
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 670049a..f158680 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -45,13 +45,15 @@
 static void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self, Class* referrer,
                                                              Class* accessed, const Method* caller,
                                                              const Method* called,
-                                                             bool is_interface, bool is_super) {
+                                                             InvokeType type) {
+  std::ostringstream type_stream;
+  type_stream << type;
   self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
                            "illegal class access ('%s' -> '%s')"
                            "in attempt to invoke %s method '%s' from '%s'",
                            PrettyDescriptor(referrer).c_str(),
                            PrettyDescriptor(accessed).c_str(),
-                           (is_interface ? "interface" : (is_super ? "super class" : "virtual")),
+                           type_stream.str().c_str(),
                            PrettyMethod(called).c_str(),
                            PrettyMethod(caller).c_str());
 }
@@ -89,13 +91,14 @@
 }
 
 static void ThrowNullPointerExceptionForMethodAccess(Thread* self, Method* caller,
-                                                     uint32_t method_idx, bool is_interface,
-                                                     bool is_super) {
+                                                     uint32_t method_idx, InvokeType type) {
   const DexFile& dex_file =
       Runtime::Current()->GetClassLinker()->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
+  std::ostringstream type_stream;
+  type_stream << type;
   self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
                            "Attempt to invoke %s method '%s' from '%s' on a null object reference",
-                           (is_interface ? "interface" : (is_super ? "super class" : "virtual")),
+                           type_stream.str().c_str(),
                            PrettyMethod(method_idx, dex_file, true).c_str(),
                            PrettyMethod(caller).c_str());
 }
@@ -540,40 +543,46 @@
                          bool is_static, bool is_primitive, size_t expected_size) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
-  if (LIKELY(resolved_field != NULL)) {
+  if (UNLIKELY(resolved_field == NULL)) {
+    DCHECK(self->IsExceptionPending());  // Throw exception and unwind
+    return NULL;  // failure
+  } else {
     Class* fields_class = resolved_field->GetDeclaringClass();
     Class* referring_class = referrer->GetDeclaringClass();
     if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
       ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
+      return NULL;  // failure
     } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
                                                           resolved_field->GetAccessFlags()))) {
       ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
       return NULL;  // failure
-    }
-    FieldHelper fh(resolved_field);
-    if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
-                 fh.FieldSize() != expected_size)) {
-      self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
-                               "Attempted read of %zd-bit %s on field '%s'",
-                               expected_size * (32 / sizeof(int32_t)),
-                               is_primitive ? "primitive" : "non-primitive",
-                               PrettyField(resolved_field, true).c_str());
-    }
-    if (!is_static) {
-      // instance fields must be being accessed on an initialized class
-      return resolved_field;
     } else {
-      // If the class is already initializing, we must be inside <clinit>, or
-      // we'd still be waiting for the lock.
-      if (fields_class->IsInitializing()) {
+      FieldHelper fh(resolved_field);
+      if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
+                   fh.FieldSize() != expected_size)) {
+        self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
+                                 "Attempted read of %zd-bit %s on field '%s'",
+                                 expected_size * (32 / sizeof(int32_t)),
+                                 is_primitive ? "primitive" : "non-primitive",
+                                 PrettyField(resolved_field, true).c_str());
+        return NULL;  // failure
+      } else if (!is_static) {
+        // instance fields must be being accessed on an initialized class
         return resolved_field;
-      } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
-        return resolved_field;
+      } else {
+        // If the class is already initializing, we must be inside <clinit>, or
+        // we'd still be waiting for the lock.
+        if (fields_class->IsInitializing()) {
+          return resolved_field;
+        } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
+          return resolved_field;
+        } else {
+          DCHECK(self->IsExceptionPending());  // Throw exception and unwind
+          return NULL;  // failure
+        }
       }
     }
   }
-  DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-  return NULL;
 }
 
 extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
@@ -1118,8 +1127,9 @@
 
 // Fast path method resolution that can't throw exceptions
 static Method* FindMethodFast(uint32_t method_idx, Object* this_object, const Method* referrer,
-                              bool access_check, bool is_interface, bool is_super) {
-  if (UNLIKELY(this_object == NULL)) {
+                              bool access_check, InvokeType type) {
+  bool is_direct = type == kStatic || type == kDirect;
+  if (UNLIKELY(this_object == NULL && !is_direct)) {
     return NULL;
   }
   Method* resolved_method =
@@ -1137,38 +1147,46 @@
       return NULL;
     }
   }
-  if (is_interface) {
+  if (type == kInterface) {  // Most common form of slow path dispatch.
     return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
-  } else if (is_super) {
+  } else if (is_direct) {
+    return resolved_method;
+  } else if (type == kSuper) {
     return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
   } else {
+    DCHECK(type == kVirtual);
     return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
   }
 }
 
 // Slow path method resolution
 static Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
-                                  Thread* self, bool access_check, bool is_interface,
-                                  bool is_super) {
+                                  Thread* self, bool access_check, InvokeType type) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, false);
-  if (LIKELY(resolved_method != NULL)) {
+  bool is_direct = type == kStatic || type == kDirect;
+  Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
+  if (UNLIKELY(resolved_method == NULL)) {
+    DCHECK(self->IsExceptionPending());  // Throw exception and unwind
+    return NULL;  // failure
+  } else {
     if (!access_check) {
-      if (is_interface) {
+      if (is_direct) {
+        return resolved_method;
+      } else if (type == kInterface) {
         Method* interface_method =
             this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
         if (UNLIKELY(interface_method == NULL)) {
           ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
                                                                         resolved_method,
                                                                         this_object);
-          return NULL;
+          return NULL;  // failure
         } else {
           return interface_method;
         }
       } else {
         ObjectArray<Method>* vtable;
         uint16_t vtable_index = resolved_method->GetMethodIndex();
-        if (is_super) {
+        if (type == kSuper) {
           vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable();
         } else {
           vtable = this_object->GetClass()->GetVTable();
@@ -1191,8 +1209,7 @@
                                                   referring_class);
         if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
           ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class,
-                                                           referrer, resolved_method, is_interface,
-                                                           is_super);
+                                                           referrer, resolved_method, type);
           return NULL;  // failure
         } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
                                                               resolved_method->GetAccessFlags()))) {
@@ -1200,21 +1217,23 @@
           return NULL;  // failure
         }
       }
-      if (is_interface) {
+      if (is_direct) {
+        return resolved_method;
+      } else if (type == kInterface) {
         Method* interface_method =
             this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
         if (UNLIKELY(interface_method == NULL)) {
           ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
                                                                         resolved_method,
                                                                         this_object);
-          return NULL;
+          return NULL;  // failure
         } else {
           return interface_method;
         }
       } else {
         ObjectArray<Method>* vtable;
         uint16_t vtable_index = resolved_method->GetMethodIndex();
-        if (is_super) {
+        if (type == kSuper) {
           Class* super_class = referring_class->GetSuperClass();
           if (LIKELY(super_class != NULL)) {
             vtable = referring_class->GetSuperClass()->GetVTable();
@@ -1232,32 +1251,26 @@
           self->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
                                    "attempt to invoke %s method '%s' from '%s'"
                                    " using incorrect form of method dispatch",
-                                   (is_super ? "super class" : "virtual"),
+                                   (type == kSuper ? "super class" : "virtual"),
                                    PrettyMethod(resolved_method).c_str(),
                                    PrettyMethod(referrer).c_str());
-          return NULL;
+          return NULL;  // failure
         }
       }
     }
   }
-  DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-  return NULL;
 }
 
 static uint64_t artInvokeCommon(uint32_t method_idx, Object* this_object, Method* caller_method,
-                                Thread* self, Method** sp, bool access_check, bool is_interface,
-                                bool is_super){
-  Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check,
-                                  is_interface, is_super);
+                                Thread* self, Method** sp, bool access_check, InvokeType type){
+  Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);
   if (UNLIKELY(method == NULL)) {
     FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
-    if (UNLIKELY(this_object == NULL)) {
-      ThrowNullPointerExceptionForMethodAccess(self, caller_method, method_idx, is_interface,
-                                               is_super);
+    if (UNLIKELY(this_object == NULL && type != kDirect && type != kStatic)) {
+      ThrowNullPointerExceptionForMethodAccess(self, caller_method, method_idx, type);
       return 0;  // failure
     }
-    method = FindMethodFromCode(method_idx, this_object, caller_method, self, access_check,
-                                is_interface, is_super);
+    method = FindMethodFromCode(method_idx, this_object, caller_method, self, access_check, type);
     if (UNLIKELY(method == NULL)) {
       CHECK(self->IsExceptionPending());
       return 0;  // failure
@@ -1277,28 +1290,43 @@
 extern "C" uint64_t artInvokeInterfaceTrampoline(uint32_t method_idx, Object* this_object,
                                                  Method* caller_method, Thread* self,
                                                  Method** sp) {
-  return artInvokeCommon(method_idx, this_object, caller_method, self, sp, false, true, false);
+  return artInvokeCommon(method_idx, this_object, caller_method, self, sp, false, kInterface);
 }
 
 extern "C" uint64_t artInvokeInterfaceTrampolineWithAccessCheck(uint32_t method_idx,
                                                                 Object* this_object,
                                                                 Method* caller_method, Thread* self,
                                                                 Method** sp) {
-  return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, true, false);
+  return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kInterface);
+}
+
+
+extern "C" uint64_t artInvokeDirectTrampolineWithAccessCheck(uint32_t method_idx,
+                                                             Object* this_object,
+                                                             Method* caller_method, Thread* self,
+                                                             Method** sp) {
+  return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kDirect);
+}
+
+extern "C" uint64_t artInvokeStaticTrampolineWithAccessCheck(uint32_t method_idx,
+                                                            Object* this_object,
+                                                            Method* caller_method, Thread* self,
+                                                            Method** sp) {
+  return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kStatic);
 }
 
 extern "C" uint64_t artInvokeSuperTrampolineWithAccessCheck(uint32_t method_idx,
                                                             Object* this_object,
                                                             Method* caller_method, Thread* self,
                                                             Method** sp) {
-  return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, false, true);
+  return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kSuper);
 }
 
 extern "C" uint64_t artInvokeVirtualTrampolineWithAccessCheck(uint32_t method_idx,
                                                               Object* this_object,
                                                               Method* caller_method, Thread* self,
                                                               Method** sp) {
-  return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, false, false);
+  return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kVirtual);
 }
 
 static void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) {
diff --git a/src/runtime_support.h b/src/runtime_support.h
index a5e4c87..305bbf6 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -69,8 +69,10 @@
   extern "C" void art_check_cast_from_code(void*, void*);
   extern "C" void art_do_long_jump(uint32_t*, uint32_t*);
   extern "C" void art_handle_fill_data_from_code(void*, void*);
+  extern "C" void art_invoke_direct_trampoline_with_access_check(uint32_t, void*);
   extern "C" void art_invoke_interface_trampoline(uint32_t, void*);
   extern "C" void art_invoke_interface_trampoline_with_access_check(uint32_t, void*);
+  extern "C" void art_invoke_static_trampoline_with_access_check(uint32_t, void*);
   extern "C" void art_invoke_super_trampoline_with_access_check(uint32_t, void*);
   extern "C" void art_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
   extern "C" void art_lock_object_from_code(void*);
diff --git a/src/runtime_support_arm.S b/src/runtime_support_arm.S
index 69e908d..b337ebc 100644
--- a/src/runtime_support_arm.S
+++ b/src/runtime_support_arm.S
@@ -170,77 +170,45 @@
     mov r3, sp                            @ pass SP
     b   artThrowVerificationErrorFromCode @ artThrowVerificationErrorFromCode(kind, ref, Thread*, SP)
 
-    .global art_invoke_interface_trampoline
-    .extern artInvokeInterfaceTrampoline
     /*
-     * All generated callsites for interface invokes will load arguments as usual - except instead
-     * of loading arg0/r0 with the target Method*, arg0/r0 will contain the method_idx.  This
-     * wrapper will save arg1-arg3, load the caller's Method*, align the stack and call the helper
-     * artFindInterfaceMethodInCacheFromCode(idx, this, method);
+     * All generated callsites for interface invokes and invocation slow paths will load arguments
+     * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
+     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
+     * stack and call the appropriate C helper.
      * NOTE: "this" is first visable argument of the target, and so can be found in arg1/r1.
      *
-     * artInvokeInterfaceTrampoline will attempt to locate the target and return a 64-bit
-     * result in r0/r1 consisting of the target Method* in r0 and method->code_ in r1.
+     * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
+     * of the target Method* in r0 and method->code_ in r1.
      *
-     * If unsuccessful, artInvokeInterfaceTrampoline will return NULL/NULL. There will be
-     * a pending exception in the thread and we branch to another stub to deliver it.
+     * If unsuccessful, the helper will return NULL/NULL. There will bea pending exception in the
+     * thread and we branch to another stub to deliver it.
      *
      * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
      * pointing back to the original caller.
      */
-art_invoke_interface_trampoline:
+.macro INVOKE_TRAMPOLINE c_name, cxx_name
+    .global \c_name
+    .extern \cxx_name
+\c_name:
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  @ save callee saves in case allocation triggers GC
-    ldr    r2, [sp, #48]                          @ pass caller Method*
-    mov    r3, r9                                 @ pass Thread::Current
-    str    sp, [sp, #0]                           @ pass SP
-    bl     artInvokeInterfaceTrampoline           @ (method_idx, this, caller, Thread*, SP)
-    mov    r12, r1                                @ save r0->code_
+    ldr    r2, [sp, #48]                  @ pass caller Method*
+    mov    r3, r9                         @ pass Thread::Current
+    str    sp, [sp, #0]                   @ pass SP
+    bl     \cxx_name                      @ (method_idx, this, caller, Thread*, SP)
+    mov    r12, r1                        @ save r0->code_
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    cmp    r0, #0                                 @ did we find the target?
-    bxne   r12                                    @ tail call to target if so
+    cmp    r0, #0                         @ did we find the target?
+    bxne   r12                            @ tail call to target if so
     DELIVER_PENDING_EXCEPTION
+.endm
 
-    .global art_invoke_interface_trampoline_with_access_check
-    .extern artInvokeInterfaceTrampolineWithAccessCheck
-art_invoke_interface_trampoline_with_access_check:
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  @ save callee saves in case allocation triggers GC
-    ldr    r2, [sp, #48]                          @ pass caller Method*
-    mov    r3, r9                                 @ pass Thread::Current
-    str    sp, [sp, #0]                           @ pass SP
-    bl     artInvokeInterfaceTrampolineWithAccessCheck @ (method_idx, this, caller, Thread*, SP)
-    mov    r12, r1                                @ save r0->code_
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    cmp    r0, #0                                 @ did we find the target?
-    bxne   r12                                    @ tail call to target if so
-    DELIVER_PENDING_EXCEPTION
+INVOKE_TRAMPOLINE art_invoke_interface_trampoline, artInvokeInterfaceTrampoline
+INVOKE_TRAMPOLINE art_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
 
-    .global art_invoke_super_trampoline_with_access_check
-    .extern artInvokeSuperTrampolineWithAccessCheck
-art_invoke_super_trampoline_with_access_check:
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  @ save callee saves in case allocation triggers GC
-    ldr    r2, [sp, #48]                          @ pass caller Method*
-    mov    r3, r9                                 @ pass Thread::Current
-    str    sp, [sp, #0]                           @ pass SP
-    bl     artInvokeSuperTrampolineWithAccessCheck @ (method_idx, this, caller, Thread*, SP)
-    mov    r12, r1                                @ save r0->code_
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    cmp    r0, #0                                 @ did we find the target?
-    bxne   r12                                    @ tail call to target if so
-    DELIVER_PENDING_EXCEPTION
-
-    .global art_invoke_virtual_trampoline_with_access_check
-    .extern artInvokeVirtualTrampolineWithAccessCheck
-art_invoke_virtual_trampoline_with_access_check:
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  @ save callee saves in case allocation triggers GC
-    ldr    r2, [sp, #48]                          @ pass caller Method*
-    mov    r3, r9                                 @ pass Thread::Current
-    str    sp, [sp, #0]                           @ pass SP
-    bl     artInvokeVirtualTrampolineWithAccessCheck @ (method_idx, this, caller, Thread*, SP)
-    mov    r12, r1                                @ save r0->code_
-    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    cmp    r0, #0                                 @ did we find the target?
-    bxne   r12                                    @ tail call to target if so
-    DELIVER_PENDING_EXCEPTION
+INVOKE_TRAMPOLINE art_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
 
     .global art_handle_fill_data_from_code
     .extern artHandleFillArrayDataFromCode
diff --git a/src/thread.cc b/src/thread.cc
index 2fd3a5a..661e3bb 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -115,8 +115,10 @@
   pInitializeStaticStorage = art_initialize_static_storage_from_code;
   pInitializeTypeFromCode = art_initialize_type_from_code;
   pInitializeTypeAndVerifyAccessFromCode = art_initialize_type_and_verify_access_from_code;
+  pInvokeDirectTrampolineWithAccessCheck = art_invoke_direct_trampoline_with_access_check;
   pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
   pInvokeInterfaceTrampolineWithAccessCheck = art_invoke_interface_trampoline_with_access_check;
+  pInvokeStaticTrampolineWithAccessCheck = art_invoke_static_trampoline_with_access_check;
   pInvokeSuperTrampolineWithAccessCheck = art_invoke_super_trampoline_with_access_check;
   pInvokeVirtualTrampolineWithAccessCheck = art_invoke_virtual_trampoline_with_access_check;
   pLockObjectFromCode = art_lock_object_from_code;
diff --git a/src/thread.h b/src/thread.h
index 4bfc5cf..cd39794 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -617,8 +617,10 @@
   void (*pHandleFillArrayDataFromCode)(void*, void*);
   void* (*pInitializeStaticStorage)(uint32_t, void*);
   uint32_t (*pInstanceofNonTrivialFromCode)(const Class*, const Class*);
+  void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*);
   void (*pInvokeInterfaceTrampoline)(uint32_t, void*);
   void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*);
+  void (*pInvokeStaticTrampolineWithAccessCheck)(uint32_t, void*);
   void (*pInvokeSuperTrampolineWithAccessCheck)(uint32_t, void*);
   void (*pInvokeVirtualTrampolineWithAccessCheck)(uint32_t, void*);
   void* (*pInitializeTypeFromCode)(uint32_t, void*);