Support for resolving unknown direct/static methods.

If we can't resolve a method we don't know whether it is direct or
static from the dex information (other than the invocation instruction).
Add support for a third type of resolution stub that can discover the
type of the method based on the calling method and PC of the invocation
instruction. Its still unimplemented to look up the instruction and
figure out if the type is static or not.

Change-Id: I8b76e6ba2c946376e7fe287dbcca17bcaab0e133
diff --git a/src/common_test.h b/src/common_test.h
index 68e3019..72701d9 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -128,20 +128,22 @@
     class_linker_ = runtime_->GetClassLinker();
 
 #if defined(__i386__)
-    runtime_->SetJniStubArray(JniCompiler::CreateJniStub(kX86));
-    runtime_->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kX86));
-    runtime_->SetResolutionStubArray(Compiler::CreateResolutionStub(kX86, false), false);
-    runtime_->SetResolutionStubArray(Compiler::CreateResolutionStub(kX86, true), true);
-    runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kX86));
-    compiler_.reset(new Compiler(kX86));
+    InstructionSet insns = kX86;
 #elif defined(__arm__)
-    runtime_->SetJniStubArray(JniCompiler::CreateJniStub(kThumb2));
-    runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kThumb2));
-    runtime_->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kThumb2));
-    runtime_->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2, false), false);
-    runtime_->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2, true), true);
-    compiler_.reset(new Compiler(kThumb2));
+    InstructionSet insns = kThumb2;
+#else
+    InstructionSet insns = kNone;
 #endif
+    runtime_->SetJniStubArray(JniCompiler::CreateJniStub(insns));
+    runtime_->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(insns));
+    runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(insns));
+    for (int i=0; i < Runtime::kMaxTrampolineMethodType; i++) {
+      Runtime::TrampolineType type = Runtime::TrampolineType(i);
+      if (!runtime_->HasResolutionStubArray(type)) {
+        runtime_->SetResolutionStubArray(Compiler::CreateResolutionStub(insns, type), type);
+      }
+    }
+    compiler_.reset(new Compiler(insns));
 
     Heap::VerifyHeap();  // Check for heap corruption before the test
   }
diff --git a/src/compiler.cc b/src/compiler.cc
index f4e8874..3b92267 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -19,12 +19,12 @@
 namespace arm {
   ByteArray* CreateAbstractMethodErrorStub();
   void ArmCreateInvokeStub(Method* method);
-  ByteArray* ArmCreateResolutionTrampoline(bool is_static);
+  ByteArray* ArmCreateResolutionTrampoline(Runtime::TrampolineType type);
 }
 namespace x86 {
   ByteArray* CreateAbstractMethodErrorStub();
   void X86CreateInvokeStub(Method* method);
-  ByteArray* X86CreateResolutionTrampoline(bool is_static);
+  ByteArray* X86CreateResolutionTrampoline(Runtime::TrampolineType type);
 }
 
 Compiler::Compiler(InstructionSet insns) : instruction_set_(insns), jni_compiler_(insns),
@@ -32,13 +32,14 @@
   CHECK(!Runtime::Current()->IsStarted());
 }
 
