Merge "Make valgrind happier and stop us leaking so much we can can't run the tests on a device." into dalvik-dev
diff --git a/src/assembler.cc b/src/assembler.cc
index 193d73f..9e67f12 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -67,6 +67,7 @@
 
 
 AssemblerBuffer::~AssemblerBuffer() {
+  delete[] contents_;
 }
 
 
diff --git a/src/class_linker.cc b/src/class_linker.cc
index f37df3f..2f1a5d7 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -84,10 +84,13 @@
   // mark as non-primitive for object_array_class
   java_lang_Object->primitive_type_ = Class::kPrimNot;
 
-  // object_array_class is for root_classes to provide the storage for these classes
+  // Object[] is for DexCache and int[] is for various Class members.
   Class* object_array_class = AllocClass(java_lang_Class, sizeof(Class));
   CHECK(object_array_class != NULL);
   object_array_class->component_type_ = java_lang_Object;
+  Class* int_array_class = AllocClass(java_lang_Class, sizeof(Class));
+  CHECK(int_array_class != NULL);
+  IntArray::SetArrayClass(int_array_class);
 
   // String and char[] are necessary so that FindClass can assign names to members
   Class* java_lang_String = AllocClass(java_lang_Class, sizeof(StringClass));
@@ -106,6 +109,7 @@
   object_array_class->descriptor_ = String::AllocFromModifiedUtf8("[Ljava/lang/Object;");
   java_lang_String->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/String;");
   char_array_class->descriptor_ = String::AllocFromModifiedUtf8("[C");
+  int_array_class->descriptor_ = String::AllocFromModifiedUtf8("[I");
 
   // Field and Method are necessary so that FindClass can link members
   Class* java_lang_reflect_Field = AllocClass(java_lang_Class, sizeof(FieldClass));
@@ -126,6 +130,7 @@
   SetClassRoot(kObjectArrayClass, object_array_class);
   SetClassRoot(kJavaLangString, java_lang_String);
   SetClassRoot(kCharArrayClass, char_array_class);
+  SetClassRoot(kIntArrayClass, int_array_class);
   SetClassRoot(kJavaLangReflectField, java_lang_reflect_Field);
   SetClassRoot(kJavaLangReflectMethod, java_lang_reflect_Method);
   // now that these are registered, we can use AllocClass() and AllocObjectArray
@@ -218,9 +223,11 @@
   SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V"));
   // now we can use FindSystemClass for anything, including for "[C"
 
-  // run char[], int[] and long[] through FindClass to complete initialization
+  // run char[] and int[] through FindClass to complete initialization
   Class* found_char_array_class = FindSystemClass("[C");
   CHECK_EQ(char_array_class, found_char_array_class);
+  Class* found_int_array_class = FindSystemClass("[I");
+  CHECK_EQ(int_array_class, found_int_array_class);
 
   // Initialize all the other primitive array types for PrimitiveArray::Alloc.
   // These are easy because everything we need has already been set up.
@@ -228,14 +235,12 @@
   SetClassRoot(kByteArrayClass, FindSystemClass("[B"));
   SetClassRoot(kDoubleArrayClass, FindSystemClass("[D"));
   SetClassRoot(kFloatArrayClass, FindSystemClass("[F"));
-  SetClassRoot(kIntArrayClass, FindSystemClass("[I"));
   SetClassRoot(kLongArrayClass, FindSystemClass("[J"));
   SetClassRoot(kShortArrayClass, FindSystemClass("[S"));
   BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
   ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
   DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
   FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
-  IntArray::SetArrayClass(GetClassRoot(kIntArrayClass));
   LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
   ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
 
@@ -702,10 +707,10 @@
     DCHECK(klass->interfaces_ == NULL);
     klass->interfaces_ = AllocObjectArray<Class>(list->Size());
     DCHECK(klass->interfaces_type_idx_ == NULL);
-    klass->interfaces_type_idx_ = new uint32_t[list->Size()];
+    klass->interfaces_type_idx_ = IntArray::Alloc(list->Size());
     for (size_t i = 0; i < list->Size(); ++i) {
       const DexFile::TypeItem& type_item = list->GetTypeItem(i);
-      klass->interfaces_type_idx_[i] = type_item.type_idx_;
+      klass->interfaces_type_idx_->Set(i, type_item.type_idx_);
     }
   }
 }
