Merge "Verify thread state for all allocations, fix 2 failures" into dalvik-dev
diff --git a/src/class_linker.cc b/src/class_linker.cc
index cf0c094..87976a3 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1178,7 +1178,7 @@
} else {
std::string class_name_string(DescriptorToDot(descriptor));
- ScopedThreadStateChange(self, Thread::kNative);
+ ScopedThreadStateChange tsc(self, Thread::kNative);
JNIEnv* env = self->GetJniEnv();
ScopedLocalRef<jclass> c(env, AddLocalReference<jclass>(env, GetClassRoot(kJavaLangClassLoader)));
CHECK(c.get() != NULL);
diff --git a/src/compiler.cc b/src/compiler.cc
index 4cc228c..ca9e53e 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -59,14 +59,10 @@
const std::set<std::string>* image_classes)
: instruction_set_(instruction_set),
jni_compiler_(instruction_set),
+ compiled_classes_lock_("compiled classes lock"),
+ compiled_methods_lock_("compiled method lock"),
+ compiled_invoke_stubs_lock_("compiled invoke stubs lock"),
image_(image),
- dex_file_count_(0),
- class_count_(0),
- abstract_method_count_(0),
- native_method_count_(0),
- regular_method_count_(0),
- instruction_count_(0),
- start_ns_(NanoTime()),
image_classes_(image_classes) {
CHECK(!Runtime::Current()->IsStarted());
if (!image_) {
@@ -75,32 +71,17 @@
}
Compiler::~Compiler() {
- STLDeleteValues(&compiled_classes_);
- STLDeleteValues(&compiled_methods_);
- STLDeleteValues(&compiled_invoke_stubs_);
- if (dex_file_count_ > 0) {
- uint64_t duration_ns = NanoTime() - start_ns_;
- std::string stats(StringPrintf("Compiled files:%zd"
- " classes:%zd"
- " methods:(abstract:%zd"
- " native:%zd"
- " regular:%zd)"
- " instructions:%zd",
- dex_file_count_,
- class_count_,
- abstract_method_count_,
- native_method_count_,
- regular_method_count_,
- instruction_count_));
- stats += " (took ",
- stats += PrettyDuration(duration_ns);
- if (instruction_count_ != 0) {
- stats += ", ";
- stats += PrettyDuration(duration_ns / instruction_count_);
- stats += "/instruction";
- }
- stats += ")";
- LOG(INFO) << stats;
+ {
+ MutexLock mu(compiled_classes_lock_);
+ STLDeleteValues(&compiled_classes_);
+ }
+ {
+ MutexLock mu(compiled_methods_lock_);
+ STLDeleteValues(&compiled_methods_);
+ }
+ {
+ MutexLock mu(compiled_invoke_stubs_lock_);
+ STLDeleteValues(&compiled_invoke_stubs_);
}
}
@@ -251,6 +232,7 @@
struct Context {
ClassLinker* class_linker;
const ClassLoader* class_loader;
+ Compiler* compiler;
DexCache* dex_cache;
const DexFile* dex_file;
};
@@ -287,7 +269,6 @@
}
pthread_t pthread_;
- Thread* thread_;
Context* context_;
size_t begin_;
@@ -296,24 +277,18 @@
size_t stripe_;
};
-class Workers {
- public:
- Workers(Context* context, size_t begin, size_t end, Callback callback) {
- const size_t thread_count = static_cast<size_t>(sysconf(_SC_NPROCESSORS_ONLN));
- for (size_t i = 0; i < thread_count; ++i) {
- threads_.push_back(new WorkerThread(context, begin + i, end, callback, thread_count));
- }
+void ForAll(Context* context, size_t begin, size_t end, Callback callback) {
+ std::vector<WorkerThread*> threads;
+
+ const size_t thread_count = static_cast<size_t>(sysconf(_SC_NPROCESSORS_ONLN));
+ for (size_t i = 0; i < thread_count; ++i) {
+ threads.push_back(new WorkerThread(context, begin + i, end, callback, thread_count));
}
- ~Workers() {
- // Switch to kVmWait while we're blocked waiting for the other threads to finish.
- ScopedThreadStateChange tsc(Thread::Current(), Thread::kVmWait);
- STLDeleteElements(&threads_);
- }
-
- private:
- std::vector<WorkerThread*> threads_;
-};
+ // Switch to kVmWait while we're blocked waiting for the other threads to finish.
+ ScopedThreadStateChange tsc(Thread::Current(), Thread::kVmWait);
+ STLDeleteElements(&threads);
+}
static void ResolveClassFieldsAndMethods(Context* context, size_t class_def_index) {
const DexFile& dex_file = *context->dex_file;
@@ -413,14 +388,10 @@
context.dex_cache = dex_cache;
context.dex_file = &dex_file;
- {
- Workers workers(&context, 0, dex_cache->NumResolvedTypes(), ResolveType);
- }
+ ForAll(&context, 0, dex_cache->NumResolvedTypes(), ResolveType);
timings.AddSplit("Resolve " + dex_file.GetLocation() + " Types");
- {
- Workers workers(&context, 0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods);
- }
+ ForAll(&context, 0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods);
timings.AddSplit("Resolve " + dex_file.GetLocation() + " MethodsAndFields");
}
@@ -465,7 +436,7 @@
context.class_linker = Runtime::Current()->GetClassLinker();
context.class_loader = class_loader;
context.dex_file = &dex_file;
- Workers workers(&context, 0, dex_file.NumClassDefs(), VerifyClass);
+ ForAll(&context, 0, dex_file.NumClassDefs(), VerifyClass);
dex_file.ChangePermissions(PROT_READ);
}
@@ -490,6 +461,7 @@
// record the final class status if necessary
Class::Status status = klass->GetStatus();
ClassReference ref(&dex_file, class_def_index);
+ MutexLock mu(compiled_classes_lock_);
CompiledClass* compiled_class = GetCompiledClass(ref);
if (compiled_class == NULL) {
compiled_class = new CompiledClass(status);
@@ -522,20 +494,13 @@
}
}
-void Compiler::CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file) {
- ++dex_file_count_;
- for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); class_def_index++) {
- const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
- CompileClass(class_def, class_loader, dex_file);
- }
-}
-
-void Compiler::CompileClass(const DexFile::ClassDef& class_def, const ClassLoader* class_loader,
- const DexFile& dex_file) {
+void Compiler::CompileClass(Context* context, size_t class_def_index) {
+ const ClassLoader* class_loader = context->class_loader;
+ const DexFile& dex_file = *context->dex_file;
+ const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
if (SkipClass(class_loader, dex_file, class_def)) {
return;
}
- ++class_count_;
const byte* class_data = dex_file.GetClassData(class_def);
if (class_data == NULL) {
// empty class, probably a marker interface
@@ -551,33 +516,37 @@
}
// Compile direct methods
while (it.HasNextDirectMethod()) {
- CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(), it.GetMemberIndex(),
- class_loader, dex_file);
+ context->compiler->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
+ it.GetMemberIndex(), class_loader, dex_file);
it.Next();
}
// Compile virtual methods
while (it.HasNextVirtualMethod()) {
- CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(), it.GetMemberIndex(),
- class_loader, dex_file);
+ context->compiler->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
+ it.GetMemberIndex(), class_loader, dex_file);
it.Next();
}
DCHECK(!it.HasNext());
}
+void Compiler::CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file) {
+ Context context;
+ context.class_loader = class_loader;
+ context.compiler = this;
+ context.dex_file = &dex_file;
+ ForAll(&context, 0, dex_file.NumClassDefs(), Compiler::CompileClass);
+}
+
void Compiler::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
uint32_t method_idx, const ClassLoader* class_loader,
const DexFile& dex_file) {
CompiledMethod* compiled_method = NULL;
uint64_t start_ns = NanoTime();
if ((access_flags & kAccNative) != 0) {
- ++native_method_count_;
compiled_method = jni_compiler_.Compile(access_flags, method_idx, class_loader, dex_file);
CHECK(compiled_method != NULL);
} else if ((access_flags & kAccAbstract) != 0) {
- ++abstract_method_count_;
} else {
- ++regular_method_count_;
- instruction_count_ += code_item->insns_size_in_code_units_;
compiled_method = oatCompileMethod(*this, code_item, access_flags, method_idx, class_loader,
dex_file, kThumb2);
CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file);
@@ -591,6 +560,7 @@
if (compiled_method != NULL) {
MethodReference ref(&dex_file, method_idx);
CHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
+ MutexLock mu(compiled_methods_lock_);
compiled_methods_[ref] = compiled_method;
DCHECK(GetCompiledMethod(ref) != NULL) << PrettyMethod(method_idx, dex_file);
}
@@ -621,6 +591,7 @@
}
const CompiledInvokeStub* Compiler::FindInvokeStub(bool is_static, const char* shorty) const {
+ MutexLock mu(compiled_invoke_stubs_lock_);
const std::string key(MakeInvokeStubKey(is_static, shorty));
InvokeStubTable::const_iterator it = compiled_invoke_stubs_.find(key);
if (it == compiled_invoke_stubs_.end()) {
@@ -633,11 +604,13 @@
void Compiler::InsertInvokeStub(bool is_static, const char* shorty,
const CompiledInvokeStub* compiled_invoke_stub) {
+ MutexLock mu(compiled_invoke_stubs_lock_);
std::string key(MakeInvokeStubKey(is_static, shorty));
compiled_invoke_stubs_[key] = compiled_invoke_stub;
}
CompiledClass* Compiler::GetCompiledClass(ClassReference ref) const {
+ MutexLock mu(compiled_classes_lock_);
ClassTable::const_iterator it = compiled_classes_.find(ref);
if (it == compiled_classes_.end()) {
return NULL;
@@ -647,6 +620,7 @@
}
CompiledMethod* Compiler::GetCompiledMethod(MethodReference ref) const {
+ MutexLock mu(compiled_methods_lock_);
MethodTable::const_iterator it = compiled_methods_.find(ref);
if (it == compiled_methods_.end()) {
return NULL;
diff --git a/src/compiler.h b/src/compiler.h
index b43d5f6..f5f8cfa 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -33,6 +33,7 @@
namespace art {
+class Context;
class TimingLogger;
class Compiler {
@@ -135,6 +136,8 @@
void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, uint32_t method_idx,
const ClassLoader* class_loader, const DexFile& dex_file);
+ static void CompileClass(Context* context, size_t class_def_index);
+
void SetGcMaps(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
void SetGcMapsDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
void SetGcMapsMethod(const DexFile& dex_file, Method* method);
@@ -152,24 +155,21 @@
typedef std::map<const ClassReference, CompiledClass*> ClassTable;
// All class references that this compiler has compiled
+ mutable Mutex compiled_classes_lock_;
ClassTable compiled_classes_;
typedef std::map<const MethodReference, CompiledMethod*> MethodTable;
// All method references that this compiler has compiled
+ mutable Mutex compiled_methods_lock_;
MethodTable compiled_methods_;
typedef std::map<std::string, const CompiledInvokeStub*> InvokeStubTable;
// Invocation stubs created to allow invocation of the compiled methods
+ mutable Mutex compiled_invoke_stubs_lock_;
InvokeStubTable compiled_invoke_stubs_;
bool image_;
- size_t dex_file_count_;
- size_t class_count_;
- size_t abstract_method_count_;
- size_t native_method_count_;
- size_t regular_method_count_;
- size_t instruction_count_;
uint64_t start_ns_;
const std::set<std::string>* image_classes_;
diff --git a/src/dalvik_system_VMRuntime.cc b/src/dalvik_system_VMRuntime.cc
index 4ec2af8..b953248 100644
--- a/src/dalvik_system_VMRuntime.cc
+++ b/src/dalvik_system_VMRuntime.cc
@@ -134,9 +134,13 @@
void VMRuntime_trimHeap(JNIEnv* env, jobject) {
ScopedHeapLock heap_lock;
+ size_t alloc_space_size = Heap::GetAllocSpace()->Size();
+ float utilization = static_cast<float>(Heap::GetBytesAllocated()) / alloc_space_size;
uint64_t start_ns = NanoTime();
Heap::GetAllocSpace()->Trim();
- VLOG(gc) << "VMRuntime_trimHeap took " << PrettyDuration(NanoTime() - start_ns);
+ LOG(INFO) << "Parallel heap trimming took " << PrettyDuration(NanoTime() - start_ns)
+ << " on a " << PrettySize(alloc_space_size)
+ << " heap with " << static_cast<int>(100 * utilization) << "% utilization";
}
JNINativeMethod gMethods[] = {
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 7a6829e..c4ca894 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -110,7 +110,8 @@
~Dex2Oat() {
delete runtime_;
- LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_);
+ const size_t thread_count = static_cast<size_t>(sysconf(_SC_NPROCESSORS_ONLN));
+ LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_) << " (threads: " << thread_count << ")";
}
// Make a list of descriptors for classes to include in the image
diff --git a/src/thread_x86.cc b/src/thread_x86.cc
index 4f61e66..85da1f3 100644
--- a/src/thread_x86.cc
+++ b/src/thread_x86.cc
@@ -36,8 +36,8 @@
#if defined(__APPLE__)
UNIMPLEMENTED(WARNING);
#else
- // TODO: create specific lock for LDT modification
- ScopedThreadListLock mutex; // Avoid concurrent modification of the LDT
+ static Mutex modify_ldt_lock("modify_ldt lock");
+ MutexLock mu(modify_ldt_lock);
// Read LDT
CHECK_EQ((size_t)LDT_ENTRY_SIZE, sizeof(uint64_t));