summaryrefslogtreecommitdiffstats
path: root/src/compiler/driver/compiler_driver.cc
diff options
context:
space:
mode:
authorSebastien Hertz <shertz@google.com>2013-05-17 11:31:37 +0200
committerSebastien Hertz <shertz@google.com>2013-06-24 15:29:06 +0200
commit2d6ba5158d7fd459db2870df47300b517dc4d08c (patch)
tree51e306969d4d707aee7a6bc36481390721e0f81f /src/compiler/driver/compiler_driver.cc
parent1e2ee7de9dff66f7ca2bdf83a7262e21d75b37d1 (diff)
downloadandroid_art-2d6ba5158d7fd459db2870df47300b517dc4d08c.tar.gz
android_art-2d6ba5158d7fd459db2870df47300b517dc4d08c.tar.bz2
android_art-2d6ba5158d7fd459db2870df47300b517dc4d08c.zip
Quickening support.
This CL adds quickening support for methods which are interpreted at runtime. This CL introduces a DEX-to-DEX compiler. A method is now compiled in one of the two following modes: - Native compilation: the method is compiled by the Quick or Portable backends. At runtime, the generated native target-dependent code is executed. - DEX-to-DEX compilation: the method is executed by the interpreter at runtime. Its DEX code is compiled so some instructions can be replaced by special instructions only valid at runtime. No native code is generated. The quickening adds special instructions to improve runtime performance. They are "-quick" versions of the following instructions: - iget/iput - iget-wide/iput-wide - iget-object/iput-object - invoke-virtual/range. These special instructions cannot be treated by the verifier since they lose the field/method index referencing the field/method being accessed/invoked. To prevent this, the DEX-to-DEX compiler is run only on methods of preverified classes (without verification error at compilation time). The DEX-to-DEX compiler implements quickening support using the CompilerDriver interface like the native compiler does (Quick or Portable backends). To replace instructions, the DEX-to-DEX compiler must be able to modify the mmapped DEX file. Since it can be read-only protected, the DEX-to-DEX compiler must be able to temporarily change its protection to read-write mmapped file. To achieve this, this CL adds support for changing DEX file protection with DexFile::EnableWrite and DexFile::DisableWrite methods. Besides, it also adds a dedicated lock (DexFile::modification_lock) to ensure thread-safety and avoid concurrent DEX file protection change (from a parallel DEX-to-DEX compiler on the same DEX file). Change-Id: Iaafd103b9766810d7fc94a2c424a8fafba66e26a
Diffstat (limited to 'src/compiler/driver/compiler_driver.cc')
-rw-r--r--src/compiler/driver/compiler_driver.cc68
1 files changed, 58 insertions, 10 deletions
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 6050108d48..4a6eb962e3 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -372,6 +372,8 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet
compiler_ = FindFunction<CompilerFn>(compiler_so_name, compiler_library_, "ArtQuickCompileMethod");
}
+ dex_to_dex_compiler_ = FindFunction<CompilerFn>(compiler_so_name, compiler_library_, "ArtCompileDEX");
+
init_compiler_context(*this);
if (compiler_backend_ == kPortable) {
@@ -531,10 +533,33 @@ void CompilerDriver::CompileAll(jobject class_loader,
}
}
+static bool IsDexToDexCompilationAllowed(mirror::ClassLoader* class_loader,
+ const DexFile& dex_file,
+ const DexFile::ClassDef& class_def)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Do not allow DEX-to-DEX compilation of image classes. This is to prevent the
+ // verifier from passing on "quick" instruction at compilation time. It must
+ // only pass on quick instructions at runtime.
+ if (class_loader == NULL) {
+ return false;
+ }
+ const char* descriptor = dex_file.GetClassDescriptor(class_def);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ mirror::Class* klass = class_linker->FindClass(descriptor, class_loader);
+ if (klass == NULL) {
+ Thread* self = Thread::Current();
+ CHECK(self->IsExceptionPending());
+ self->ClearException();
+ return false;
+ }
+ // DEX-to-DEX compilation is only allowed on preverified classes.
+ return klass->IsVerified();
+}
+
void CompilerDriver::CompileOne(const mirror::AbstractMethod* method) {
DCHECK(!Runtime::Current()->IsStarted());
Thread* self = Thread::Current();
- jobject class_loader;
+ jobject jclass_loader;
const DexFile* dex_file;
uint32_t class_def_idx;
{
@@ -542,7 +567,7 @@ void CompilerDriver::CompileOne(const mirror::AbstractMethod* method) {
ScopedLocalRef<jobject>
local_class_loader(soa.Env(),
soa.AddLocalReference<jobject>(method->GetDeclaringClass()->GetClassLoader()));
- class_loader = soa.Env()->NewGlobalRef(local_class_loader.get());
+ jclass_loader = soa.Env()->NewGlobalRef(local_class_loader.get());
// Find the dex_file
MethodHelper mh(method);
dex_file = &mh.GetDexFile();
@@ -555,14 +580,22 @@ void CompilerDriver::CompileOne(const mirror::AbstractMethod* method) {
UniquePtr<ThreadPool> thread_pool(new ThreadPool(1U));
TimingLogger timings("CompileOne", false);
- PreCompile(class_loader, dex_files, *thread_pool.get(), timings);
+ PreCompile(jclass_loader, dex_files, *thread_pool.get(), timings);
uint32_t method_idx = method->GetDexMethodIndex();
const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
+ // Can we run DEX-to-DEX compiler on this class ?
+ bool allow_dex_compilation;
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx);
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader);
+ allow_dex_compilation = IsDexToDexCompilationAllowed(class_loader, *dex_file, class_def);
+ }
CompileMethod(code_item, method->GetAccessFlags(), method->GetInvokeType(),
- class_def_idx, method_idx, class_loader, *dex_file);
+ class_def_idx, method_idx, jclass_loader, *dex_file, allow_dex_compilation);
- self->GetJniEnv()->DeleteGlobalRef(class_loader);
+ self->GetJniEnv()->DeleteGlobalRef(jclass_loader);
self->TransitionFromSuspendedToRunnable();
}
@@ -2015,12 +2048,12 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi
}
void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, size_t class_def_index) {
- jobject class_loader = manager->GetClassLoader();
+ jobject jclass_loader = manager->GetClassLoader();
const DexFile& dex_file = *manager->GetDexFile();
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
{
ScopedObjectAccess soa(Thread::Current());
- mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader());
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader);
if (SkipClass(class_loader, dex_file, class_def)) {
return;
}
@@ -2035,6 +2068,13 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
// empty class, probably a marker interface
return;
}
+ // Can we run DEX-to-DEX compiler on this class ?
+ bool allow_dex_compilation;
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(jclass_loader);
+ allow_dex_compilation = IsDexToDexCompilationAllowed(class_loader, dex_file, class_def);
+ }
ClassDataItemIterator it(dex_file, class_data);
// Skip fields
while (it.HasNextStaticField()) {
@@ -2056,7 +2096,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
previous_direct_method_idx = method_idx;
manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
it.GetMethodInvokeType(class_def), class_def_index,
- method_idx, class_loader, dex_file);
+ method_idx, jclass_loader, dex_file, allow_dex_compilation);
it.Next();
}
// Compile virtual methods
@@ -2072,7 +2112,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
previous_virtual_method_idx = method_idx;
manager->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
it.GetMethodInvokeType(class_def), class_def_index,
- method_idx, class_loader, dex_file);
+ method_idx, jclass_loader, dex_file, allow_dex_compilation);
it.Next();
}
DCHECK(!it.HasNext());
@@ -2088,7 +2128,8 @@ void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_fil
void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
InvokeType invoke_type, uint32_t class_def_idx,
uint32_t method_idx, jobject class_loader,
- const DexFile& dex_file) {
+ const DexFile& dex_file,
+ bool allow_dex_to_dex_compilation) {
CompiledMethod* compiled_method = NULL;
uint64_t start_ns = NanoTime();
@@ -2113,6 +2154,13 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
compiled_method = (*compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx,
method_idx, class_loader, dex_file);
CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file);
+ } else if (allow_dex_to_dex_compilation) {
+ // TODO: add a mode to disable DEX-to-DEX compilation ?
+ compiled_method = (*dex_to_dex_compiler_)(*this, code_item, access_flags,
+ invoke_type, class_def_idx,
+ method_idx, class_loader, dex_file);
+ // No native code is generated.
+ CHECK(compiled_method == NULL) << PrettyMethod(method_idx, dex_file);
}
}
uint64_t duration_ns = NanoTime() - start_ns;