@@ -902,6 +907,8 @@
       new_class = GetClassRoot(kObjectArrayClass);
     } else if (descriptor == "[C") {
       new_class = GetClassRoot(kCharArrayClass);
+    } else if (descriptor == "[I") {
+      new_class = GetClassRoot(kIntArrayClass);
     }
   }
   if (new_class == NULL) {
@@ -1343,7 +1350,7 @@
   }
   if (klass->NumInterfaces() > 0) {
     for (size_t i = 0; i < klass->NumInterfaces(); ++i) {
-      uint32_t type_idx = klass->interfaces_type_idx_[i];
+      uint32_t type_idx = klass->interfaces_type_idx_->Get(i);
       klass->SetInterface(i, ResolveType(dex_file, type_idx, klass));
       if (klass->GetInterface(i) == NULL) {
         LG << "Failed to resolve interface";
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 3998140..f31586d 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -163,9 +163,11 @@
   copy->virtual_methods_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->virtual_methods_));
   copy->vtable_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->vtable_));
   // TODO: convert iftable_ to heap allocated storage
+  // TODO: convert ifvi_pool_ to heap allocated storage
   copy->ifields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->ifields_));
   // TODO: convert source_file_ to heap allocated storage
   copy->sfields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->sfields_));
+  copy->interfaces_type_idx_ = down_cast<IntArray*>(GetImageAddress(orig->interfaces_type_idx_));
   FixupStaticFields(orig, copy);
 }
 
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 1746cc3..89519c4 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -2580,6 +2580,9 @@
   functions = &gNativeInterface;
 }
 
+JNIEnvExt::~JNIEnvExt() {
+}
+
 // JNI Invocation interface.
 
 extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, void** p_env, void* vm_args) {
diff --git a/src/jni_internal.h b/src/jni_internal.h
index fec84ea..c8a5a39 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -61,6 +61,7 @@
 
 struct JNIEnvExt : public JNIEnv {
   JNIEnvExt(Thread* self, JavaVMExt* vm);
+  ~JNIEnvExt();
 
   Thread* self;
   JavaVMExt* vm;
diff --git a/src/main.cc b/src/main.cc
index 0330d0d..2056b0b 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -11,25 +11,7 @@
 #include "toStringArray.h"
 #include "ScopedLocalRef.h"
 
-// TODO: move this into the runtime.
-static void BlockSigpipe() {
-  sigset_t sigset;
-  if (sigemptyset(&sigset) == -1) {
-    PLOG(ERROR) << "sigemptyset failed";
-    return;
-  }
-  if (sigaddset(&sigset, SIGPIPE) == -1) {
-    PLOG(ERROR) << "sigaddset failed";
-    return;
-  }
-  if (sigprocmask(SIG_BLOCK, &sigset, NULL) == -1) {
-    PLOG(ERROR) << "sigprocmask failed";
-  }
-}
-
 // Determine whether or not the specified method is public.
-//
-// Returns JNI_TRUE on success, JNI_FALSE on failure.
 static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) {
   ScopedLocalRef<jobject> reflected(env, env->ToReflectedMethod(clazz,
       method_id, JNI_FALSE));
@@ -54,7 +36,7 @@
   }
   static const int PUBLIC = 0x0001;   // java.lang.reflect.Modifiers.PUBLIC
 #if 0 // CallIntMethod not yet implemented
-  int modifiers = env->CallIntMethod(method.get(), get_modifiers);
+  int modifiers = env->CallIntMethod(reflected.get(), get_modifiers);
 #else
   int modifiers = PUBLIC;
   UNIMPLEMENTED(WARNING) << "assuming main is public...";
@@ -65,13 +47,13 @@
   return true;
 }
 
-static bool InvokeMain(JNIEnv* env, int argc, char** argv) {
+static void InvokeMain(JNIEnv* env, int argc, char** argv) {
   // We want to call main() with a String array with our arguments in
   // it.  Create an array and populate it.  Note argv[0] is not
   // included.
   ScopedLocalRef<jobjectArray> args(env, toStringArray(env, argv + 1));
   if (args.get() == NULL) {
-    return false;
+    return;
   }
 
   // Find [class].main(String[]).
@@ -83,7 +65,7 @@
   ScopedLocalRef<jclass> klass(env, env->FindClass(class_name.c_str()));
   if (klass.get() == NULL) {
     fprintf(stderr, "Unable to locate class '%s'\n", class_name.c_str());
-    return false;
+    return;
   }
 
   jmethodID method = env->GetStaticMethodID(klass.get(),
@@ -92,24 +74,18 @@
   if (method == NULL) {
     fprintf(stderr, "Unable to find static main(String[]) in '%s'\n",
             class_name.c_str());
-    return false;
+    return;
   }
 
   // Make sure the method is public.  JNI doesn't prevent us from
   // calling a private method, so we have to check it explicitly.
   if (!IsMethodPublic(env, klass.get(), method)) {
     fprintf(stderr, "Sorry, main() is not public\n");
-    return false;
+    return;
   }
 
   // Invoke main().
-
   env->CallStaticVoidMethod(klass.get(), method, args.get());
-  if (env->ExceptionCheck()) {
-    return false;
-  } else {
-    return true;
-  }
 }
 
 // Parse arguments.  Most of it just gets passed through to the VM.
@@ -173,8 +149,6 @@
   init_args.nOptions = curr_opt;
   init_args.ignoreUnrecognized = JNI_FALSE;
 
-  BlockSigpipe();
-
   // Start VM.  The current thread becomes the main thread of the VM.
   JavaVM* vm = NULL;
   JNIEnv* env = NULL;
@@ -183,17 +157,21 @@
     return EXIT_FAILURE;
   }
 
-  bool success = InvokeMain(env, argc - arg_idx, &argv[arg_idx]);
+  InvokeMain(env, argc - arg_idx, &argv[arg_idx]);
+  int rc = env->ExceptionCheck() ? EXIT_FAILURE : EXIT_SUCCESS;
+  if (rc == EXIT_FAILURE) {
+    env->ExceptionDescribe();
+  }
 
   if (vm->DetachCurrentThread() != JNI_OK) {
     fprintf(stderr, "Warning: unable to detach main thread\n");
-    success = false;
+    rc = EXIT_FAILURE;
   }
 
   if (vm->DestroyJavaVM() != 0) {
     fprintf(stderr, "Warning: VM did not shut down cleanly\n");
-    success = false;
+    rc = EXIT_FAILURE;
   }
 
-  return success ? EXIT_SUCCESS : EXIT_FAILURE;
+  return rc;
 }
