summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2011-08-25 18:09:09 -0700
committerElliott Hughes <enh@google.com>2011-08-25 18:48:47 -0700
commitc1674ed06662420213441ff2b818f2f71f9098dc (patch)
tree2799982a5059feab2a680ce5d91c276e5852983c
parentbafc342a37e423a19ac05f14800006ea9d67a941 (diff)
downloadart-c1674ed06662420213441ff2b818f2f71f9098dc.zip
art-c1674ed06662420213441ff2b818f2f71f9098dc.tar.gz
art-c1674ed06662420213441ff2b818f2f71f9098dc.tar.bz2
Make valgrind happier and stop us leaking so much we can can't run the tests on a device.
Change-Id: Id8f45dde788fd84c10b0b5807b2d12eae529ba5e
-rw-r--r--src/assembler.cc1
-rw-r--r--src/class_linker.cc21
-rw-r--r--src/image_writer.cc2
-rw-r--r--src/jni_internal.cc3
-rw-r--r--src/jni_internal.h1
-rw-r--r--src/main.cc50
-rw-r--r--src/object.cc1
-rw-r--r--src/object.h2
-rw-r--r--src/reference_table.cc3
-rw-r--r--src/reference_table.h1
-rw-r--r--src/runtime.cc30
-rw-r--r--src/runtime.h3
-rw-r--r--src/thread.cc39
-rw-r--r--src/thread.h10
14 files changed, 105 insertions, 62 deletions
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() {
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 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) {
// 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 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) {
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 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) {
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 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) {
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 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) {
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 @@ void ClassLinker::LoadInterfaces(const DexFile& dex_file,
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 @@ Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor,
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 @@ bool ClassLinker::LoadSuperAndInterfaces(Class* klass, const DexFile& dex_file)
}
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 @@ void ImageWriter::FixupClass(const Class* orig, Class* copy) {
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 @@ JNIEnvExt::JNIEnvExt(Thread* self, JavaVMExt* vm)
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 JavaVMExt : public JavaVM {
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 bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) {
}
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 @@ static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) {
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 @@ static bool InvokeMain(JNIEnv* env, int argc, char** argv) {
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 @@ static bool InvokeMain(JNIEnv* env, int argc, char** argv) {
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 @@ int main(int argc, char** argv) {
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 @@ int main(int argc, char** argv) {
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 @@ Field* Class::FindStaticField(const StringPiece& name, const StringPiece& descri
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 @@ class Class : public Object {
// 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 @@ ReferenceTable::ReferenceTable(const char* name,
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 Object;
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 @@ Runtime::~Runtime() {
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 @@ Runtime* Runtime::Create(const Options& options, bool ignore_unrecognized) {
}
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 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
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 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
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::AttachCurrentThread(const char* name, JNIEnv** penv, bool as_daemo
}
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 @@ class Runtime {
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 @@ Thread* Thread::Attach(const Runtime* runtime) {
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 @@ static void ThreadExitCheck(void* arg) {
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 @@ bool Thread::Init() {
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() {
}
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 @@ class Thread {
void Resume();
- static bool Init();
+ static bool Startup();
+ static void Shutdown();
State GetState() const {
return state_;
@@ -398,9 +399,8 @@ class Thread {
InitFunctionPointers();
}
- ~Thread() {
- delete jni_env_;
- }
+ ~Thread();
+ friend class Runtime; // For ~Thread.
void InitCpu();
void InitFunctionPointers();
@@ -489,6 +489,8 @@ class ThreadList {
void Unregister(Thread* thread);
+ bool Contains(Thread* thread);
+
void Lock() {
lock_->Lock();
}