SIRT work around JNI support for legacy apps

Legacy apps may be broken and expect a jobject to equal an Object*. This
is a work around to support outgoing SIRT arguments being converted to
be Object*s. It steals the unused GC map pointer on native methods.

Change-Id: I8fb3701b0cdf15be9e8f9b722e47386505482666
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index f158680..d9d7e90 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -131,21 +131,21 @@
   return thread->DecodeJObject(obj);
 }
 
-extern void* FindNativeMethod(Thread* thread) {
-  DCHECK(Thread::Current() == thread);
+extern void* FindNativeMethod(Thread* self) {
+  DCHECK(Thread::Current() == self);
 
-  Method* method = const_cast<Method*>(thread->GetCurrentMethod());
+  Method* method = const_cast<Method*>(self->GetCurrentMethod());
   DCHECK(method != NULL);
 
   // Lookup symbol address for method, on failure we'll return NULL with an
   // exception set, otherwise we return the address of the method we found.
-  void* native_code = thread->GetJniEnv()->vm->FindCodeForNativeMethod(method);
+  void* native_code = self->GetJniEnv()->vm->FindCodeForNativeMethod(method);
   if (native_code == NULL) {
-    DCHECK(thread->IsExceptionPending());
+    DCHECK(self->IsExceptionPending());
     return NULL;
   } else {
     // Register so that future calls don't come here
-    method->RegisterNative(native_code);
+    method->RegisterNative(self, native_code);
     return native_code;
   }
 }
@@ -510,6 +510,74 @@
   return code;
 }
 
+static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) {
+  intptr_t value = *arg_ptr;
+  Object** value_as_jni_rep = reinterpret_cast<Object**>(value);
+  Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL;
+  CHECK(Heap::IsHeapAddress(value_as_work_around_rep));
+  *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
+}
+
+extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp) {
+  DCHECK(Thread::Current() == self);
+  // TODO: this code is specific to ARM
+  // On entry the stack pointed by sp is:
+  // | arg3   | <- Calling JNI method's frame (and extra bit for out args)
+  // | LR     |
+  // | R3     |    arg2
+  // | R2     |    arg1
+  // | R1     |    jclass/jobject
+  // | R0     |    JNIEnv
+  // | unused |
+  // | unused |
+  // | unused | <- sp
+  Method* jni_method = self->GetTopOfStack().GetMethod();
+  DCHECK(jni_method->IsNative()) << PrettyMethod(jni_method);
+  intptr_t* arg_ptr = sp + 4;  // pointer to r1 on stack
+  // Fix up this/jclass argument
+  WorkAroundJniBugsForJobject(arg_ptr);
+  arg_ptr++;
+  // Fix up jobject arguments
+  MethodHelper mh(jni_method);
+  int reg_num = 2;  // Current register being processed, -1 for stack arguments.
+  for (int32_t i = 1; i < mh.GetShortyLength(); i++) {
+    char shorty_char = mh.GetShorty()[i];
+    if (shorty_char == 'L') {
+      WorkAroundJniBugsForJobject(arg_ptr);
+    }
+    if (shorty_char == 'J' || shorty_char == 'D') {
+      if (reg_num == 2) {
+        arg_ptr = sp + 8;  // skip to out arguments
+        reg_num = -1;
+      } else if (reg_num == 3) {
+        arg_ptr = sp + 10;  // skip to out arguments plus 2 slots as long must be aligned
+        reg_num = -1;
+      } else {
+        DCHECK(reg_num == -1);
+        if ((reinterpret_cast<intptr_t>(arg_ptr) & 7) == 4) {
+          arg_ptr += 3;  // unaligned, pad and move through stack arguments
+        } else {
+          arg_ptr += 2;  // aligned, move through stack arguments
+        }
+      }
+    } else {
+      if (reg_num == 2) {
+        arg_ptr++; // move through register arguments
+        reg_num++;
+      } else if (reg_num == 3) {
+        arg_ptr = sp + 8;  // skip to outgoing stack arguments
+        reg_num = -1;
+      } else {
+        DCHECK(reg_num == -1);
+        arg_ptr++;  // move through stack arguments
+      }
+    }
+  }
+  // Load expected destination, see Method::RegisterNative
+  return reinterpret_cast<const void*>(jni_method->GetGcMapRaw());
+}
+
+
 // Fast path field resolution that can't throw exceptions
 static Field* FindFieldFast(uint32_t field_idx, const Method* referrer, bool is_primitive,
                             size_t expected_size) {