summaryrefslogtreecommitdiff
path: root/compiler/driver/compiler_driver.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/driver/compiler_driver.cc')
-rw-r--r--compiler/driver/compiler_driver.cc289
1 files changed, 241 insertions, 48 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 818d50a994..440fe9502e 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -39,6 +39,7 @@
#include "compiler_driver-inl.h"
#include "dex_compilation_unit.h"
#include "dex_file-inl.h"
+#include "dex_instruction-inl.h"
#include "dex/dex_to_dex_compiler.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
@@ -365,7 +366,7 @@ CompilerDriver::CompilerDriver(
classes_to_compile_(compiled_classes),
methods_to_compile_(compiled_methods),
had_hard_verifier_failure_(false),
- thread_count_(thread_count),
+ parallel_thread_count_(thread_count),
stats_(new AOTCompilationStats),
dump_stats_(dump_stats),
dump_passes_(dump_passes),
@@ -435,24 +436,27 @@ void CompilerDriver::CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
- std::unique_ptr<ThreadPool> thread_pool(
- new ThreadPool("Compiler driver thread pool", thread_count_ - 1));
+
+ InitializeThreadPools();
+
VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false);
// Precompile:
// 1) Load image classes
// 2) Resolve all classes
// 3) Attempt to verify all classes
// 4) Attempt to initialize image classes, and trivially initialized classes
- PreCompile(class_loader, dex_files, thread_pool.get(), timings);
+ PreCompile(class_loader, dex_files, timings);
// Compile:
// 1) Compile all classes and methods enabled for compilation. May fall back to dex-to-dex
// compilation.
if (!GetCompilerOptions().VerifyAtRuntime()) {
- Compile(class_loader, dex_files, thread_pool.get(), timings);
+ Compile(class_loader, dex_files, timings);
}
if (dump_stats_) {
stats_->Dump();
}
+
+ FreeThreadPools();
}
static optimizer::DexToDexCompilationLevel GetDexToDexCompilationLevel(
@@ -653,8 +657,9 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t
std::vector<const DexFile*> dex_files;
dex_files.push_back(dex_file);
- std::unique_ptr<ThreadPool> thread_pool(new ThreadPool("Compiler driver thread pool", 0U));
- PreCompile(jclass_loader, dex_files, thread_pool.get(), timings);
+ InitializeThreadPools();
+
+ PreCompile(jclass_loader, dex_files, timings);
// Can we run DEX-to-DEX compiler on this class ?
optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level =
@@ -677,20 +682,147 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t
true,
dex_cache);
+ FreeThreadPools();
+
self->GetJniEnv()->DeleteGlobalRef(jclass_loader);
}
-void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+void CompilerDriver::Resolve(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) {
+ // Resolution allocates classes and needs to run single-threaded to be deterministic.
+ bool force_determinism = GetCompilerOptions().IsForceDeterminism();
+ ThreadPool* resolve_thread_pool = force_determinism
+ ? single_thread_pool_.get()
+ : parallel_thread_pool_.get();
+ size_t resolve_thread_count = force_determinism ? 1U : parallel_thread_count_;
+
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != nullptr);
- ResolveDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
+ ResolveDexFile(class_loader,
+ *dex_file,
+ dex_files,
+ resolve_thread_pool,
+ resolve_thread_count,
+ timings);
+ }
+}
+
+// Resolve const-strings in the code. Done to have deterministic allocation behavior. Right now
+// this is single-threaded for simplicity.
+// TODO: Collect the relevant string indices in parallel, then allocate them sequentially in a
+// stable order.
+
+static void ResolveConstStrings(CompilerDriver* driver,
+ const DexFile& dex_file,
+ const DexFile::CodeItem* code_item) {
+ if (code_item == nullptr) {
+ // Abstract or native method.
+ return;
+ }
+
+ const uint16_t* code_ptr = code_item->insns_;
+ const uint16_t* code_end = code_item->insns_ + code_item->insns_size_in_code_units_;
+
+ while (code_ptr < code_end) {
+ const Instruction* inst = Instruction::At(code_ptr);
+ switch (inst->Opcode()) {
+ case Instruction::CONST_STRING: {
+ uint32_t string_index = inst->VRegB_21c();
+ driver->CanAssumeStringIsPresentInDexCache(dex_file, string_index);
+ break;
+ }
+ case Instruction::CONST_STRING_JUMBO: {
+ uint32_t string_index = inst->VRegB_31c();
+ driver->CanAssumeStringIsPresentInDexCache(dex_file, string_index);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ code_ptr += inst->SizeInCodeUnits();
+ }
+}
+
+static void ResolveConstStrings(CompilerDriver* driver,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) {
+ for (const DexFile* dex_file : dex_files) {
+ TimingLogger::ScopedTiming t("Resolve const-string Strings", timings);
+
+ size_t class_def_count = dex_file->NumClassDefs();
+ for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
+
+ const uint8_t* class_data = dex_file->GetClassData(class_def);
+ if (class_data == nullptr) {
+ // empty class, probably a marker interface
+ continue;
+ }
+
+ ClassDataItemIterator it(*dex_file, class_data);
+ // Skip fields
+ while (it.HasNextStaticField()) {
+ it.Next();
+ }
+ while (it.HasNextInstanceField()) {
+ it.Next();
+ }
+
+ bool compilation_enabled = driver->IsClassToCompile(
+ dex_file->StringByTypeIdx(class_def.class_idx_));
+ if (!compilation_enabled) {
+ // Compilation is skipped, do not resolve const-string in code of this class.
+ // TODO: Make sure that inlining honors this.
+ continue;
+ }
+
+ // Direct methods.
+ int64_t previous_direct_method_idx = -1;
+ while (it.HasNextDirectMethod()) {
+ uint32_t method_idx = it.GetMemberIndex();
+ if (method_idx == previous_direct_method_idx) {
+ // smali can create dex files with two encoded_methods sharing the same method_idx
+ // http://code.google.com/p/smali/issues/detail?id=119
+ it.Next();
+ continue;
+ }
+ previous_direct_method_idx = method_idx;
+ ResolveConstStrings(driver, *dex_file, it.GetMethodCodeItem());
+ it.Next();
+ }
+ // Virtual methods.
+ int64_t previous_virtual_method_idx = -1;
+ while (it.HasNextVirtualMethod()) {
+ uint32_t method_idx = it.GetMemberIndex();
+ if (method_idx == previous_virtual_method_idx) {
+ // smali can create dex files with two encoded_methods sharing the same method_idx
+ // http://code.google.com/p/smali/issues/detail?id=119
+ it.Next();
+ continue;
+ }
+ previous_virtual_method_idx = method_idx;
+ ResolveConstStrings(driver, *dex_file, it.GetMethodCodeItem());
+ it.Next();
+ }
+ DCHECK(!it.HasNext());
+ }
}
}
-void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+inline void CompilerDriver::CheckThreadPools() {
+ DCHECK(parallel_thread_pool_ != nullptr);
+ DCHECK(single_thread_pool_ != nullptr);
+}
+
+void CompilerDriver::PreCompile(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) {
+ CheckThreadPools();
+
LoadImageClasses(timings);
VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(false);
@@ -700,20 +832,26 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const De
// We need to resolve for never_verify since it needs to run dex to dex to add the
// RETURN_VOID_NO_BARRIER.
if (never_verify || verification_enabled) {
- Resolve(class_loader, dex_files, thread_pool, timings);
+ Resolve(class_loader, dex_files, timings);
VLOG(compiler) << "Resolve: " << GetMemoryUsageString(false);
}
if (never_verify) {
VLOG(compiler) << "Verify none mode specified, skipping verification.";
- SetVerified(class_loader, dex_files, thread_pool, timings);
+ SetVerified(class_loader, dex_files, timings);
}
if (!verification_enabled) {
return;
}
- Verify(class_loader, dex_files, thread_pool, timings);
+ if (GetCompilerOptions().IsForceDeterminism() && IsBootImage()) {
+ // Resolve strings from const-string. Do this now to have a deterministic image.
+ ResolveConstStrings(this, dex_files, timings);
+ VLOG(compiler) << "Resolve const-strings: " << GetMemoryUsageString(false);
+ }
+
+ Verify(class_loader, dex_files, timings);
VLOG(compiler) << "Verify: " << GetMemoryUsageString(false);
if (had_hard_verifier_failure_ && GetCompilerOptions().AbortOnHardVerifierFailure()) {
@@ -721,7 +859,7 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const De
<< "situations. Please check the log.";
}
- InitializeClasses(class_loader, dex_files, thread_pool, timings);
+ InitializeClasses(class_loader, dex_files, timings);
VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
UpdateImageClasses(timings);
@@ -1759,6 +1897,9 @@ class ParallelCompilationManager {
// Wait for all the worker threads to finish.
thread_pool_->Wait(self, true, false);
+
+ // And stop the workers accepting jobs.
+ thread_pool_->StopWorkers(self);
}
size_t NextIndex() {
@@ -1995,9 +2136,12 @@ class ResolveTypeVisitor : public CompilationVisitor {
const ParallelCompilationManager* const manager_;
};
-void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_file,
+void CompilerDriver::ResolveDexFile(jobject class_loader,
+ const DexFile& dex_file,
const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+ ThreadPool* thread_pool,
+ size_t thread_count,
+ TimingLogger* timings) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
// TODO: we could resolve strings here, although the string table is largely filled with class
@@ -2010,27 +2154,43 @@ void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_fil
// classdefs are resolved by ResolveClassFieldsAndMethods.
TimingLogger::ScopedTiming t("Resolve Types", timings);
ResolveTypeVisitor visitor(&context);
- context.ForAll(0, dex_file.NumTypeIds(), &visitor, thread_count_);
+ context.ForAll(0, dex_file.NumTypeIds(), &visitor, thread_count);
}
TimingLogger::ScopedTiming t("Resolve MethodsAndFields", timings);
ResolveClassFieldsAndMethodsVisitor visitor(&context);
- context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count_);
+ context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count);
}
-void CompilerDriver::SetVerified(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+void CompilerDriver::SetVerified(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) {
+ // This can be run in parallel.
for (const DexFile* dex_file : dex_files) {
CHECK(dex_file != nullptr);
- SetVerifiedDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
+ SetVerifiedDexFile(class_loader,
+ *dex_file,
+ dex_files,
+ parallel_thread_pool_.get(),
+ parallel_thread_count_,
+ timings);
}
}
-void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+void CompilerDriver::Verify(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) {
+ // Note: verification should not be pulling in classes anymore when compiling the boot image,
+ // as all should have been resolved before. As such, doing this in parallel should still
+ // be deterministic.
for (const DexFile* dex_file : dex_files) {
CHECK(dex_file != nullptr);
- VerifyDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
+ VerifyDexFile(class_loader,
+ *dex_file,
+ dex_files,
+ parallel_thread_pool_.get(),
+ parallel_thread_count_,
+ timings);
}
}
@@ -2104,15 +2264,18 @@ class VerifyClassVisitor : public CompilationVisitor {
const ParallelCompilationManager* const manager_;
};
-void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file,
+void CompilerDriver::VerifyDexFile(jobject class_loader,
+ const DexFile& dex_file,
const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+ ThreadPool* thread_pool,
+ size_t thread_count,
+ TimingLogger* timings) {
TimingLogger::ScopedTiming t("Verify Dex File", timings);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
thread_pool);
VerifyClassVisitor visitor(&context);
- context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count_);
+ context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count);
}
class SetVerifiedClassVisitor : public CompilationVisitor {
@@ -2162,15 +2325,18 @@ class SetVerifiedClassVisitor : public CompilationVisitor {
const ParallelCompilationManager* const manager_;
};
-void CompilerDriver::SetVerifiedDexFile(jobject class_loader, const DexFile& dex_file,
+void CompilerDriver::SetVerifiedDexFile(jobject class_loader,
+ const DexFile& dex_file,
const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+ ThreadPool* thread_pool,
+ size_t thread_count,
+ TimingLogger* timings) {
TimingLogger::ScopedTiming t("Verify Dex File", timings);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
thread_pool);
SetVerifiedClassVisitor visitor(&context);
- context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count_);
+ context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count);
}
class InitializeClassVisitor : public CompilationVisitor {
@@ -2271,31 +2437,37 @@ class InitializeClassVisitor : public CompilationVisitor {
const ParallelCompilationManager* const manager_;
};
-void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
+void CompilerDriver::InitializeClasses(jobject jni_class_loader,
+ const DexFile& dex_file,
const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+ TimingLogger* timings) {
TimingLogger::ScopedTiming t("InitializeNoClinit", timings);
+
+ // Initialization allocates objects and needs to run single-threaded to be deterministic.
+ bool force_determinism = GetCompilerOptions().IsForceDeterminism();
+ ThreadPool* init_thread_pool = force_determinism
+ ? single_thread_pool_.get()
+ : parallel_thread_pool_.get();
+ size_t init_thread_count = force_determinism ? 1U : parallel_thread_count_;
+
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, dex_files,
- thread_pool);
- size_t thread_count;
+ init_thread_pool);
if (IsBootImage()) {
// TODO: remove this when transactional mode supports multithreading.
- thread_count = 1U;
- } else {
- thread_count = thread_count_;
+ init_thread_count = 1U;
}
InitializeClassVisitor visitor(&context);
- context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count);
+ context.ForAll(0, dex_file.NumClassDefs(), &visitor, init_thread_count);
}
void CompilerDriver::InitializeClasses(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+ TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != nullptr);
- InitializeClasses(class_loader, *dex_file, dex_files, thread_pool, timings);
+ InitializeClasses(class_loader, *dex_file, dex_files, timings);
}
if (IsBootImage()) {
// Prune garbage objects created during aborted transactions.
@@ -2303,8 +2475,9 @@ void CompilerDriver::InitializeClasses(jobject class_loader,
}
}
-void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+void CompilerDriver::Compile(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) {
if (kDebugProfileGuidedCompilation) {
LOG(INFO) << "[ProfileGuidedCompilation] " <<
((profile_compilation_info_ == nullptr)
@@ -2314,7 +2487,12 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != nullptr);
- CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
+ CompileDexFile(class_loader,
+ *dex_file,
+ dex_files,
+ parallel_thread_pool_.get(),
+ parallel_thread_count_,
+ timings);
}
VLOG(compiler) << "Compile: " << GetMemoryUsageString(false);
}
@@ -2421,14 +2599,17 @@ class CompileClassVisitor : public CompilationVisitor {
const ParallelCompilationManager* const manager_;
};
-void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file,
+void CompilerDriver::CompileDexFile(jobject class_loader,
+ const DexFile& dex_file,
const std::vector<const DexFile*>& dex_files,
- ThreadPool* thread_pool, TimingLogger* timings) {
+ ThreadPool* thread_pool,
+ size_t thread_count,
+ TimingLogger* timings) {
TimingLogger::ScopedTiming t("Compile Dex File", timings);
ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this,
&dex_file, dex_files, thread_pool);
CompileClassVisitor visitor(&context);
- context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count_);
+ context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count);
}
void CompilerDriver::AddCompiledMethod(const MethodReference& method_ref,
@@ -2589,4 +2770,16 @@ bool CompilerDriver::MayInlineInternal(const DexFile* inlined_from,
return true;
}
+void CompilerDriver::InitializeThreadPools() {
+ size_t parallel_count = parallel_thread_count_ > 0 ? parallel_thread_count_ - 1 : 0;
+ parallel_thread_pool_.reset(
+ new ThreadPool("Compiler driver thread pool", parallel_count));
+ single_thread_pool_.reset(new ThreadPool("Single-threaded Compiler driver thread pool", 0));
+}
+
+void CompilerDriver::FreeThreadPools() {
+ parallel_thread_pool_.reset();
+ single_thread_pool_.reset();
+}
+
} // namespace art