summaryrefslogtreecommitdiffstats
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.cc175
1 files changed, 114 insertions, 61 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 01e0ac4abe..b99301566e 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -350,10 +350,10 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
dump_stats_(dump_stats),
dump_passes_(dump_passes),
timings_logger_(timer),
- compiler_library_(NULL),
- compiler_context_(NULL),
- compiler_enable_auto_elf_loading_(NULL),
- compiler_get_method_code_addr_(NULL),
+ compiler_library_(nullptr),
+ compiler_context_(nullptr),
+ compiler_enable_auto_elf_loading_(nullptr),
+ compiler_get_method_code_addr_(nullptr),
support_boot_image_fixup_(instruction_set != kMips),
dedupe_code_("dedupe code"),
dedupe_src_mapping_table_("dedupe source mapping table"),
@@ -365,7 +365,7 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
DCHECK(verification_results_ != nullptr);
DCHECK(method_inliner_map_ != nullptr);
- CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key");
+ CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, nullptr), "compiler tls key");
dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX);
@@ -445,7 +445,7 @@ CompilerDriver::~CompilerDriver() {
CompilerTls* CompilerDriver::GetTls() {
// Lazily create thread-local storage
CompilerTls* res = static_cast<CompilerTls*>(pthread_getspecific(tls_key_));
- if (res == NULL) {
+ if (res == nullptr) {
res = compiler_->CreateNewCompilerTls();
CHECK_PTHREAD_CALL(pthread_setspecific, (tls_key_, res), "compiler tls");
}
@@ -520,20 +520,18 @@ static DexToDexCompilationLevel GetDexToDexCompilationlevel(
const char* descriptor = dex_file.GetClassDescriptor(class_def);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
mirror::Class* klass = class_linker->FindClass(self, descriptor, class_loader);
- if (klass == NULL) {
+ if (klass == nullptr) {
CHECK(self->IsExceptionPending());
self->ClearException();
return kDontDexToDexCompile;
}
- // The verifier can only run on "quick" instructions at runtime (see usage of
- // FindAccessedFieldAtDexPc and FindInvokedMethodAtDexPc in ThrowNullPointerExceptionFromDexPC
- // function). Since image classes can be verified again while compiling an application,
- // we must prevent the DEX-to-DEX compiler from introducing them.
- // TODO: find a way to enable "quick" instructions for image classes and remove this check.
- bool compiling_image_classes = class_loader.Get() == nullptr;
- if (compiling_image_classes) {
- return kRequired;
- } else if (klass->IsVerified()) {
+ // DexToDex at the kOptimize level may introduce quickened opcodes, which replace symbolic
+ // references with actual offsets. We cannot re-verify such instructions.
+ //
+ // We store the verification information in the class status in the oat file, which the linker
+ // can validate (checksums) and use to skip load-time verification. It is thus safe to
+ // optimize when a class has been fully verified before.
+ if (klass->IsVerified()) {
// Class is verified so we can enable DEX-to-DEX compilation for performance.
return kOptimize;
} else if (klass->IsCompileTimeVerified()) {
@@ -606,13 +604,14 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const De
ThreadPool* thread_pool, TimingLogger* timings) {
LoadImageClasses(timings);
+ Resolve(class_loader, dex_files, thread_pool, timings);
+
if (!compiler_options_->IsVerificationEnabled()) {
- VLOG(compiler) << "Verify none mode specified, skipping pre-compilation";
+ VLOG(compiler) << "Verify none mode specified, skipping verification.";
+ SetVerified(class_loader, dex_files, thread_pool, timings);
return;
}
- Resolve(class_loader, dex_files, thread_pool, timings);
-
Verify(class_loader, dex_files, thread_pool, timings);
InitializeClasses(class_loader, dex_files, thread_pool, timings);
@@ -632,7 +631,7 @@ static void ResolveExceptionsForMethod(MethodHelper* mh,
std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
const DexFile::CodeItem* code_item = mh->GetMethod()->GetCodeItem();
- if (code_item == NULL) {
+ if (code_item == nullptr) {
return; // native or abstract method
}
if (code_item->tries_size_ == 0) {
@@ -710,7 +709,7 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings)
StackHandleScope<1> hs(self);
Handle<mirror::Class> klass(
hs.NewHandle(class_linker->FindSystemClass(self, descriptor.c_str())));
- if (klass.Get() == NULL) {
+ if (klass.Get() == nullptr) {
VLOG(compiler) << "Failed to find class " << descriptor;
image_classes_->erase(it++);
self->ClearException();
@@ -738,7 +737,7 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings)
Handle<mirror::Class> klass(hs.NewHandle(
class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache,
NullHandle<mirror::ClassLoader>())));
- if (klass.Get() == NULL) {
+ if (klass.Get() == nullptr) {
const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
const char* descriptor = dex_file->GetTypeDescriptor(type_id);
LOG(FATAL) << "Failed to resolve class " << descriptor;
@@ -785,8 +784,8 @@ static void MaybeAddToImageClasses(Handle<mirror::Class> c, std::set<std::string
}
void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) {
- DCHECK(object != NULL);
- DCHECK(arg != NULL);
+ DCHECK(object != nullptr);
+ DCHECK(arg != nullptr);
CompilerDriver* compiler_driver = reinterpret_cast<CompilerDriver*>(arg);
StackHandleScope<1> hs(Thread::Current());
MaybeAddToImageClasses(hs.NewHandle(object->GetClass()), compiler_driver->image_classes_.get());
@@ -854,29 +853,29 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const Dex
uint32_t type_idx,
bool* type_known_final, bool* type_known_abstract,
bool* equals_referrers_class) {
- if (type_known_final != NULL) {
+ if (type_known_final != nullptr) {
*type_known_final = false;
}
- if (type_known_abstract != NULL) {
+ if (type_known_abstract != nullptr) {
*type_known_abstract = false;
}
- if (equals_referrers_class != NULL) {
+ if (equals_referrers_class != nullptr) {
*equals_referrers_class = false;
}
ScopedObjectAccess soa(Thread::Current());
mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
// Get type from dex cache assuming it was populated by the verifier
mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
- if (resolved_class == NULL) {
+ if (resolved_class == nullptr) {
stats_->TypeNeedsAccessCheck();
return false; // Unknown class needs access checks.
}
const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
- if (equals_referrers_class != NULL) {
+ if (equals_referrers_class != nullptr) {
*equals_referrers_class = (method_id.class_idx_ == type_idx);
}
mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
- if (referrer_class == NULL) {
+ if (referrer_class == nullptr) {
stats_->TypeNeedsAccessCheck();
return false; // Incomplete referrer knowledge needs access check.
}
@@ -885,10 +884,10 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const Dex
bool result = referrer_class->CanAccess(resolved_class);
if (result) {
stats_->TypeDoesntNeedAccessCheck();
- if (type_known_final != NULL) {
+ if (type_known_final != nullptr) {
*type_known_final = resolved_class->IsFinal() && !resolved_class->IsArrayClass();
}
- if (type_known_abstract != NULL) {
+ if (type_known_abstract != nullptr) {
*type_known_abstract = resolved_class->IsAbstract() && !resolved_class->IsArrayClass();
}
} else {
@@ -904,13 +903,13 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_id
mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
// Get type from dex cache assuming it was populated by the verifier.
mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
- if (resolved_class == NULL) {
+ if (resolved_class == nullptr) {
stats_->TypeNeedsAccessCheck();
return false; // Unknown class needs access checks.
}
const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
- if (referrer_class == NULL) {
+ if (referrer_class == nullptr) {
stats_->TypeNeedsAccessCheck();
return false; // Incomplete referrer knowledge needs access check.
}
@@ -1310,6 +1309,10 @@ const VerifiedMethod* CompilerDriver::GetVerifiedMethod(const DexFile* dex_file,
}
bool CompilerDriver::IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc) {
+ if (!compiler_options_->IsVerificationEnabled()) {
+ // If we didn't verify, every cast has to be treated as non-safe.
+ return false;
+ }
DCHECK(mUnit->GetVerifiedMethod() != nullptr);
bool result = mUnit->GetVerifiedMethod()->IsSafeCast(dex_pc);
if (result) {
@@ -1410,7 +1413,7 @@ class ParallelCompilationManager {
thread_pool_(thread_pool) {}
ClassLinker* GetClassLinker() const {
- CHECK(class_linker_ != NULL);
+ CHECK(class_linker_ != nullptr);
return class_linker_;
}
@@ -1419,12 +1422,12 @@ class ParallelCompilationManager {
}
CompilerDriver* GetCompiler() const {
- CHECK(compiler_ != NULL);
+ CHECK(compiler_ != nullptr);
return compiler_;
}
const DexFile* GetDexFile() const {
- CHECK(dex_file_ != NULL);
+ CHECK(dex_file_ != nullptr);
return dex_file_;
}
@@ -1499,10 +1502,10 @@ class ParallelCompilationManager {
// that avoids the expensive FindInClassPath search.
static bool SkipClass(jobject class_loader, const DexFile& dex_file, mirror::Class* klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK(klass != NULL);
+ DCHECK(klass != nullptr);
const DexFile& original_dex_file = *klass->GetDexCache()->GetDexFile();
if (&dex_file != &original_dex_file) {
- if (class_loader == NULL) {
+ if (class_loader == nullptr) {
LOG(WARNING) << "Skipping class " << PrettyDescriptor(klass) << " from "
<< dex_file.GetLocation() << " previously found in "
<< original_dex_file.GetLocation();
@@ -1587,7 +1590,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag
// static fields, instance fields, direct methods, and virtual
// methods.
const byte* class_data = dex_file.GetClassData(class_def);
- if (class_data == NULL) {
+ if (class_data == nullptr) {
// Empty class such as a marker interface.
requires_constructor_barrier = false;
} else {
@@ -1596,7 +1599,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag
if (resolve_fields_and_methods) {
mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
dex_cache, class_loader, true);
- if (field == NULL) {
+ if (field == nullptr) {
CheckAndClearResolveException(soa.Self());
}
}
@@ -1611,7 +1614,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag
if (resolve_fields_and_methods) {
mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
dex_cache, class_loader, false);
- if (field == NULL) {
+ if (field == nullptr) {
CheckAndClearResolveException(soa.Self());
}
}
@@ -1623,7 +1626,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag
dex_cache, class_loader,
NullHandle<mirror::ArtMethod>(),
it.GetMethodInvokeType(class_def));
- if (method == NULL) {
+ if (method == nullptr) {
CheckAndClearResolveException(soa.Self());
}
it.Next();
@@ -1633,7 +1636,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag
dex_cache, class_loader,
NullHandle<mirror::ArtMethod>(),
it.GetMethodInvokeType(class_def));
- if (method == NULL) {
+ if (method == nullptr) {
CheckAndClearResolveException(soa.Self());
}
it.Next();
@@ -1658,9 +1661,9 @@ static void ResolveType(const ParallelCompilationManager* manager, size_t type_i
hs.NewHandle(soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader())));
mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
- if (klass == NULL) {
+ if (klass == nullptr) {
CHECK(soa.Self()->IsExceptionPending());
- mirror::Throwable* exception = soa.Self()->GetException(NULL);
+ mirror::Throwable* exception = soa.Self()->GetException(nullptr);
VLOG(compiler) << "Exception during type resolution: " << exception->Dump();
if (exception->GetClass()->DescriptorEquals("Ljava/lang/OutOfMemoryError;")) {
// There's little point continuing compilation if the heap is exhausted.
@@ -1691,11 +1694,20 @@ void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_fil
context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_);
}
+void CompilerDriver::SetVerified(jobject class_loader, const std::vector<const DexFile*>& dex_files,
+ ThreadPool* thread_pool, TimingLogger* timings) {
+ for (size_t i = 0; i != dex_files.size(); ++i) {
+ const DexFile* dex_file = dex_files[i];
+ CHECK(dex_file != nullptr);
+ SetVerifiedDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
+ }
+}
+
void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
- CHECK(dex_file != NULL);
+ CHECK(dex_file != nullptr);
VerifyDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
}
}
@@ -1757,6 +1769,47 @@ void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file
context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
}
+static void SetVerifiedClass(const ParallelCompilationManager* manager, size_t class_def_index)
+ LOCKS_EXCLUDED(Locks::mutator_lock_) {
+ ATRACE_CALL();
+ ScopedObjectAccess soa(Thread::Current());
+ const DexFile& dex_file = *manager->GetDexFile();
+ const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
+ const char* descriptor = dex_file.GetClassDescriptor(class_def);
+ ClassLinker* class_linker = manager->GetClassLinker();
+ jobject jclass_loader = manager->GetClassLoader();
+ StackHandleScope<3> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader(
+ hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ Handle<mirror::Class> klass(
+ hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
+ // Class might have failed resolution. Then don't set it to verified.
+ if (klass.Get() != nullptr) {
+ // Only do this if the class is resolved. If even resolution fails, quickening will go very,
+ // very wrong.
+ if (klass->IsResolved()) {
+ if (klass->GetStatus() < mirror::Class::kStatusVerified) {
+ ObjectLock<mirror::Class> lock(soa.Self(), klass);
+ klass->SetStatus(mirror::Class::kStatusVerified, soa.Self());
+ }
+ // Record the final class status if necessary.
+ ClassReference ref(manager->GetDexFile(), class_def_index);
+ manager->GetCompiler()->RecordClassStatus(ref, klass->GetStatus());
+ }
+ }
+ soa.Self()->AssertNoPendingException();
+}
+
+void CompilerDriver::SetVerifiedDexFile(jobject class_loader, const DexFile& dex_file,
+ const std::vector<const DexFile*>& dex_files,
+ ThreadPool* thread_pool, 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);
+ context.ForAll(0, dex_file.NumClassDefs(), SetVerifiedClass, thread_count_);
+}
+
static void InitializeClass(const ParallelCompilationManager* manager, size_t class_def_index)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
ATRACE_CALL();
@@ -1865,7 +1918,7 @@ void CompilerDriver::InitializeClasses(jobject class_loader,
ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
- CHECK(dex_file != NULL);
+ CHECK(dex_file != nullptr);
InitializeClasses(class_loader, *dex_file, dex_files, thread_pool, timings);
}
if (IsImage()) {
@@ -1878,7 +1931,7 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi
ThreadPool* thread_pool, TimingLogger* timings) {
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
- CHECK(dex_file != NULL);
+ CHECK(dex_file != nullptr);
CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
}
}
@@ -1911,7 +1964,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz
return;
}
const byte* class_data = dex_file.GetClassData(class_def);
- if (class_data == NULL) {
+ if (class_data == nullptr) {
// empty class, probably a marker interface
return;
}
@@ -1984,7 +2037,7 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
uint32_t method_idx, jobject class_loader,
const DexFile& dex_file,
DexToDexCompilationLevel dex_to_dex_compilation_level) {
- CompiledMethod* compiled_method = NULL;
+ CompiledMethod* compiled_method = nullptr;
uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0;
if ((access_flags & kAccNative) != 0) {
@@ -1994,14 +2047,14 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
// Leaving this empty will trigger the generic JNI version
} else {
compiled_method = compiler_->JniCompile(access_flags, method_idx, dex_file);
- CHECK(compiled_method != NULL);
+ CHECK(compiled_method != nullptr);
}
} else if ((access_flags & kAccAbstract) != 0) {
} else {
MethodReference method_ref(&dex_file, method_idx);
bool compile = verification_results_->IsCandidateForCompilation(method_ref, access_flags);
if (compile) {
- // NOTE: if compiler declines to compile this method, it will return NULL.
+ // NOTE: if compiler declines to compile this method, it will return nullptr.
compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
method_idx, class_loader, dex_file);
}
@@ -2022,20 +2075,20 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
}
Thread* self = Thread::Current();
- if (compiled_method != NULL) {
+ if (compiled_method != nullptr) {
MethodReference ref(&dex_file, method_idx);
- DCHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
+ DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file);
{
MutexLock mu(self, compiled_methods_lock_);
compiled_methods_.Put(ref, compiled_method);
}
- DCHECK(GetCompiledMethod(ref) != NULL) << PrettyMethod(method_idx, dex_file);
+ DCHECK(GetCompiledMethod(ref) != nullptr) << PrettyMethod(method_idx, dex_file);
}
if (self->IsExceptionPending()) {
ScopedObjectAccess soa(self);
LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n"
- << self->GetException(NULL)->Dump();
+ << self->GetException(nullptr)->Dump();
}
}
@@ -2043,9 +2096,9 @@ CompiledClass* CompilerDriver::GetCompiledClass(ClassReference ref) const {
MutexLock mu(Thread::Current(), compiled_classes_lock_);
ClassTable::const_iterator it = compiled_classes_.find(ref);
if (it == compiled_classes_.end()) {
- return NULL;
+ return nullptr;
}
- CHECK(it->second != NULL);
+ CHECK(it->second != nullptr);
return it->second;
}
@@ -2079,9 +2132,9 @@ CompiledMethod* CompilerDriver::GetCompiledMethod(MethodReference ref) const {
MutexLock mu(Thread::Current(), compiled_methods_lock_);
MethodTable::const_iterator it = compiled_methods_.find(ref);
if (it == compiled_methods_.end()) {
- return NULL;
+ return nullptr;
}
- CHECK(it->second != NULL);
+ CHECK(it->second != nullptr);
return it->second;
}