diff --git a/src/object.cc b/src/object.cc
index bb60dc1..d06c3e3 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -538,6 +538,7 @@
 
 template<typename T>
 PrimitiveArray<T>* PrimitiveArray<T>::Alloc(size_t length) {
+  DCHECK(array_class_ != NULL);
   Array* raw_array = Array::Alloc(array_class_, length, sizeof(T));
   return down_cast<PrimitiveArray<T>*>(raw_array);
 }
diff --git a/src/object.h b/src/object.h
index f3cd0fd..2657872 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1276,7 +1276,7 @@
 
   // array of interfaces this class implements directly
   ObjectArray<Class>* interfaces_;
-  uint32_t* interfaces_type_idx_;
+  IntArray* interfaces_type_idx_;
 
   // static, private, and <init> methods
   ObjectArray<Method>* direct_methods_;
diff --git a/src/reference_table.cc b/src/reference_table.cc
index b5c988a..ebdb7bc 100644
--- a/src/reference_table.cc
+++ b/src/reference_table.cc
@@ -29,6 +29,9 @@
   entries_.reserve(initial_size);
 }
 
+ReferenceTable::~ReferenceTable() {
+}
+
 void ReferenceTable::Add(const Object* obj) {
   DCHECK(obj != NULL);
   if (entries_.size() == max_size_) {
diff --git a/src/reference_table.h b/src/reference_table.h
index 15a2e11..13317ea 100644
--- a/src/reference_table.h
+++ b/src/reference_table.h
@@ -33,6 +33,7 @@
 class ReferenceTable {
  public:
   ReferenceTable(const char* name, size_t initial_size, size_t max_size);
+  ~ReferenceTable();
 
   void Add(const Object* obj);
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 30395e1..80914db 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -24,6 +24,7 @@
   Heap::Destroy();
   delete thread_list_;
   delete java_vm_;
+  Thread::Shutdown();
   // TODO: acquire a static mutex on Runtime to avoid racing.
   CHECK(instance_ == NULL || instance_ == this);
   instance_ = NULL;
@@ -324,7 +325,7 @@
 }
 
 bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
-  CHECK_EQ(kPageSize, sysconf(_SC_PAGE_SIZE));
+  CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
 
   scoped_ptr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized));
   if (options == NULL) {
@@ -343,10 +344,12 @@
     return false;
   }
 
+  BlockSignals();
+
   bool verbose_jni = options->verbose_.find("jni") != options->verbose_.end();
   java_vm_ = new JavaVMExt(this, options->check_jni_, verbose_jni);
 
-  if (!Thread::Init()) {
+  if (!Thread::Startup()) {
     return false;
   }
   Thread* current_thread = Thread::Attach(this);
@@ -357,6 +360,25 @@
   return true;
 }
 