-ByteArray* Compiler::CreateResolutionStub(InstructionSet instruction_set, bool is_static) {
+ByteArray* Compiler::CreateResolutionStub(InstructionSet instruction_set,
+                                          Runtime::TrampolineType type) {
   if (instruction_set == kX86) {
-    return x86::X86CreateResolutionTrampoline(is_static);
+    return x86::X86CreateResolutionTrampoline(type);
   } else {
     CHECK(instruction_set == kArm || instruction_set == kThumb2);
     // Generates resolution stub using ARM instruction set
-    return arm::ArmCreateResolutionTrampoline(is_static);
+    return arm::ArmCreateResolutionTrampoline(type);
   }
 }
 
@@ -332,7 +333,8 @@
   for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
     Method* method = dex_cache->GetResolvedMethod(i);
     if ((method == NULL) || (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized())) {
-      ByteArray* res_trampoline = runtime->GetResolutionStubArray(method->IsStatic());
+      Runtime::TrampolineType type = Runtime::GetTrampolineType(method);
+      ByteArray* res_trampoline = runtime->GetResolutionStubArray(type);
       if (instruction_set_ == kX86) {
         code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline, kX86);
       } else {
diff --git a/src/compiler.h b/src/compiler.h
index 3b316eb..0f6f02f 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -7,6 +7,7 @@
 #include "dex_file.h"
 #include "jni_compiler.h"
 #include "object.h"
+#include "runtime.h"
 
 int oatVRegOffsetFromMethod(art::Method* method, int reg);
 
@@ -34,7 +35,8 @@
   static ByteArray* CreateAbstractMethodErrorStub(InstructionSet instruction_set);
 
   // Generate the trampoline that's invoked by unresolved direct methods
-  static ByteArray* CreateResolutionStub(InstructionSet instruction_set, bool is_static);
+  static ByteArray* CreateResolutionStub(InstructionSet instruction_set,
+                                         Runtime::TrampolineType type);
 
  private:
   // Attempt to resolve all type, methods, fields, and strings
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 1ad71a6..e1ffab0 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -200,11 +200,11 @@
   if (!runtime->HasAbstractMethodErrorStubArray()) {
     runtime->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kThumb2));
   }
-  if (!runtime->HasResolutionStubArray(false)) {
-    runtime->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2,false), false);
-  }
-  if (!runtime->HasResolutionStubArray(true)) {
-    runtime->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2,true), true);
+  for (int i=0; i < Runtime::kMaxTrampolineMethodType; i++) {
+    Runtime::TrampolineType type = Runtime::TrampolineType(i);
+    if (!runtime->HasResolutionStubArray(type)) {
+      runtime->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2, type), type);
+    }
   }
   if (!runtime->HasCalleeSaveMethod()) {
     runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(kThumb2));
diff --git a/src/exception_test.cc b/src/exception_test.cc
index fd012cd..49a5266 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -99,7 +99,7 @@
   ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t));
 
   // Create two fake stack frames with mapping data created in SetUp. We map offset 3 in the code
-  // two dex pc 3, however, we set the return pc to 5 as the stack walker always subtracts two
+  // to dex pc 3, however, we set the return pc to 5 as the stack walker always subtracts two
   // from a return pc.
 
   // Create/push fake 16byte stack frame for method g
diff --git a/src/image.h b/src/image.h
index a5cdeb7..e2be3d4 100644
--- a/src/image.h
+++ b/src/image.h
@@ -70,6 +70,7 @@
     kAbstractMethodErrorStubArray,
     kInstanceResolutionStubArray,
     kStaticResolutionStubArray,
+    kUnknownMethodResolutionStubArray,
     kCalleeSaveMethod,
     kOatLocation,
     kDexCaches,
diff --git a/src/image_writer.cc b/src/image_writer.cc
index c020a79..9246440 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -140,8 +140,12 @@
   image_roots->Set(ImageHeader::kJniStubArray, runtime->GetJniStubArray());
   image_roots->Set(ImageHeader::kAbstractMethodErrorStubArray,
                    runtime->GetAbstractMethodErrorStubArray());
-  image_roots->Set(ImageHeader::kInstanceResolutionStubArray, runtime->GetResolutionStubArray(false));
-  image_roots->Set(ImageHeader::kStaticResolutionStubArray, runtime->GetResolutionStubArray(true));
+  image_roots->Set(ImageHeader::kInstanceResolutionStubArray,
+                   runtime->GetResolutionStubArray(Runtime::kInstanceMethod));
+  image_roots->Set(ImageHeader::kStaticResolutionStubArray,
+                   runtime->GetResolutionStubArray(Runtime::kStaticMethod));
+  image_roots->Set(ImageHeader::kUnknownMethodResolutionStubArray,
+                   runtime->GetResolutionStubArray(Runtime::kUnknownMethod));
   image_roots->Set(ImageHeader::kCalleeSaveMethod, runtime->GetCalleeSaveMethod());
   image_roots->Set(ImageHeader::kOatLocation,
                    String::AllocFromModifiedUtf8(oat_file_->GetLocation().c_str()));
@@ -355,16 +359,8 @@
   CodeAndDirectMethods* orig_cadms = orig->GetCodeAndDirectMethods();
   // The compacted object in local memory but not at the correct image address
   CodeAndDirectMethods* copy_cadms = down_cast<CodeAndDirectMethods*>(GetLocalAddress(orig_cadms));
