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/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);