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/object.cc b/src/object.cc
index 3aba5c8..cf15a64 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -34,6 +34,7 @@
 #include "monitor.h"
 #include "object_utils.h"
 #include "runtime.h"
+#include "runtime_support.h"
 #include "stack.h"
 #include "utils.h"
 
@@ -598,17 +599,34 @@
   return native_method != jni_stub;
 }
 
-void Method::RegisterNative(const void* native_method) {
+void Method::RegisterNative(Thread* self, const void* native_method) {
+  DCHECK(Thread::Current() == self);
   CHECK(IsNative()) << PrettyMethod(this);
   CHECK(native_method != NULL) << PrettyMethod(this);
-  SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, native_method_),
-                           native_method, false);
+  if (!self->GetJniEnv()->vm->work_around_app_jni_bugs) {
+    SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, native_method_),
+                             native_method, false);
+  } else {
+    // We've been asked to associate this method with the given native method but are working
+    // around JNI bugs, that include not giving Object** SIRT references to native methods. Direct
+    // the native method to runtime support and store the target somewhere runtime support will
+    // find it.
+#if defined(__arm__)
+    SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, native_method_),
+        reinterpret_cast<const void*>(art_work_around_app_jni_bugs), false);
+#else
+    UNIMPLEMENTED(FATAL);
+#endif
+    SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(Method, gc_map_),
+        reinterpret_cast<const uint8_t*>(native_method), false);
+  }
 }
 
 void Method::UnregisterNative() {
   CHECK(IsNative()) << PrettyMethod(this);
   // restore stub to lookup native pointer via dlsym
-  RegisterNative(Runtime::Current()->GetJniDlsymLookupStub()->GetData());
+  SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, native_method_),
+      Runtime::Current()->GetJniDlsymLookupStub()->GetData(), false);
 }
 
 void Class::SetStatus(Status new_status) {