Refactor reflective method invocation.

Move invocation code out of JNI internal into reflection, including ArgArray
code. Make reflective invocation use the ArgArray to build arguments rather
than allocating a jvalue[] and unboxing arguments into that.
Move reflection part of jni_internal_test into reflection_test.
Make greater use of fast JNI.

Change-Id: Ib381372df5f9a83679e30e7275de24fa0e6b1057
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 6482917..0b58af4 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -29,7 +29,7 @@
 #include "jni_internal.h"
 #include "mirror/class.h"
 #include "ScopedUtfChars.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
 #include "toStringArray.h"
 #include "trace.h"
 
@@ -153,12 +153,12 @@
 }
 
 static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   return Runtime::Current()->GetClassLinker()->DumpAllClasses(flags);
 }
 
 static jint VMDebug_getLoadedClassCount(JNIEnv* env, jclass) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   return Runtime::Current()->GetClassLinker()->NumLoadedClasses();
 }
 
@@ -318,14 +318,14 @@
   NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"),
   NATIVE_METHOD(VMDebug, getHeapSpaceStats, "([J)V"),
   NATIVE_METHOD(VMDebug, getInstructionCount, "([I)V"),
-  NATIVE_METHOD(VMDebug, getLoadedClassCount, "()I"),
+  NATIVE_METHOD(VMDebug, getLoadedClassCount, "!()I"),
   NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"),
   NATIVE_METHOD(VMDebug, infopoint, "(I)V"),
-  NATIVE_METHOD(VMDebug, isDebuggerConnected, "()Z"),
-  NATIVE_METHOD(VMDebug, isDebuggingEnabled, "()Z"),
+  NATIVE_METHOD(VMDebug, isDebuggerConnected, "!()Z"),
+  NATIVE_METHOD(VMDebug, isDebuggingEnabled, "!()Z"),
   NATIVE_METHOD(VMDebug, getMethodTracingMode, "()I"),
-  NATIVE_METHOD(VMDebug, lastDebuggerActivity, "()J"),
-  NATIVE_METHOD(VMDebug, printLoadedClasses, "(I)V"),
+  NATIVE_METHOD(VMDebug, lastDebuggerActivity, "!()J"),
+  NATIVE_METHOD(VMDebug, printLoadedClasses, "!(I)V"),
   NATIVE_METHOD(VMDebug, resetAllocCount, "(I)V"),
   NATIVE_METHOD(VMDebug, resetInstructionCount, "()V"),
   NATIVE_METHOD(VMDebug, startAllocCounting, "()V"),
@@ -338,7 +338,7 @@
   NATIVE_METHOD(VMDebug, stopEmulatorTracing, "()V"),
   NATIVE_METHOD(VMDebug, stopInstructionCounting, "()V"),
   NATIVE_METHOD(VMDebug, stopMethodTracing, "()V"),