+void Runtime::BlockSignals() {
+  sigset_t sigset;
+  if (sigemptyset(&sigset) == -1) {
+    PLOG(FATAL) << "sigemptyset failed";
+  }
+  if (sigaddset(&sigset, SIGPIPE) == -1) {
+    PLOG(ERROR) << "sigaddset SIGPIPE failed";
+  }
+  // SIGQUIT is used to dump the runtime's state (including stack traces).
+  if (sigaddset(&sigset, SIGQUIT) == -1) {
+    PLOG(ERROR) << "sigaddset SIGQUIT failed";
+  }
+  // SIGUSR1 is used to initiate a heap dump.
+  if (sigaddset(&sigset, SIGUSR1) == -1) {
+    PLOG(ERROR) << "sigaddset SIGUSR1 failed";
+  }
+  CHECK_EQ(sigprocmask(SIG_BLOCK, &sigset, NULL), 0);
+}
+
 bool Runtime::AttachCurrentThread(const char* name, JNIEnv** penv, bool as_daemon) {
   if (as_daemon) {
     UNIMPLEMENTED(WARNING) << "TODO: do something different for daemon threads";
@@ -365,7 +387,9 @@
 }
 
 bool Runtime::DetachCurrentThread() {
-  UNIMPLEMENTED(WARNING);
+  Thread* self = Thread::Current();
+  thread_list_->Unregister(self);
+  delete self;
   return true;
 }
 
diff --git a/src/runtime.h b/src/runtime.h
index 323c6c8..b6873e3 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -95,7 +95,8 @@
 
   Runtime() : stack_size_(0), thread_list_(NULL), class_linker_(NULL) {}
 
-  // Initializes a new uninitialized runtime.
+  void BlockSignals();
+
   bool Init(const Options& options, bool ignore_unrecognized);
 
   // The default stack size for managed threads created by the runtime.
diff --git a/src/thread.cc b/src/thread.cc
index ef8501a..40aaa7d 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -172,7 +172,7 @@
 
   errno = pthread_setspecific(Thread::pthread_key_self_, thread);
   if (errno != 0) {
-      PLOG(FATAL) << "pthread_setspecific failed";
+    PLOG(FATAL) << "pthread_setspecific failed";
   }
 
   thread->jni_env_ = new JNIEnvExt(thread, runtime->GetJavaVM());
@@ -184,9 +184,10 @@
   LG << "Thread exit check";
 }
 
-bool Thread::Init() {
+bool Thread::Startup() {
   // Allocate a TLS slot.
-  if (pthread_key_create(&Thread::pthread_key_self_, ThreadExitCheck) != 0) {
+  errno = pthread_key_create(&Thread::pthread_key_self_, ThreadExitCheck);
+  if (errno != 0) {
     PLOG(WARNING) << "pthread_key_create failed";
     return false;
   }
@@ -202,6 +203,17 @@
   return true;
 }
 
+void Thread::Shutdown() {
+  errno = pthread_key_delete(Thread::pthread_key_self_);
+  if (errno != 0) {
+    PLOG(WARNING) << "pthread_key_delete failed";
+  }
+}
+
+Thread::~Thread() {
+  delete jni_env_;
+}
+
 size_t Thread::NumSirtReferences() {
   size_t count = 0;
   for (StackIndirectReferenceTable* cur = top_sirt_; cur; cur = cur->Link()) {
@@ -404,26 +416,33 @@
 }
 
 ThreadList::~ThreadList() {
-  // Make sure that all threads have exited and unregistered when we
+  if (Contains(Thread::Current())) {
+    Runtime::Current()->DetachCurrentThread();
+  }
+
+  // All threads should have exited and unregistered when we
   // reach this point. This means that all daemon threads had been
   // shutdown cleanly.
-  CHECK_LE(list_.size(), 1U);
-  // TODO: wait for all other threads to unregister
-  CHECK(list_.size() == 0 || list_.front() == Thread::Current());
-  // TODO: detach the current thread
+  // TODO: dump ThreadList if non-empty.
+  CHECK_EQ(list_.size(), 0U);
+
   delete lock_;
   lock_ = NULL;
 }
 
+bool ThreadList::Contains(Thread* thread) {
+  return find(list_.begin(), list_.end(), thread) != list_.end();
+}
+
 void ThreadList::Register(Thread* thread) {
   MutexLock mu(lock_);
-  CHECK(find(list_.begin(), list_.end(), thread) == list_.end());
+  CHECK(!Contains(thread));
   list_.push_front(thread);
 }
 
 void ThreadList::Unregister(Thread* thread) {
   MutexLock mu(lock_);
-  CHECK(find(list_.begin(), list_.end(), thread) != list_.end());
+  CHECK(Contains(thread));
   list_.remove(thread);
 }
 
diff --git a/src/thread.h b/src/thread.h
index 7609b40..ac1d7e3 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -293,7 +293,8 @@
 
   void Resume();
 
-  static bool Init();
+  static bool Startup();
+  static void Shutdown();
 
   State GetState() const {
     return state_;
@@ -398,9 +399,8 @@
     InitFunctionPointers();
   }
 
-  ~Thread() {
-    delete jni_env_;
-  }
+  ~Thread();
+  friend class Runtime; // For ~Thread.
 
   void InitCpu();
   void InitFunctionPointers();
@@ -489,6 +489,8 @@
 
   void Unregister(Thread* thread);
 
+  bool Contains(Thread* thread);
+
   void Lock() {
     lock_->Lock();
   }