-  // The lazy resolution stub
-  ByteArray* orig_res_stub_array[2];
-  orig_res_stub_array[0] = Runtime::Current()->GetResolutionStubArray(false);
-  orig_res_stub_array[1] = Runtime::Current()->GetResolutionStubArray(true);
-  DCHECK(orig_res_stub_array[0] != NULL);
-  DCHECK(orig_res_stub_array[1] != NULL);
-  uint32_t orig_res_stub_array_data[2];
-  orig_res_stub_array_data[0] = reinterpret_cast<uint32_t>(orig_res_stub_array[0]->GetData());
-  orig_res_stub_array_data[1] = reinterpret_cast<uint32_t>(orig_res_stub_array[1]->GetData());
 
+  Runtime* runtime = Runtime::Current();
   for (size_t i = 0; i < orig->NumResolvedMethods(); i++) {
     Method* orig_method = orig->GetResolvedMethod(i);
     if (orig_method != NULL && !InSourceSpace(orig_method)) {
@@ -373,35 +369,31 @@
     // if it was resolved in the original, resolve it in the copy
     if (orig_method == NULL || (orig_method->IsStatic() &&
                                 !orig_method->GetDeclaringClass()->IsInitialized())) {
-      // Do we need to relocate this for this space?
-      if (InSourceSpace(orig_res_stub_array[0])) {
-        bool is_static;  // is this static? hard to tell for null methods
-        uint32_t orig_res_stub_code = orig_cadms->Get(CodeAndDirectMethods::CodeIndex(i));
-        if (orig_res_stub_code == 0) {
-          continue;  // NULL maps the same in the image and the original
-        }
-        if (orig_res_stub_code - orig_res_stub_array_data[0] < 1) {
-          DCHECK(orig_method == NULL || !orig_method->IsStatic());
-          is_static = false;
-        } else {
-          DCHECK(orig_method == NULL || orig_method->IsStatic());
-          is_static = true;
-        }
-        // Compute the delta from the start of the resolution stub to its starting code.
-        // For ARM and X86 this is 0, for Thumb2 it is 1.
-        static size_t res_stub_delta = 0xFFFF;
-        if (res_stub_delta == 0xFFFF) {
-          res_stub_delta = orig_res_stub_code - orig_res_stub_array_data[is_static ? 1 : 0];
-          DCHECK(res_stub_delta == 0 || res_stub_delta == 1);
-        }
-        // Compute address in image of resolution stub and the code address
-        ByteArray* image_res_stub_array =
-            down_cast<ByteArray*>(GetImageAddress(orig_res_stub_array[is_static ? 1 : 0]));
-        int32_t image_res_stub_code =
-            reinterpret_cast<int32_t>(image_res_stub_array->GetData()) + res_stub_delta;
-        // Put the image code address in the array
-        copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i), image_res_stub_code);
+      uint32_t orig_res_stub_code = orig_cadms->Get(CodeAndDirectMethods::CodeIndex(i));
+      if (orig_res_stub_code == 0) {
+        continue;  // NULL maps the same in the image and the original
       }
+      Runtime::TrampolineType type = Runtime::GetTrampolineType(orig_method);  // Type of trampoline
+      ByteArray* orig_res_stub_array = runtime->GetResolutionStubArray(type);
+      // Do we need to relocate this for this space?
+      if (!InSourceSpace(orig_res_stub_array)) {
+        continue;
+      }
+      // Compute the delta from the start of the resolution stub to its starting code.
+      // For ARM and X86 this is 0, for Thumb2 it is 1.
+      static size_t res_stub_delta = 0xFFFF;
+      if (res_stub_delta == 0xFFFF) {
+        uint32_t orig_res_stub_array_data =
+            reinterpret_cast<uint32_t>(orig_res_stub_array->GetData());
+        res_stub_delta = orig_res_stub_code - orig_res_stub_array_data;
+        DCHECK(res_stub_delta == 0 || res_stub_delta == 1);
+      }
+      // Compute address in image of resolution stub and the code address
+      ByteArray* image_res_stub_array = down_cast<ByteArray*>(GetImageAddress(orig_res_stub_array));
+      int32_t image_res_stub_code =
+          reinterpret_cast<int32_t>(image_res_stub_array->GetData()) + res_stub_delta;
+      // Put the image code address in the array
+      copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i), image_res_stub_code);
     } else if (orig_method->IsDirect()) {
       Method* copy_method = down_cast<Method*>(GetLocalAddress(orig_method));
       copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i),
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 529f8e2..27dbdee 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -50,6 +50,7 @@
   "kAbstractMethodErrorStubArray",
   "kInstanceResolutionStubArray",
   "kStaticResolutionStubArray",