-  NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "()J"),
+  NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "!()J"),
 };
 
 void register_dalvik_system_VMDebug(JNIEnv* env) {
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 0e2d921..5c5eaa1 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -532,7 +532,7 @@
   NATIVE_METHOD(VMRuntime, concurrentGC, "()V"),
   NATIVE_METHOD(VMRuntime, disableJitCompilation, "()V"),
   NATIVE_METHOD(VMRuntime, getTargetHeapUtilization, "()F"),
-  NATIVE_METHOD(VMRuntime, isDebuggerActive, "()Z"),
+  NATIVE_METHOD(VMRuntime, isDebuggerActive, "!()Z"),
   NATIVE_METHOD(VMRuntime, nativeSetTargetHeapUtilization, "(F)V"),
   NATIVE_METHOD(VMRuntime, newNonMovableArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"),
   NATIVE_METHOD(VMRuntime, newUnpaddedArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"),
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 7e02e29..9975bf7 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -26,42 +26,43 @@
 
 namespace art {
 
-static jobject GetThreadStack(JNIEnv* env, jobject peer) {
-  {
-    ScopedObjectAccess soa(env);
-    if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
-      return soa.Self()->CreateInternalStackTrace(soa);
-    }
-  }
-  // Suspend thread to build stack trace.
-  bool timed_out;
-  Thread* thread = ThreadList::SuspendThreadByPeer(peer, true, false, &timed_out);
-  if (thread != NULL) {
-    jobject trace;
-    {
-      ScopedObjectAccess soa(env);
-      trace = thread->CreateInternalStackTrace(soa);
-    }
-    // Restart suspended thread.
-    Runtime::Current()->GetThreadList()->Resume(thread, false);
-    return trace;
+static jobject GetThreadStack(const ScopedFastNativeObjectAccess& soa, jobject peer)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  jobject trace = nullptr;
+  if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
+    trace = soa.Self()->CreateInternalStackTrace(soa);
   } else {
-    if (timed_out) {
-      LOG(ERROR) << "Trying to get thread's stack failed as the thread failed to suspend within a "
-          "generous timeout.";
+    // Suspend thread to build stack trace.
+    soa.Self()->TransitionFromRunnableToSuspended(kNative);
+    bool timed_out;
+    Thread* thread = ThreadList::SuspendThreadByPeer(peer, true, false, &timed_out);
+    if (thread != nullptr) {
+      // Must be runnable to create returned array.
+      CHECK_EQ(soa.Self()->TransitionFromSuspendedToRunnable(), kNative);
+      trace = thread->CreateInternalStackTrace(soa);
+      soa.Self()->TransitionFromRunnableToSuspended(kNative);
+      // Restart suspended thread.
+      Runtime::Current()->GetThreadList()->Resume(thread, false);
+    } else {
+      if (timed_out) {
+        LOG(ERROR) << "Trying to get thread's stack failed as the thread failed to suspend within a "
+            "generous timeout.";
+      }
     }
-    return NULL;
+    CHECK_EQ(soa.Self()->TransitionFromSuspendedToRunnable(), kNative);
   }
+  return trace;
 }
 
 static jint VMStack_fillStackTraceElements(JNIEnv* env, jclass, jobject javaThread,
                                            jobjectArray javaSteArray) {
-  jobject trace = GetThreadStack(env, javaThread);
-  if (trace == NULL) {
+  ScopedFastNativeObjectAccess soa(env);
+  jobject trace = GetThreadStack(soa, javaThread);
+  if (trace == nullptr) {
     return 0;
   }
   int32_t depth;
-  Thread::InternalStackTraceToStackTraceElementArray(env, trace, javaSteArray, &depth);
+  Thread::InternalStackTraceToStackTraceElementArray(soa, trace, javaSteArray, &depth);
   return depth;
 }
 
@@ -111,19 +112,20 @@
 }
 
 static jobjectArray VMStack_getThreadStackTrace(JNIEnv* env, jclass, jobject javaThread) {
-  jobject trace = GetThreadStack(env, javaThread);
-  if (trace == NULL) {
-    return NULL;
+  ScopedFastNativeObjectAccess soa(env);
+  jobject trace = GetThreadStack(soa, javaThread);
+  if (trace == nullptr) {
+    return nullptr;
   }
-  return Thread::InternalStackTraceToStackTraceElementArray(env, trace);
+  return Thread::InternalStackTraceToStackTraceElementArray(soa, trace);
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(VMStack, fillStackTraceElements, "(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I"),
+  NATIVE_METHOD(VMStack, fillStackTraceElements, "!(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I"),
   NATIVE_METHOD(VMStack, getCallingClassLoader, "!()Ljava/lang/ClassLoader;"),
   NATIVE_METHOD(VMStack, getClosestUserClassLoader, "!(Ljava/lang/ClassLoader;Ljava/lang/ClassLoader;)Ljava/lang/ClassLoader;"),
   NATIVE_METHOD(VMStack, getStackClass2, "!()Ljava/lang/Class;"),
-  NATIVE_METHOD(VMStack, getThreadStackTrace, "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;"),
+  NATIVE_METHOD(VMStack, getThreadStackTrace, "!(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;"),
 };
 
 void register_dalvik_system_VMStack(JNIEnv* env) {
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 8bf36e7..6daf9a9 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -45,7 +45,7 @@
 // "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
 static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize,
                                  jobject javaLoader) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   ScopedUtfChars name(env, javaName);
   if (name.c_str() == nullptr) {
     return nullptr;
@@ -96,7 +96,7 @@
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
+  NATIVE_METHOD(Class, classForName, "!(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
   NATIVE_METHOD(Class, getNameNative, "!()Ljava/lang/String;"),
   NATIVE_METHOD(Class, getProxyInterfaces, "!()[Ljava/lang/Class;"),
 };
diff --git a/runtime/native/java_lang_Runtime.cc b/runtime/native/java_lang_Runtime.cc
index f6149ff..636be5d 100644
--- a/runtime/native/java_lang_Runtime.cc
+++ b/runtime/native/java_lang_Runtime.cc
@@ -92,12 +92,12 @@
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(Runtime, freeMemory, "()J"),
+  NATIVE_METHOD(Runtime, freeMemory, "!()J"),
   NATIVE_METHOD(Runtime, gc, "()V"),
-  NATIVE_METHOD(Runtime, maxMemory, "()J"),
+  NATIVE_METHOD(Runtime, maxMemory, "!()J"),
   NATIVE_METHOD(Runtime, nativeExit, "(I)V"),
   NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/String;"),
-  NATIVE_METHOD(Runtime, totalMemory, "()J"),
+  NATIVE_METHOD(Runtime, totalMemory, "!()J"),
 };
 
 void register_java_lang_Runtime(JNIEnv* env) {
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index 2665a08..de1b593 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -38,7 +38,7 @@
 }
 
 static jboolean Thread_isInterrupted(JNIEnv* env, jobject java_thread) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
   Thread* thread = Thread::FromManagedThread(soa, java_thread);
   return (thread != NULL) ? thread->IsInterrupted() : JNI_FALSE;
@@ -170,8 +170,8 @@
 
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(Thread, currentThread, "!()Ljava/lang/Thread;"),
-  NATIVE_METHOD(Thread, interrupted, "()Z"),
-  NATIVE_METHOD(Thread, isInterrupted, "()Z"),
+  NATIVE_METHOD(Thread, interrupted, "!()Z"),
+  NATIVE_METHOD(Thread, isInterrupted, "!()Z"),
   NATIVE_METHOD(Thread, nativeCreate, "(Ljava/lang/Thread;JZ)V"),
   NATIVE_METHOD(Thread, nativeGetStatus, "(Z)I"),
   NATIVE_METHOD(Thread, nativeHoldsLock, "(Ljava/lang/Object;)Z"),
diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
index 332a130..d1a1105 100644
--- a/runtime/native/java_lang_Throwable.cc
+++ b/runtime/native/java_lang_Throwable.cc
@@ -15,26 +15,27 @@
  */
 
 #include "jni_internal.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
 #include "thread.h"
 
 namespace art {
 
 static jobject Throwable_nativeFillInStackTrace(JNIEnv* env, jclass) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   return soa.Self()->CreateInternalStackTrace(soa);
 }
 
 static jobjectArray Throwable_nativeGetStackTrace(JNIEnv* env, jclass, jobject javaStackState) {
-  if (javaStackState == NULL) {
-      return NULL;
+  if (javaStackState == nullptr) {
+      return nullptr;
   }
-  return Thread::InternalStackTraceToStackTraceElementArray(env, javaStackState);
+  ScopedFastNativeObjectAccess soa(env);
+  return Thread::InternalStackTraceToStackTraceElementArray(soa, javaStackState);
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(Throwable, nativeFillInStackTrace, "()Ljava/lang/Object;"),
-  NATIVE_METHOD(Throwable, nativeGetStackTrace, "(Ljava/lang/Object;)[Ljava/lang/StackTraceElement;"),
+  NATIVE_METHOD(Throwable, nativeFillInStackTrace, "!()Ljava/lang/Object;"),
+  NATIVE_METHOD(Throwable, nativeGetStackTrace, "!(Ljava/lang/Object;)[Ljava/lang/StackTraceElement;"),
 };
 
 void register_java_lang_Throwable(JNIEnv* env) {
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 314cdb1..cb8e623 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -18,14 +18,14 @@
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
 #include "ScopedUtfChars.h"
 #include "zip_archive.h"
 
 namespace art {
 
 static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader, jstring javaName) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
   ScopedUtfChars name(env, javaName);
   if (name.c_str() == NULL) {
@@ -89,9 +89,9 @@
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(VMClassLoader, findLoadedClass, "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;"),
+  NATIVE_METHOD(VMClassLoader, findLoadedClass, "!(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;"),
   NATIVE_METHOD(VMClassLoader, getBootClassPathResource, "(Ljava/lang/String;I)Ljava/lang/String;"),
-  NATIVE_METHOD(VMClassLoader, getBootClassPathSize, "()I"),
+  NATIVE_METHOD(VMClassLoader, getBootClassPathSize, "!()I"),
 };
 
 void register_java_lang_VMClassLoader(JNIEnv* env) {
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index c06bf4c..a22d7ca 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -22,7 +22,7 @@
 #include "mirror/object-inl.h"
 #include "object_utils.h"
 #include "reflection.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
 #include "well_known_classes.h"
 
 namespace art {
@@ -35,8 +35,7 @@
  * with an interface, array, or primitive class.
  */
 static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) {
-  // TODO: ScopedFastNativeObjectAccess
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   jobject art_method = soa.Env()->GetObjectField(
       javaMethod, WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
 
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 694f5e4..7e21d6c 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -90,7 +90,7 @@
 
   class_or_rcvr = soa.Decode<mirror::Object*>(j_rcvr);
   mirror::Class* declaringClass = f->GetDeclaringClass();
-  if (!VerifyObjectInClass(class_or_rcvr, declaringClass)) {
+  if (!VerifyObjectIsClass(class_or_rcvr, declaringClass)) {
     return false;
   }
   return true;
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index d29de3d..0b8bb7b 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -24,19 +24,19 @@
 #include "mirror/proxy.h"
 #include "object_utils.h"
 #include "reflection.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
 #include "well_known_classes.h"
 
 namespace art {
 
 static jobject Method_invoke(JNIEnv* env,
                              jobject javaMethod, jobject javaReceiver, jobject javaArgs) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
 }
 
 static jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   jobject art_method = soa.Env()->GetObjectField(
       javaMethod, WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
 
@@ -59,8 +59,8 @@
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(Method, invoke, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
-  NATIVE_METHOD(Method, getExceptionTypesNative, "()[Ljava/lang/Class;"),
+  NATIVE_METHOD(Method, invoke, "!(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
+  NATIVE_METHOD(Method, getExceptionTypesNative, "!()[Ljava/lang/Class;"),
 };
 
 void register_java_lang_reflect_Method(JNIEnv* env) {
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index 1266c41..07d670d 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -19,14 +19,14 @@
 #include "mirror/class_loader.h"
 #include "mirror/object_array.h"
 #include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
 #include "verify_object-inl.h"
 
 namespace art {
 
 static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces,
                                   jobject loader, jobjectArray methods, jobjectArray throws) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   mirror::Class* result = class_linker->CreateProxyClass(soa, name, interfaces, loader, methods,
                                                          throws);
@@ -34,7 +34,7 @@
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(Proxy, generateProxy, "(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/ArtMethod;[[Ljava/lang/Class;)Ljava/lang/Class;"),
+  NATIVE_METHOD(Proxy, generateProxy, "!(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/ArtMethod;[[Ljava/lang/Class;)Ljava/lang/Class;"),
 };
 
 void register_java_lang_reflect_Proxy(JNIEnv* env) {
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 4f81a0b..1b9ebe4 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -18,7 +18,7 @@
 #include "base/mutex.h"
 #include "debugger.h"
 #include "jni_internal.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "stack.h"
@@ -31,7 +31,7 @@
 }
 
 static jbyteArray DdmVmInternal_getRecentAllocations(JNIEnv* env, jclass) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   return Dbg::GetRecentAllocations();
 }
 
@@ -46,24 +46,24 @@
 static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint thin_lock_id) {
   // Suspend thread to build stack trace.
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
+  jobjectArray trace = nullptr;
   bool timed_out;
   Thread* thread = thread_list->SuspendThreadByThreadId(thin_lock_id, false, &timed_out);
   if (thread != NULL) {
-    jobject trace;
     {
       ScopedObjectAccess soa(env);
-      trace = thread->CreateInternalStackTrace(soa);
+      jobject internal_trace = thread->CreateInternalStackTrace(soa);
+      trace = Thread::InternalStackTraceToStackTraceElementArray(soa, internal_trace);
     }
     // Restart suspended thread.
     thread_list->Resume(thread, false);
-    return Thread::InternalStackTraceToStackTraceElementArray(env, trace);
   } else {
     if (timed_out) {
       LOG(ERROR) << "Trying to get thread's stack by id failed as the thread failed to suspend "
           "within a generous timeout.";
     }
-    return NULL;
   }
+  return trace;
 }
 
 static void ThreadCountCallback(Thread*, void* context) {
@@ -136,7 +136,7 @@
 }
 
 static jint DdmVmInternal_heapInfoNotify(JNIEnv* env, jclass, jint when) {
-  ScopedObjectAccess soa(env);
+  ScopedFastNativeObjectAccess soa(env);
   return Dbg::DdmHandleHpifChunk(static_cast<Dbg::HpifWhen>(when));
 }
 
@@ -150,11 +150,11 @@
 
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(DdmVmInternal, enableRecentAllocations, "(Z)V"),
-  NATIVE_METHOD(DdmVmInternal, getRecentAllocations, "()[B"),
-  NATIVE_METHOD(DdmVmInternal, getRecentAllocationStatus, "()Z"),
+  NATIVE_METHOD(DdmVmInternal, getRecentAllocations, "!()[B"),
+  NATIVE_METHOD(DdmVmInternal, getRecentAllocationStatus, "!()Z"),
   NATIVE_METHOD(DdmVmInternal, getStackTraceById, "(I)[Ljava/lang/StackTraceElement;"),
   NATIVE_METHOD(DdmVmInternal, getThreadStats, "()[B"),
-  NATIVE_METHOD(DdmVmInternal, heapInfoNotify, "(I)Z"),
+  NATIVE_METHOD(DdmVmInternal, heapInfoNotify, "!(I)Z"),
   NATIVE_METHOD(DdmVmInternal, heapSegmentNotify, "(IIZ)Z"),
   NATIVE_METHOD(DdmVmInternal, threadNotify, "(Z)V"),
 };
diff --git a/runtime/native/scoped_fast_native_object_access.h b/runtime/native/scoped_fast_native_object_access.h
index 645d78c..744ac05 100644
--- a/runtime/native/scoped_fast_native_object_access.h
+++ b/runtime/native/scoped_fast_native_object_access.h
@@ -17,22 +17,19 @@
 #ifndef ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
 #define ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
 
-#include "base/casts.h"
-#include "jni_internal.h"
-#include "thread-inl.h"
 #include "mirror/art_method.h"
-#include "verify_object.h"
+#include "scoped_thread_state_change.h"
 
 namespace art {
 
 // Variant of ScopedObjectAccess that does no runnable transitions. Should only be used by "fast"
 // JNI methods.
-class ScopedFastNativeObjectAccess {
+class ScopedFastNativeObjectAccess : public ScopedObjectAccess {
  public:
   explicit ScopedFastNativeObjectAccess(JNIEnv* env)
     LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
     SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
-     : env_(down_cast<JNIEnvExt*>(env)), self_(ThreadForEnv(env)) {
+     : ScopedObjectAccess(env) {
     Locks::mutator_lock_->AssertSharedHeld(Self());
     DCHECK((*Self()->GetManagedStack()->GetTopQuickFrame())->IsFastNative());
     // Don't work with raw objects in non-runnable states.
@@ -42,57 +39,8 @@
   ~ScopedFastNativeObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
   }
 
-  Thread* Self() const {
-    return self_;
-  }
-
-  JNIEnvExt* Env() const {
-    return env_;
-  }
-
-  template<typename T>
-  T Decode(jobject obj) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    // Don't work with raw objects in non-runnable states.
-    DCHECK_EQ(Self()->GetState(), kRunnable);
-    return down_cast<T>(Self()->DecodeJObject(obj));
-  }
-
-  mirror::ArtField* DecodeField(jfieldID fid) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    // Don't work with raw objects in non-runnable states.
-    DCHECK_EQ(Self()->GetState(), kRunnable);
-    return reinterpret_cast<mirror::ArtField*>(fid);
-  }
-
-  /*
-   * Variant of ScopedObjectAccessUnched::AddLocalReference that without JNI work arounds
-   * or check JNI that should be being used by fast native methods.
-   */
-  template<typename T>
-  T AddLocalReference(mirror::Object* obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    Locks::mutator_lock_->AssertSharedHeld(Self());
-    // Don't work with raw objects in non-runnable states.
-    DCHECK_EQ(Self()->GetState(), kRunnable);
-    if (obj == NULL) {
-      return NULL;
-    }
-
-    DCHECK_NE((reinterpret_cast<uintptr_t>(obj) & 0xffff0000), 0xebad0000);
-
-    IndirectReferenceTable& locals = Env()->locals;
-
-    uint32_t cookie = Env()->local_ref_cookie;
-    IndirectRef ref = locals.Add(cookie, obj);
-
-    return reinterpret_cast<T>(ref);
-  }
-
  private:
-  JNIEnvExt* const env_;
-  Thread* const self_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedFastNativeObjectAccess);
 };
 
 }  // namespace art