Implement most of VMStack and some of Zygote.

Change-Id: I07e18259a0452a2a9b077148f4f1ca67d3f63427
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 0f12340..b115e2e 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -86,8 +86,10 @@
 	src/compiler/codegen/arm/Assemble.cc \
 	src/compiler/codegen/arm/LocalOptimizations.cc \
 	src/compiler/codegen/arm/armv7-a/Codegen.cc \
+	src/dalvik_system_VMDebug.cc \
 	src/dalvik_system_VMRuntime.cc \
 	src/dalvik_system_VMStack.cc \
+	src/dalvik_system_Zygote.cc \
 	src/dex_cache.cc \
 	src/dex_file.cc \
 	src/dex_instruction.cc \
@@ -99,7 +101,6 @@
 	src/image_writer.cc \
 	src/indirect_reference_table.cc \
 	src/intern_table.cc \
-	src/dalvik_system_VMDebug.cc \
 	src/java_lang_Class.cc \
 	src/java_lang_Object.cc \
 	src/java_lang_Runtime.cc \
diff --git a/src/dalvik_system_VMRuntime.cc b/src/dalvik_system_VMRuntime.cc
index 1e95637..1bc1e39 100644
--- a/src/dalvik_system_VMRuntime.cc
+++ b/src/dalvik_system_VMRuntime.cc
@@ -88,7 +88,7 @@
 
 jboolean VMRuntime_isDebuggerActive(JNIEnv*, jobject) {
   // TODO: debugger!
-  return false;
+  return JNI_FALSE;
 }
 
 jobjectArray VMRuntime_properties(JNIEnv* env, jobject) {
diff --git a/src/dalvik_system_VMStack.cc b/src/dalvik_system_VMStack.cc
index 2a3f18b..331a64f 100644
--- a/src/dalvik_system_VMStack.cc
+++ b/src/dalvik_system_VMStack.cc
@@ -15,7 +15,9 @@
  */
 
 #include "jni_internal.h"
+#include "class_loader.h"
 #include "object.h"
+#include "thread_list.h"
 
 #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
 
@@ -23,14 +25,58 @@
 
 namespace {
 
-jint VMStack_fillStackTraceElements(JNIEnv* env, jclass, jobject targetThread, jobjectArray javaSteArray) {
-  UNIMPLEMENTED(FATAL);
-  return 0;
+class StackGetter {
+ public:
+  StackGetter(JNIEnv* env, Thread* thread) : env_(env), thread_(thread), trace_(NULL) {
+  }
+
+  static void Callback(void* arg) {
+    reinterpret_cast<StackGetter*>(arg)->Callback();
+  }
+
+  jobject GetTrace() {
+    return trace_;
+  }
+
+ private:
+  void Callback() {
+    trace_ = thread_->CreateInternalStackTrace(env_);
+  }
+
+  JNIEnv* env_;
+  Thread* thread_;
+  jobject trace_;
+};
+
+jobject GetThreadStack(JNIEnv* env, jobject javaThread) {
+  Thread* thread = Thread::FromManagedThread(env, javaThread);
+  if (thread == NULL) {
+    return NULL;
+  }
+  ThreadList* thread_list = Runtime::Current()->GetThreadList();
+  StackGetter stack_getter(env, thread);
+  thread_list->RunWhileSuspended(thread, StackGetter::Callback, &stack_getter);
+  return stack_getter.GetTrace();
+}
+
+jint VMStack_fillStackTraceElements(JNIEnv* env, jclass, jobject javaThread, jobjectArray javaSteArray) {
+  jobject trace = GetThreadStack(env, javaThread);
+  if (trace == NULL) {
+    return 0;
+  }
+  int32_t depth;
+  Thread::InternalStackTraceToStackTraceElementArray(env, trace, javaSteArray, &depth);
+  return depth;
 }
 
 jobject VMStack_getCallingClassLoader(JNIEnv* env, jclass) {
-  UNIMPLEMENTED(WARNING);
-  return NULL;
+  // Returns the defining class loader of the caller's caller.
+  Frame frame = Thread::Current()->GetTopOfStack();
+  frame.Next();
+  frame.Next();
+  Method* callerCaller = frame.GetMethod();
+  const Object* cl = callerCaller->GetDeclaringClass()->GetClassLoader();
+  return AddLocalReference<jobject>(env, cl);
 }
 
 jobjectArray VMStack_getClasses(JNIEnv* env, jclass, jint maxDepth) {
@@ -39,13 +85,22 @@
 }
 
 jclass VMStack_getStackClass2(JNIEnv* env, jclass) {
-  UNIMPLEMENTED(FATAL);
-  return NULL;
+  // Returns the class of the caller's caller's caller.
+  Frame frame = Thread::Current()->GetTopOfStack();
+  frame.Next();
+  frame.Next();
+  frame.Next();
+  Method* callerCallerCaller = frame.GetMethod();
+  Class* c = callerCallerCaller->GetDeclaringClass();
+  return AddLocalReference<jclass>(env, c);
 }
 
-jobjectArray VMStack_getThreadStackTrace(JNIEnv* env, jclass, jobject targetThread) {
-  UNIMPLEMENTED(FATAL);
-  return NULL;
+jobjectArray VMStack_getThreadStackTrace(JNIEnv* env, jclass, jobject javaThread) {
+  jobject trace = GetThreadStack(env, javaThread);
+  if (trace == NULL) {
+    return NULL;
+  }
+  return Thread::InternalStackTraceToStackTraceElementArray(env, trace);
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/src/dalvik_system_Zygote.cc b/src/dalvik_system_Zygote.cc
new file mode 100644
index 0000000..1b98e9b
--- /dev/null
+++ b/src/dalvik_system_Zygote.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni_internal.h"
+#include "JNIHelp.h"
+#include "ScopedUtfChars.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+#include <paths.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+namespace art {
+
+namespace {
+
+void Zygote_nativeExecShell(JNIEnv* env, jclass, jstring javaCommand) {
+  ScopedUtfChars command(env, javaCommand);
+  if (command.c_str() == NULL) {
+    return;
+  }
+  const char *argp[] = {_PATH_BSHELL, "-c", command.c_str(), NULL};
+  LOG(INFO) << "Exec: " << argp[0] << ' ' << argp[1] << ' ' << argp[2];
+
+  execv(_PATH_BSHELL, (char**)argp);
+  exit(127);
+}
+
+static JNINativeMethod gMethods[] = {
+  NATIVE_METHOD(Zygote, nativeExecShell, "(Ljava/lang/String;)V"),
+  //NATIVE_METHOD(Zygote, nativeFork, "()I"),
+  //NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[I)I"),
+  //NATIVE_METHOD(Zygote, nativeForkSystemServer, "(II[II[[IJJ)I"),
+};
+
+}  // namespace
+
+void register_dalvik_system_Zygote(JNIEnv* env) {
+  jniRegisterNativeMethods(env, "dalvik/system/Zygote", gMethods, NELEM(gMethods));
+}
+
+}  // namespace art
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 6c48f5f..ee6c1a0d 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -160,13 +160,11 @@
   Thread* thread = Thread::Current();
   thread->SetTopOfStack(fake_stack, reinterpret_cast<uintptr_t>(method_g_->GetCode()) + 3);
 
-  jobject internal = thread->CreateInternalStackTrace();
-  jobjectArray ste_array =
-      Thread::InternalStackTraceToStackTraceElementArray(internal,
-                                                         thread->GetJniEnv());
+  JNIEnv* env = thread->GetJniEnv();
+  jobject internal = thread->CreateInternalStackTrace(env);
+  jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(env, internal);
   ObjectArray<StackTraceElement>* trace_array =
-      Decode<ObjectArray<StackTraceElement>*>(thread->GetJniEnv(), ste_array);
-
+      Decode<ObjectArray<StackTraceElement>*>(env, ste_array);
 
   ASSERT_TRUE(trace_array->Get(0) != NULL);
   EXPECT_STREQ("java.lang.MyClass",
diff --git a/src/java_lang_Throwable.cc b/src/java_lang_Throwable.cc
index 4c3bfcf..e8a3891 100644
--- a/src/java_lang_Throwable.cc
+++ b/src/java_lang_Throwable.cc
@@ -25,11 +25,11 @@
 
 jobject Throwable_nativeFillInStackTrace(JNIEnv* env, jclass) {
   JNIEnvExt* env_ext = reinterpret_cast<JNIEnvExt*>(env);
-  return env_ext->self->CreateInternalStackTrace();
+  return env_ext->self->CreateInternalStackTrace(env);
 }
 
 jobjectArray Throwable_nativeGetStackTrace(JNIEnv* env, jclass, jobject javaStackState) {
-  return Thread::InternalStackTraceToStackTraceElementArray(javaStackState, env);
+  return Thread::InternalStackTraceToStackTraceElementArray(env, javaStackState);
 }
 
 JNINativeMethod gMethods[] = {
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 4f862d6..fbdf2bf 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -464,9 +464,8 @@
     ScopedJniThreadState ts(env);
 
     // Build stack trace
-    jobject internal = Thread::Current()->CreateInternalStackTrace();
-    jobjectArray ste_array =
-        Thread::InternalStackTraceToStackTraceElementArray(internal, env);
+    jobject internal = Thread::Current()->CreateInternalStackTrace(env);
+    jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(env, internal);
     ObjectArray<StackTraceElement>* trace_array =
         Decode<ObjectArray<StackTraceElement>*>(env, ste_array);
     EXPECT_TRUE(trace_array != NULL);
diff --git a/src/runtime.cc b/src/runtime.cc
index 68f42af..5dc057e 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -455,7 +455,7 @@
   REGISTER(register_dalvik_system_VMDebug);
   REGISTER(register_dalvik_system_VMRuntime);
   REGISTER(register_dalvik_system_VMStack);
-  //REGISTER(register_dalvik_system_Zygote);
+  REGISTER(register_dalvik_system_Zygote);
   REGISTER(register_java_lang_Class);
   REGISTER(register_java_lang_Object);
   REGISTER(register_java_lang_Runtime);
diff --git a/src/thread.cc b/src/thread.cc
index 6eac92b..97f5710 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -56,10 +56,11 @@
 
 // Temporary debugging hook for compiler.
 void DebugMe(Method* method, uint32_t info) {
-    LOG(INFO) << "DebugMe";
-    if (method != NULL)
-        LOG(INFO) << PrettyMethod(method);
-    LOG(INFO) << "Info: " << info;
+  LOG(INFO) << "DebugMe";
+  if (method != NULL) {
+    LOG(INFO) << PrettyMethod(method);
+  }
+  LOG(INFO) << "Info: " << info;
 }
 
 }  // namespace art
@@ -479,6 +480,11 @@
   gThread_vmData->SetInt(managed_thread, reinterpret_cast<uintptr_t>(native_thread));
 }
 
+Thread* Thread::FromManagedThread(JNIEnv* env, jobject java_thread) {
+  Object* thread = Decode<Object*>(env, java_thread);
+  return reinterpret_cast<Thread*>(static_cast<uintptr_t>(gThread_vmData->GetInt(thread)));
+}
+
 void Thread::Create(Object* peer, size_t stack_size) {
   CHECK(peer != NULL);
 
@@ -549,7 +555,8 @@
 }
 
 void Thread::CreatePeer(const char* name, bool as_daemon) {
-  ScopedThreadStateChange tsc(Thread::Current(), Thread::kNative);
+  Thread* self = Thread::Current();
+  ScopedThreadStateChange tsc(self, Thread::kNative);
 
   JNIEnv* env = jni_env_;
 
@@ -563,21 +570,16 @@
   jmethodID mid = env->GetMethodID(c, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
 
   jobject peer = env->NewObject(c, mid, thread_group, thread_name, thread_priority, thread_is_daemon);
+  peer_ = DecodeJObject(peer);
+  SetVmData(peer_, self);
 
   // Because we mostly run without code available (in the compiler, in tests), we
   // manually assign the fields the constructor should have set.
   // TODO: lose this.
-  jfieldID fid;
-  fid = env->GetFieldID(c, "group", "Ljava/lang/ThreadGroup;");
-  env->SetObjectField(peer, fid, thread_group);
-  fid = env->GetFieldID(c, "name", "Ljava/lang/String;");
-  env->SetObjectField(peer, fid, thread_name);
-  fid = env->GetFieldID(c, "priority", "I");
-  env->SetIntField(peer, fid, thread_priority);
-  fid = env->GetFieldID(c, "daemon", "Z");
-  env->SetBooleanField(peer, fid, thread_is_daemon);
-
-  peer_ = DecodeJObject(peer);
+  gThread_daemon->SetBoolean(peer_, thread_is_daemon);
+  gThread_group->SetObject(peer_, Decode<Object*>(env, thread_group));
+  gThread_name->SetObject(peer_, Decode<Object*>(env, thread_name));
+  gThread_priority->SetInt(peer_, thread_priority);
 }
 
 void Thread::InitStackHwm() {
@@ -867,9 +869,6 @@
 }
 
 void Thread::FinishStartup() {
-  // Finish attaching the main thread.
-  Thread::Current()->CreatePeer("main", false);
-
   // Now the ClassLinker is ready, we can find the various Class*, Field*, and Method*s we need.
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Class* boolean_class = class_linker->FindPrimitiveClass('Z');
@@ -892,6 +891,9 @@
   gThreadGroup_removeThread = ThreadGroup_class->FindVirtualMethod("removeThread", "(Ljava/lang/Thread;)V");
   gUncaughtExceptionHandler_uncaughtException =
       UncaughtExceptionHandler_class->FindVirtualMethod("uncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V");
+
+  // Finish attaching the main thread.
+  Thread::Current()->CreatePeer("main", false);
 }
 
 void Thread::Shutdown() {
@@ -1124,8 +1126,7 @@
   explicit BuildInternalStackTraceVisitor(int depth, int skip_depth, ScopedJniThreadState& ts)
       : skip_depth_(skip_depth), count_(0) {
     // Allocate method trace with an extra slot that will hold the PC trace
-    method_trace_ = Runtime::Current()->GetClassLinker()->
-        AllocObjectArray<Object>(depth + 1);
+    method_trace_ = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(depth + 1);
     // Register a local reference as IntArray::Alloc may trigger GC
     local_ref_ = AddLocalReference<jobject>(ts.Env(), method_trace_);
     pc_trace_ = IntArray::Alloc(depth);
@@ -1207,7 +1208,7 @@
   }
 }
 
-jobject Thread::CreateInternalStackTrace() const {
+jobject Thread::CreateInternalStackTrace(JNIEnv* env) const {
   // Compute depth of stack
   CountStackDepthVisitor count_visitor;
   WalkStack(&count_visitor);
@@ -1215,7 +1216,7 @@
   int32_t skip_depth = count_visitor.GetSkipDepth();
 
   // Transition into runnable state to work on Object*/Array*
-  ScopedJniThreadState ts(jni_env_);
+  ScopedJniThreadState ts(env);
 
   // Build internal stack trace
   BuildInternalStackTraceVisitor build_trace_visitor(depth, skip_depth, ts);
@@ -1224,8 +1225,8 @@
   return build_trace_visitor.GetInternalStackTrace();
 }
 
-jobjectArray Thread::InternalStackTraceToStackTraceElementArray(jobject internal,
-                                                                JNIEnv* env) {
+jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, jobject internal,
+    jobjectArray output_array, int* stack_depth) {
   // Transition into runnable state to work on Object*/Array*
   ScopedJniThreadState ts(env);
 
@@ -1237,10 +1238,24 @@
 
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
-  // Create java_trace array and place in local reference table
-  ObjectArray<StackTraceElement>* java_traces =
-      class_linker->AllocStackTraceElementArray(depth);
-  jobjectArray result = AddLocalReference<jobjectArray>(ts.Env(), java_traces);
+  jobjectArray result;
+  ObjectArray<StackTraceElement>* java_traces;
+  if (output_array != NULL) {
+    // Reuse the array we were given.
+    result = output_array;
+    java_traces = reinterpret_cast<ObjectArray<StackTraceElement>*>(Decode<Array*>(env,
+        output_array));
+    // ...adjusting the number of frames we'll write to not exceed the array length.
+    depth = std::min(depth, java_traces->GetLength());
+  } else {
+    // Create java_trace array and place in local reference table
+    java_traces = class_linker->AllocStackTraceElementArray(depth);
+    result = AddLocalReference<jobjectArray>(ts.Env(), java_traces);
+  }
+
+  if (stack_depth != NULL) {
+    *stack_depth = depth;
+  }
 
   for (int32_t i = 0; i < depth; ++i) {
     // Prepare parameters for StackTraceElement(String cls, String method, String file, int line)
diff --git a/src/thread.h b/src/thread.h
index 4e1db6f..446a8ec 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -254,12 +254,7 @@
     return reinterpret_cast<Thread*>(thread);
   }
 
-  static Thread* FromManagedThread(JNIEnv* env, jobject thread) {
-    // TODO: make these more generally available, and cached.
-    jclass java_lang_Thread = env->FindClass("java/lang/Thread");
-    jfieldID fid = env->GetFieldID(java_lang_Thread, "vmData", "I");
-    return reinterpret_cast<Thread*>(static_cast<uintptr_t>(env->GetIntField(thread, fid)));
-  }
+  static Thread* FromManagedThread(JNIEnv* env, jobject thread);
 
   void Dump(std::ostream& os) const;
 
@@ -456,11 +451,14 @@
 
   // Create the internal representation of a stack trace, that is more time
   // and space efficient to compute than the StackTraceElement[]
-  jobject CreateInternalStackTrace() const;
+  jobject CreateInternalStackTrace(JNIEnv* env) const;
 
-  // Convert an internal stack trace representation to a StackTraceElement[]
-  static jobjectArray
-      InternalStackTraceToStackTraceElementArray(jobject internal, JNIEnv* env);
+  // Convert an internal stack trace representation (returned by CreateInternalStackTrace) to a
+  // StackTraceElement[]. If output_array is NULL, a new array is created, otherwise as many
+  // frames as will fit are written into the given array. If stack_depth is non-NULL, it's updated
+  // with the number of valid frames in the returned array.
+  static jobjectArray InternalStackTraceToStackTraceElementArray(JNIEnv* env, jobject internal,
+      jobjectArray output_array = NULL, int* stack_depth = NULL);
 
   void VisitRoots(Heap::RootVisitor* visitor, void* arg) const;
 
diff --git a/src/thread_list.cc b/src/thread_list.cc
index f17414c..8c6185d 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -122,6 +122,29 @@
   //LOG(INFO) << *self << " SuspendAll complete";
 }
 
+void ThreadList::Suspend(Thread* thread) {
+  DCHECK(thread != Thread::Current());
+
+  // TODO: add another thread_suspend_lock_ to avoid GC/debugger races.
+
+  //LOG(INFO) << "Suspend(" << *thread << ") starting...";
+
+  MutexLock mu(thread_list_lock_);
+  if (!Contains(thread)) {
+    return;
+  }
+
+  {
+    MutexLock mu(thread_suspend_count_lock_);
+    ++thread->suspend_count_;
+  }
+
+  thread->WaitUntilSuspended();
+
+  //LOG(INFO) << "Suspend(" << *thread << ") complete";
+}
+
+
 void ThreadList::ResumeAll() {
   Thread* self = Thread::Current();
 
@@ -156,6 +179,45 @@
   //LOG(INFO) << *self << " ResumeAll complete";
 }
 
+void ThreadList::Resume(Thread* thread) {
+  DCHECK(thread != Thread::Current());
+
+  //LOG(INFO) << "Resume(" << *thread << ") starting...";
+
+  {
+    MutexLock mu1(thread_list_lock_);
+    MutexLock mu2(thread_suspend_count_lock_);
+    if (!Contains(thread)) {
+      return;
+    }
+    if (thread->suspend_count_ > 0) {
+      --thread->suspend_count_;
+    } else {
+      LOG(WARNING) << *thread << " suspend count already zero";
+    }
+  }
+
+  {
+    //LOG(INFO) << "Resume(" << *thread << ") waking others";
+    MutexLock mu(thread_suspend_count_lock_);
+    thread_suspend_count_cond_.Broadcast();
+  }
+
+  //LOG(INFO) << "Resume(" << *thread << ") complete";
+}
+
+void ThreadList::RunWhileSuspended(Thread* thread, void (*callback)(void*), void* arg) {
+  DCHECK(thread != NULL);
+  Thread* self = Thread::Current();
+  if (thread != self) {
+    Suspend(thread);
+  }
+  callback(arg);
+  if (thread != self) {
+    Resume(thread);
+  }
+}
+
 void ThreadList::Register(Thread* thread) {
   //LOG(INFO) << "ThreadList::Register() " << *thread;
   MutexLock mu(thread_list_lock_);
diff --git a/src/thread_list.h b/src/thread_list.h
index 32bcf20..7840f71 100644
--- a/src/thread_list.h
+++ b/src/thread_list.h
@@ -31,14 +31,13 @@
   ThreadList();
   ~ThreadList();
 
-  bool Contains(Thread* thread);
-
   void Dump(std::ostream& os);
 
   // Thread suspension support.
   void FullSuspendCheck(Thread* thread);
   void ResumeAll();
   void SuspendAll();
+  void RunWhileSuspended(Thread* thread, void (*callback)(void*), void* arg);
 
   void Register(Thread* thread);
   void Unregister();
@@ -54,7 +53,10 @@
 
   bool AllThreadsAreDaemons();
   uint32_t AllocThreadId();
+  bool Contains(Thread* thread);
   void ReleaseThreadId(uint32_t id);
+  void Resume(Thread* thread);
+  void Suspend(Thread* thread);
   void SuspendAllDaemonThreads();
   void WaitForNonDaemonThreadsToExit();