+  "kUnknownMethodResolutionStubArray",
   "kCalleeSaveMethod",
   "kOatLocation",
   "kDexCaches",
diff --git a/src/runtime.cc b/src/runtime.cc
index 231c010..5d2689d 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -592,20 +592,30 @@
   abstract_method_error_stub_array_ = abstract_method_error_stub_array;
 }
 
-bool Runtime::HasResolutionStubArray(bool is_static) const {
-  return resolution_stub_array_[is_static ? 1 : 0] != NULL;
+
+Runtime::TrampolineType Runtime::GetTrampolineType(Method* method) {
+  if (method == NULL) {
+    return Runtime::kUnknownMethod;
+  } else if (method->IsStatic()) {
+    return Runtime::kStaticMethod;
+  } else {
+    return Runtime::kInstanceMethod;
+  }
 }
 
-ByteArray* Runtime::GetResolutionStubArray(bool is_static) const {
-  CHECK(HasResolutionStubArray(is_static));
-  return resolution_stub_array_[is_static ? 1 : 0];
+bool Runtime::HasResolutionStubArray(TrampolineType type) const {
+  return resolution_stub_array_[type] != NULL;
 }
 
-void Runtime::SetResolutionStubArray(ByteArray* resolution_stub_array, bool is_static) {
+ByteArray* Runtime::GetResolutionStubArray(TrampolineType type) const {
+  CHECK(HasResolutionStubArray(type));
+  return resolution_stub_array_[type];
+}
+
+void Runtime::SetResolutionStubArray(ByteArray* resolution_stub_array, TrampolineType type) {
   CHECK(resolution_stub_array != NULL);
-  CHECK(!HasResolutionStubArray(is_static) ||
-        resolution_stub_array_[is_static ? 1 : 0] == resolution_stub_array);
-  resolution_stub_array_[is_static ? 1 : 0] = resolution_stub_array;
+  CHECK(!HasResolutionStubArray(type) || resolution_stub_array_[type] == resolution_stub_array);
+  resolution_stub_array_[type] = resolution_stub_array;
 }
 
 Method* Runtime::CreateCalleeSaveMethod(InstructionSet insns) {
diff --git a/src/runtime.h b/src/runtime.h
index f99d994..8c4ce7c 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -156,9 +156,16 @@
   ByteArray* GetAbstractMethodErrorStubArray() const;
   void SetAbstractMethodErrorStubArray(ByteArray* abstract_method_error_stub_array);
 
-  bool HasResolutionStubArray(bool is_static) const;
-  ByteArray* GetResolutionStubArray(bool is_static) const;
-  void SetResolutionStubArray(ByteArray* resolution_stub_array, bool is_static);
+  enum TrampolineType {
+    kInstanceMethod,
+    kStaticMethod,
+    kUnknownMethod,
+    kMaxTrampolineMethodType = kUnknownMethod
+  };
+  static TrampolineType GetTrampolineType(Method* method);
+  bool HasResolutionStubArray(TrampolineType type) const;
+  ByteArray* GetResolutionStubArray(TrampolineType type) const;
+  void SetResolutionStubArray(ByteArray* resolution_stub_array, TrampolineType type);
 
   // Returns a special method that describes all callee saves being spilled to the stack.
   Method* CreateCalleeSaveMethod(InstructionSet insns);
@@ -225,7 +232,7 @@
 
   ByteArray* abstract_method_error_stub_array_;
 
-  ByteArray* resolution_stub_array_[2];
+  ByteArray* resolution_stub_array_[kMaxTrampolineMethodType];
 
   Method* callee_save_method_;
 
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 49191b7..9cc8804 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -310,7 +310,7 @@
 }
 
 void* UnresolvedDirectMethodTrampolineFromCode(int32_t method_idx, void* sp, Thread* thread,
-                                               bool is_static) {
+                                               Runtime::TrampolineType type) {
   // TODO: this code is specific to ARM
   // On entry the stack pointed by sp is:
   // | argN       |  |
@@ -327,40 +327,49 @@
   // | R0         | <- sp
   uintptr_t* regs = reinterpret_cast<uintptr_t*>(sp);
   Method** caller_sp = reinterpret_cast<Method**>(&regs[5]);
+  uintptr_t caller_pc = regs[4];
   // Record the last top of the managed stack
-  thread->SetTopOfStack(caller_sp, regs[4]);
-  ClassLinker* linker = Runtime::Current()->GetClassLinker();
+  thread->SetTopOfStack(caller_sp, caller_pc);
   // Start new JNI local reference state
   JNIEnvExt* env = thread->GetJniEnv();
   uint32_t saved_local_ref_cookie = env->local_ref_cookie;
   env->local_ref_cookie = env->locals.GetSegmentState();
   // Discover shorty (avoid GCs)
+  ClassLinker* linker = Runtime::Current()->GetClassLinker();
   const char* shorty = linker->MethodShorty(method_idx, *caller_sp);
   size_t shorty_len = strlen(shorty);
   size_t args_in_regs = shorty_len < 3 ? shorty_len : 3;
-  // Handlerize references in registers
-  int cur_arg = 1;   // skip method_idx in R0, first arg is in R1
-  if (!is_static) {
-    Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
-    cur_arg++;
-    AddLocalReference<jobject>(env, obj);
-  }
-  for(size_t i = 0; i < args_in_regs; i++) {
-    char c = shorty[i + 1];  // offset to skip return value
-    if (c == 'L') {
+  if (type == Runtime::kUnknownMethod) {
+    uint32_t dex_pc = (*caller_sp)->ToDexPC(caller_pc - 2);
+    UNIMPLEMENTED(WARNING) << "Missed argument handlerization in direct method trampoline. "
+        "Need to discover method invoke type at " << PrettyMethod(*caller_sp)
+        << " PC: " << (void*)dex_pc;
+  } else {
+    bool is_static = type == Runtime::kStaticMethod;
+    // Handlerize references in registers
+    int cur_arg = 1;   // skip method_idx in R0, first arg is in R1
+    if (!is_static) {
       Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
+      cur_arg++;
       AddLocalReference<jobject>(env, obj);
     }
-    cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
-  }
-  // Handlerize references in out going arguments
-  for(size_t i = 3; i < shorty_len; i++) {
-    char c = shorty[i + 1];  // offset to skip return value
-    if (c == 'L') {
-      Object* obj = reinterpret_cast<Object*>(regs[i + 3]);  // skip R0, LR and Method* of caller
-      AddLocalReference<jobject>(env, obj);
+    for(size_t i = 0; i < args_in_regs; i++) {
+      char c = shorty[i + 1];  // offset to skip return value
+      if (c == 'L') {
+        Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
+        AddLocalReference<jobject>(env, obj);
+      }
+      cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
     }
-    cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
+    // Handlerize references in out going arguments
+    for(size_t i = 3; i < shorty_len; i++) {
+      char c = shorty[i + 1];  // offset to skip return value
+      if (c == 'L') {
+        Object* obj = reinterpret_cast<Object*>(regs[i + 3]);  // skip R0, LR and Method* of caller
+        AddLocalReference<jobject>(env, obj);
+      }
+      cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
+    }
   }
   // Resolve method filling in dex cache
   Method* called = linker->ResolveMethod(method_idx, *caller_sp, true);
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 78a5813..d47f25b 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -14,7 +14,7 @@
 extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
 extern void* FindNativeMethod(Thread* thread);
 extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
-void* UnresolvedDirectMethodTrampolineFromCode(int32_t, void*, Thread*, bool);
+void* UnresolvedDirectMethodTrampolineFromCode(int32_t, void*, Thread*, Runtime::TrampolineType);
 extern Class* InitializeTypeFromCode(uint32_t type_idx, Method* method);
 extern void ResolveMethodFromCode(Method* method, uint32_t method_idx);
 extern void LockObjectFromCode(Thread* thread, Object* obj);
diff --git a/src/space.cc b/src/space.cc
index 1b887d8..d498b8b 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -135,9 +135,14 @@
   Runtime::Current()->SetAbstractMethodErrorStubArray(down_cast<ByteArray*>(ame_stub_array));
 
   Object* resolution_stub_array = image_header.GetImageRoot(ImageHeader::kInstanceResolutionStubArray);
-  Runtime::Current()->SetResolutionStubArray(down_cast<ByteArray*>(resolution_stub_array), false);
+  Runtime::Current()->SetResolutionStubArray(
+      down_cast<ByteArray*>(resolution_stub_array), Runtime::kInstanceMethod);
   resolution_stub_array = image_header.GetImageRoot(ImageHeader::kStaticResolutionStubArray);
-  Runtime::Current()->SetResolutionStubArray(down_cast<ByteArray*>(resolution_stub_array), true);
+  Runtime::Current()->SetResolutionStubArray(
+      down_cast<ByteArray*>(resolution_stub_array), Runtime::kStaticMethod);
+  resolution_stub_array = image_header.GetImageRoot(ImageHeader::kUnknownMethodResolutionStubArray);
+  Runtime::Current()->SetResolutionStubArray(
+      down_cast<ByteArray*>(resolution_stub_array), Runtime::kUnknownMethod);
 
   Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
   Runtime::Current()->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method));
diff --git a/src/stub_arm.cc b/src/stub_arm.cc
index 772950c..aeee8c8 100644
--- a/src/stub_arm.cc
+++ b/src/stub_arm.cc
@@ -9,7 +9,7 @@
 namespace art {
 namespace arm {
 
-ByteArray* ArmCreateResolutionTrampoline(bool is_static) {
+ByteArray* ArmCreateResolutionTrampoline(Runtime::TrampolineType type) {
   UniquePtr<ArmAssembler> assembler( static_cast<ArmAssembler*>(Assembler::Create(kArm)) );
   RegList save = (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | (1 << LR);
 
@@ -25,7 +25,7 @@
   __ LoadFromOffset(kLoadWord, R12, TR,
                     OFFSETOF_MEMBER(Thread, pUnresolvedDirectMethodTrampolineFromCode));
   __ mov(R2, ShifterOperand(TR));  // Pass Thread::Current() in R2
-  __ LoadImmediate(R3, is_static ? 1 : 0);
+  __ LoadImmediate(R3, type);
   __ IncreaseFrameSize(12);        // 3 words of space for alignment
   // Call to unresolved direct method trampoline (method_idx, sp, Thread*, is_static)
   __ blx(R12);
diff --git a/src/stub_x86.cc b/src/stub_x86.cc
index e4a56a7..9a6797a 100644
--- a/src/stub_x86.cc
+++ b/src/stub_x86.cc
@@ -9,7 +9,7 @@
 namespace art {
 namespace x86 {
 
-ByteArray* X86CreateResolutionTrampoline(bool) {
+ByteArray* X86CreateResolutionTrampoline(Runtime::TrampolineType) {
   UniquePtr<X86Assembler> assembler( static_cast<X86Assembler*>(Assembler::Create(kX86)) );
 
   // TODO: unimplemented
diff --git a/src/thread.h b/src/thread.h
index d1da623..7bd6855 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -116,7 +116,8 @@
   int (*pIdiv)(int, int);
   long long (*pLmul)(long long, long long);
   long long (*pLdivmod)(long long, long long);
-  void* (*pUnresolvedDirectMethodTrampolineFromCode)(int32_t, void*, Thread*, bool);
+  void* (*pUnresolvedDirectMethodTrampolineFromCode)(int32_t, void*, Thread*,
+      Runtime::TrampolineType);
   void* (*pAllocObjectFromCode)(uint32_t, void*);
   void* (*pAllocArrayFromCode)(uint32_t, void*, int32_t);
   void* (*pCheckAndAllocArrayFromCode)(uint32_t, void*, int32_t);