Refactor CompilerDriver::CompileAll().
Treat verification results and image classes as mutable
only in CompilerDriver::PreCompile(), and treat them as
immutable during compilation, accessed through the
CompilerOptions. This severs the dependency of the inliner
on the CompilerDriver.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Change-Id: I594a0213ca6a5003c19b4bd488af98db4358d51d
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 66421e2..be6da71 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -22,6 +22,7 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/callee_save_type.h"
+#include "base/casts.h"
#include "base/enums.h"
#include "base/utils.h"
#include "class_linker.h"
@@ -152,6 +153,10 @@
CreateCompilerDriver();
}
+ // Note: We cannot use MemMap because some tests tear down the Runtime and destroy
+ // the gMaps, so when destroying the MemMap, the test would crash.
+ inaccessible_page_ = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ CHECK(inaccessible_page_ != MAP_FAILED) << strerror(errno);
}
void CommonCompilerTest::ApplyInstructionSet() {
@@ -190,9 +195,7 @@
compiler_options_->image_classes_.swap(*GetImageClasses());
compiler_options_->profile_compilation_info_ = GetProfileCompilationInfo();
compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
- verification_results_.get(),
compiler_kind_,
- &compiler_options_->image_classes_,
number_of_threads_,
/* swap_fd */ -1));
}
@@ -222,6 +225,10 @@
verification_results_.reset();
compiler_options_.reset();
image_reservation_.Reset();
+ if (inaccessible_page_ != nullptr) {
+ munmap(inaccessible_page_, kPageSize);
+ inaccessible_page_ = nullptr;
+ }
CommonRuntimeTest::TearDown();
}
@@ -267,8 +274,16 @@
compiler_driver_->InitializeThreadPools();
- compiler_driver_->PreCompile(class_loader, dex_files, &timings);
+ compiler_driver_->PreCompile(class_loader,
+ dex_files,
+ &timings,
+ &compiler_options_->image_classes_,
+ verification_results_.get());
+ // Verification results in the `callback_` should not be used during compilation.
+ down_cast<QuickCompilerCallbacks*>(callbacks_.get())->SetVerificationResults(
+ reinterpret_cast<VerificationResults*>(inaccessible_page_));
+ compiler_options_->verification_results_ = verification_results_.get();
compiler_driver_->CompileOne(self,
class_loader,
*dex_file,
@@ -279,6 +294,9 @@
code_item,
dex_cache,
h_class_loader);
+ compiler_options_->verification_results_ = nullptr;
+ down_cast<QuickCompilerCallbacks*>(callbacks_.get())->SetVerificationResults(
+ verification_results_.get());
compiler_driver_->FreeThreadPools();
@@ -334,6 +352,32 @@
CHECK(image_reservation_.IsValid()) << error_msg;
}
+void CommonCompilerTest::CompileAll(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) {
+ TimingLogger::ScopedTiming t(__FUNCTION__, timings);
+ SetDexFilesForOatFile(dex_files);
+
+ compiler_driver_->InitializeThreadPools();
+
+ compiler_driver_->PreCompile(class_loader,
+ dex_files,
+ timings,
+ &compiler_options_->image_classes_,
+ verification_results_.get());
+
+ // Verification results in the `callback_` should not be used during compilation.
+ down_cast<QuickCompilerCallbacks*>(callbacks_.get())->SetVerificationResults(
+ reinterpret_cast<VerificationResults*>(inaccessible_page_));
+ compiler_options_->verification_results_ = verification_results_.get();
+ compiler_driver_->CompileAll(class_loader, dex_files, timings);
+ compiler_options_->verification_results_ = nullptr;
+ down_cast<QuickCompilerCallbacks*>(callbacks_.get())->SetVerificationResults(
+ verification_results_.get());
+
+ compiler_driver_->FreeThreadPools();
+}
+
void CommonCompilerTest::UnreserveImageSpace() {
image_reservation_.Reset();
}
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index e6d1564..a71908e 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -20,6 +20,8 @@
#include <list>
#include <vector>
+#include <jni.h>
+
#include "arch/instruction_set.h"
#include "arch/instruction_set_features.h"
#include "base/hash_set.h"
@@ -37,6 +39,7 @@
class CumulativeLogger;
class DexFile;
class ProfileCompilationInfo;
+class TimingLogger;
class VerificationResults;
template<class T> class Handle;
@@ -88,6 +91,10 @@
const char* method_name, const char* signature)
REQUIRES_SHARED(Locks::mutator_lock_);
+ void CompileAll(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings) REQUIRES(!Locks::mutator_lock_);
+
void ApplyInstructionSet();
void OverrideInstructionSetFeatures(InstructionSet instruction_set, const std::string& variant);
@@ -116,6 +123,7 @@
private:
MemMap image_reservation_;
+ void* inaccessible_page_;
// Chunks must not move their storage after being created - use the node-based std::list.
std::list<std::vector<uint8_t>> header_code_and_maps_chunks_;
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 04ad10c..c124ef5 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -528,7 +528,7 @@
class_def_idx,
method_idx,
access_flags,
- driver_->GetVerifiedMethod(&dex_file, method_idx),
+ driver_->GetCompilerOptions().GetVerifiedMethod(&dex_file, method_idx),
hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file)));
std::vector<uint8_t> quicken_data;
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index f61e6c4..b055416 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -39,16 +39,15 @@
class DexToDexDecompilerTest : public CommonCompilerTest {
public:
void CompileAll(jobject class_loader) REQUIRES(!Locks::mutator_lock_) {
- TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
- TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
+ TimingLogger timings("DexToDexDecompilerTest::CompileAll", false, false);
compiler_options_->image_type_ = CompilerOptions::ImageType::kNone;
compiler_options_->SetCompilerFilter(CompilerFilter::kQuicken);
// Create the main VerifierDeps, here instead of in the compiler since we want to aggregate
// the results for all the dex files, not just the results for the current dex file.
down_cast<QuickCompilerCallbacks*>(Runtime::Current()->GetCompilerCallbacks())->SetVerifierDeps(
new verifier::VerifierDeps(GetDexFiles(class_loader)));
- SetDexFilesForOatFile(GetDexFiles(class_loader));
- compiler_driver_->CompileAll(class_loader, GetDexFiles(class_loader), &timings);
+ std::vector<const DexFile*> dex_files = GetDexFiles(class_loader);
+ CommonCompilerTest::CompileAll(class_loader, dex_files, &timings);
}
void RunTest(const char* dex_name) {
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index dd947d9..5a34efb 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -97,7 +97,7 @@
}
}
-const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) {
+const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) const {
const VerifiedMethod* ret = nullptr;
if (atomic_verified_methods_.Get(ref, &ret)) {
return ret;
@@ -129,13 +129,13 @@
DCHECK(IsClassRejected(ref));
}
-bool VerificationResults::IsClassRejected(ClassReference ref) {
+bool VerificationResults::IsClassRejected(ClassReference ref) const {
ReaderMutexLock mu(Thread::Current(), rejected_classes_lock_);
return (rejected_classes_.find(ref) != rejected_classes_.end());
}
bool VerificationResults::IsCandidateForCompilation(MethodReference&,
- const uint32_t access_flags) {
+ const uint32_t access_flags) const {
if (!compiler_options_->IsAotCompilationEnabled()) {
return false;
}
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
index 56f0030..04c4fa6 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -51,13 +51,13 @@
void CreateVerifiedMethodFor(MethodReference ref)
REQUIRES(!verified_methods_lock_);
- const VerifiedMethod* GetVerifiedMethod(MethodReference ref)
+ const VerifiedMethod* GetVerifiedMethod(MethodReference ref) const
REQUIRES(!verified_methods_lock_);
void AddRejectedClass(ClassReference ref) REQUIRES(!rejected_classes_lock_);
- bool IsClassRejected(ClassReference ref) REQUIRES(!rejected_classes_lock_);
+ bool IsClassRejected(ClassReference ref) const REQUIRES(!rejected_classes_lock_);
- bool IsCandidateForCompilation(MethodReference& method_ref, const uint32_t access_flags);
+ bool IsCandidateForCompilation(MethodReference& method_ref, const uint32_t access_flags) const;
// Add a dex file to enable using the atomic map.
void AddDexFile(const DexFile* dex_file) REQUIRES(!verified_methods_lock_);
@@ -74,10 +74,12 @@
// GetVerifiedMethod.
AtomicMap atomic_verified_methods_;
- ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ // TODO: External locking during CompilerDriver::PreCompile(), no locking during compilation.
+ mutable ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
// Rejected classes.
- ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ // TODO: External locking during CompilerDriver::PreCompile(), no locking during compilation.
+ mutable ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
std::set<ClassReference> rejected_classes_ GUARDED_BY(rejected_classes_lock_);
friend class verifier::VerifierDepsTest;
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 792f508..63dcb46 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -99,11 +99,6 @@
return std::make_pair(fast_get, fast_put);
}
-inline VerificationResults* CompilerDriver::GetVerificationResults() const {
- DCHECK(Runtime::Current()->IsAotCompiler());
- return verification_results_;
-}
-
} // namespace art
#endif // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 67cabef..18f7105 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -245,16 +245,12 @@
CompilerDriver::CompilerDriver(
const CompilerOptions* compiler_options,
- VerificationResults* verification_results,
Compiler::Kind compiler_kind,
- HashSet<std::string>* image_classes,
size_t thread_count,
int swap_fd)
: compiler_options_(compiler_options),
- verification_results_(verification_results),
compiler_(Compiler::Create(this, compiler_kind)),
compiler_kind_(compiler_kind),
- image_classes_(std::move(image_classes)),
number_of_soft_verifier_failures_(0),
had_hard_verifier_failure_(false),
parallel_thread_count_(thread_count),
@@ -266,10 +262,6 @@
compiler_->Init();
- if (GetCompilerOptions().IsBootImage()) {
- CHECK(image_classes_ != nullptr) << "Expected image classes for boot image";
- }
-
compiled_method_storage_.SetDedupeEnabled(compiler_options_->DeduplicateCode());
}
@@ -325,9 +317,8 @@
TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
- InitializeThreadPools();
+ CheckThreadPools();
- PreCompile(class_loader, dex_files, timings);
if (GetCompilerOptions().IsBootImage()) {
// We don't need to setup the intrinsics for non boot image compilation, as
// those compilations will pick up a boot image that have the ArtMethod already
@@ -343,8 +334,6 @@
if (GetCompilerOptions().GetDumpStats()) {
stats_->Dump();
}
-
- FreeThreadPools();
}
static optimizer::DexToDexCompiler::CompilationLevel GetDexToDexCompilationLevel(
@@ -496,7 +485,7 @@
optimizer::DexToDexCompiler* const compiler = &driver->GetDexToDexCompiler();
if (compiler->ShouldCompileMethod(method_ref)) {
- VerificationResults* results = driver->GetVerificationResults();
+ const VerificationResults* results = driver->GetCompilerOptions().GetVerificationResults();
DCHECK(results != nullptr);
const VerifiedMethod* verified_method = results->GetVerifiedMethod(method_ref);
// Do not optimize if a VerifiedMethod is missing. SafeCast elision,
@@ -574,7 +563,7 @@
} else if ((access_flags & kAccAbstract) != 0) {
// Abstract methods don't have code.
} else {
- VerificationResults* results = driver->GetVerificationResults();
+ const VerificationResults* results = driver->GetCompilerOptions().GetVerificationResults();
DCHECK(results != nullptr);
const VerifiedMethod* verified_method = results->GetVerifiedMethod(method_ref);
bool compile =
@@ -881,7 +870,9 @@
void CompilerDriver::PreCompile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings) {
+ TimingLogger* timings,
+ /*inout*/ HashSet<std::string>* image_classes,
+ /*out*/ VerificationResults* verification_results) {
CheckThreadPools();
VLOG(compiler) << "Before precompile " << GetMemoryUsageString(false);
@@ -898,7 +889,7 @@
// 6) Update the set of image classes.
// 7) For deterministic boot image, initialize bitstrings for type checking.
- LoadImageClasses(timings);
+ LoadImageClasses(timings, image_classes);
VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(false);
if (compiler_options_->IsAnyCompilationEnabled()) {
@@ -932,7 +923,7 @@
ResolveConstStrings(dex_files, /*only_startup_strings=*/ true, timings);
}
- Verify(class_loader, dex_files, timings);
+ Verify(class_loader, dex_files, timings, verification_results);
VLOG(compiler) << "Verify: " << GetMemoryUsageString(false);
if (had_hard_verifier_failure_ && GetCompilerOptions().AbortOnHardVerifierFailure()) {
@@ -957,7 +948,7 @@
VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
}
- UpdateImageClasses(timings);
+ UpdateImageClasses(timings, image_classes);
VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString(false);
if (kBitstringSubtypeCheckEnabled &&
@@ -1071,7 +1062,8 @@
};
// Make a list of descriptors for classes to include in the image
-void CompilerDriver::LoadImageClasses(TimingLogger* timings) {
+void CompilerDriver::LoadImageClasses(TimingLogger* timings,
+ /*inout*/ HashSet<std::string>* image_classes) {
CHECK(timings != nullptr);
if (!GetCompilerOptions().IsBootImage()) {
return;
@@ -1082,15 +1074,15 @@
Thread* self = Thread::Current();
ScopedObjectAccess soa(self);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- CHECK(image_classes_ != nullptr);
- for (auto it = image_classes_->begin(), end = image_classes_->end(); it != end;) {
+ CHECK(image_classes != nullptr);
+ for (auto it = image_classes->begin(), end = image_classes->end(); it != end;) {
const std::string& descriptor(*it);
StackHandleScope<1> hs(self);
Handle<mirror::Class> klass(
hs.NewHandle(class_linker->FindSystemClass(self, descriptor.c_str())));
if (klass == nullptr) {
VLOG(compiler) << "Failed to find class " << descriptor;
- it = image_classes_->erase(it);
+ it = image_classes->erase(it);
self->ClearException();
} else {
++it;
@@ -1140,10 +1132,10 @@
// We walk the roots looking for classes so that we'll pick up the
// above classes plus any classes them depend on such super
// classes, interfaces, and the required ClassLinker roots.
- RecordImageClassesVisitor visitor(image_classes_);
+ RecordImageClassesVisitor visitor(image_classes);
class_linker->VisitClasses(&visitor);
- CHECK(!image_classes_->empty());
+ CHECK(!image_classes->empty());
}
static void MaybeAddToImageClasses(Thread* self,
@@ -1312,7 +1304,8 @@
DISALLOW_COPY_AND_ASSIGN(ClinitImageUpdate);
};
-void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
+void CompilerDriver::UpdateImageClasses(TimingLogger* timings,
+ /*inout*/ HashSet<std::string>* image_classes) {
if (GetCompilerOptions().IsBootImage()) {
TimingLogger::ScopedTiming t("UpdateImageClasses", timings);
@@ -1324,7 +1317,7 @@
VariableSizedHandleScope hs(Thread::Current());
std::string error_msg;
std::unique_ptr<ClinitImageUpdate> update(ClinitImageUpdate::Create(hs,
- image_classes_,
+ image_classes,
Thread::Current(),
runtime->GetClassLinker()));
@@ -1393,12 +1386,6 @@
}
}
-const VerifiedMethod* CompilerDriver::GetVerifiedMethod(const DexFile* dex_file,
- uint32_t method_idx) const {
- MethodReference ref(dex_file, method_idx);
- return verification_results_->GetVerifiedMethod(ref);
-}
-
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.
@@ -1764,7 +1751,8 @@
bool CompilerDriver::FastVerify(jobject jclass_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings) {
+ TimingLogger* timings,
+ /*out*/ VerificationResults* verification_results) {
verifier::VerifierDeps* verifier_deps =
Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps();
// If there exist VerifierDeps that aren't the ones we just created to output, use them to verify.
@@ -1812,7 +1800,7 @@
// - Quickening will not do checkcast ellision.
// TODO(ngeoffray): Reconsider this once we refactor compiler filters.
for (const ClassAccessor::Method& method : accessor.GetMethods()) {
- verification_results_->CreateVerifiedMethodFor(method.GetReference());
+ verification_results->CreateVerifiedMethodFor(method.GetReference());
}
}
} else if (!compiler_only_verifies) {
@@ -1830,8 +1818,9 @@
void CompilerDriver::Verify(jobject jclass_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings) {
- if (FastVerify(jclass_loader, dex_files, timings)) {
+ TimingLogger* timings,
+ /*out*/ VerificationResults* verification_results) {
+ if (FastVerify(jclass_loader, dex_files, timings, verification_results)) {
return;
}
@@ -2530,7 +2519,7 @@
// SetVerificationAttempted so that the access flags are set. If we do not do this they get
// changed at runtime resulting in more dirty image pages.
// Also create conflict tables.
- // Only useful if we are compiling an image (image_classes_ is not null).
+ // Only useful if we are compiling an image.
ScopedObjectAccess soa(Thread::Current());
VariableSizedHandleScope hs(soa.Self());
InitializeArrayClassesAndCreateConflictTablesVisitor visitor(hs);
@@ -2569,8 +2558,9 @@
ClassReference ref(&dex_file, class_def_index);
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
ClassAccessor accessor(dex_file, class_def_index);
+ CompilerDriver* const driver = context.GetCompiler();
// Skip compiling classes with generic verifier failures since they will still fail at runtime
- if (context.GetCompiler()->GetVerificationResults()->IsClassRejected(ref)) {
+ if (driver->GetCompilerOptions().GetVerificationResults()->IsClassRejected(ref)) {
return;
}
// Use a scoped object access to perform to the quick SkipClass check.
@@ -2602,8 +2592,6 @@
// Go to native so that we don't block GC during compilation.
ScopedThreadSuspension sts(soa.Self(), kNative);
- CompilerDriver* const driver = context.GetCompiler();
-
// Can we run DEX-to-DEX compiler on this class ?
optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level =
GetDexToDexCompilationLevel(soa.Self(), *driver, jclass_loader, dex_file, class_def);
@@ -2775,31 +2763,6 @@
return compiled_method;
}
-bool CompilerDriver::IsMethodVerifiedWithoutFailures(uint32_t method_idx,
- uint16_t class_def_idx,
- const DexFile& dex_file) const {
- const VerifiedMethod* verified_method = GetVerifiedMethod(&dex_file, method_idx);
- if (verified_method != nullptr) {
- return !verified_method->HasVerificationFailures();
- }
-
- // If we can't find verification metadata, check if this is a system class (we trust that system
- // classes have their methods verified). If it's not, be conservative and assume the method
- // has not been verified successfully.
-
- // TODO: When compiling the boot image it should be safe to assume that everything is verified,
- // even if methods are not found in the verification cache.
- const char* descriptor = dex_file.GetClassDescriptor(dex_file.GetClassDef(class_def_idx));
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Thread* self = Thread::Current();
- ScopedObjectAccess soa(self);
- bool is_system_class = class_linker->FindSystemClass(self, descriptor) != nullptr;
- if (!is_system_class) {
- self->ClearException();
- }
- return is_system_class;
-}
-
std::string CompilerDriver::GetMemoryUsageString(bool extended) const {
std::ostringstream oss;
const gc::Heap* const heap = Runtime::Current()->GetHeap();
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 714b2d1..7c0fc64 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -76,7 +76,6 @@
class TimingLogger;
class VdexFile;
class VerificationResults;
-class VerifiedMethod;
enum EntryPointCallingConvention {
// ABI of invocations to a method's interpreter entry point.
@@ -95,9 +94,7 @@
// can assume will be in the image, with null implying all available
// classes.
CompilerDriver(const CompilerOptions* compiler_options,
- VerificationResults* verification_results,
Compiler::Kind compiler_kind,
- HashSet<std::string>* image_classes,
size_t thread_count,
int swap_fd);
@@ -106,6 +103,17 @@
// Set dex files classpath.
void SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files);
+ // Initialize and destroy thread pools. This is exposed because we do not want
+ // to do this twice, for PreCompile() and CompileAll().
+ void InitializeThreadPools();
+ void FreeThreadPools();
+
+ void PreCompile(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ TimingLogger* timings,
+ /*inout*/ HashSet<std::string>* image_classes,
+ /*out*/ VerificationResults* verification_results)
+ REQUIRES(!Locks::mutator_lock_);
void CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings)
@@ -124,8 +132,6 @@
Handle<mirror::ClassLoader> h_class_loader)
REQUIRES(!Locks::mutator_lock_);
- VerificationResults* GetVerificationResults() const;
-
const CompilerOptions& GetCompilerOptions() const {
return *compiler_options_;
}
@@ -194,7 +200,6 @@
REQUIRES_SHARED(Locks::mutator_lock_);
- const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const;
bool IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc);
size_t GetThreadCount() const {
@@ -219,12 +224,6 @@
void RecordClassStatus(const ClassReference& ref, ClassStatus status);
- // Checks if the specified method has been verified without failures. Returns
- // false if the method is not in the verification results (GetVerificationResults).
- bool IsMethodVerifiedWithoutFailures(uint32_t method_idx,
- uint16_t class_def_idx,
- const DexFile& dex_file) const;
-
// Get memory usage during compilation.
std::string GetMemoryUsageString(bool extended) const;
@@ -265,13 +264,9 @@
}
private:
- void PreCompile(jobject class_loader,
- const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings)
+ void LoadImageClasses(TimingLogger* timings, /*inout*/ HashSet<std::string>* image_classes)
REQUIRES(!Locks::mutator_lock_);
- void LoadImageClasses(TimingLogger* timings) REQUIRES(!Locks::mutator_lock_);
-
// Attempt to resolve all type, methods, fields, and strings
// referenced from code in the dex file following PathClassLoader
// ordering semantics.
@@ -291,11 +286,13 @@
// verification was successful.
bool FastVerify(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings);
+ TimingLogger* timings,
+ /*out*/ VerificationResults* verification_results);
void Verify(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- TimingLogger* timings);
+ TimingLogger* timings,
+ /*out*/ VerificationResults* verification_results);
void VerifyDexFile(jobject class_loader,
const DexFile& dex_file,
@@ -326,14 +323,13 @@
TimingLogger* timings)
REQUIRES(!Locks::mutator_lock_);
- void UpdateImageClasses(TimingLogger* timings) REQUIRES(!Locks::mutator_lock_);
+ void UpdateImageClasses(TimingLogger* timings, /*inout*/ HashSet<std::string>* image_classes)
+ REQUIRES(!Locks::mutator_lock_);
void Compile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings);
- void InitializeThreadPools();
- void FreeThreadPools();
void CheckThreadPools();
// Resolve const string literals that are loaded from dex code. If only_startup_strings is
@@ -343,7 +339,6 @@
/*inout*/ TimingLogger* timings);
const CompilerOptions* const compiler_options_;
- VerificationResults* const verification_results_;
std::unique_ptr<Compiler> compiler_;
Compiler::Kind compiler_kind_;
@@ -359,12 +354,6 @@
// All method references that this compiler has compiled.
MethodTable compiled_methods_;
- // Image classes to be updated by PreCompile().
- // TODO: Remove this member which is a non-const pointer to the CompilerOptions' data.
- // Pass this explicitly to the PreCompile() which should be called directly from
- // Dex2Oat rather than implicitly by CompileAll().
- HashSet<std::string>* image_classes_;
-
std::atomic<uint32_t> number_of_soft_verifier_failures_;
bool had_hard_verifier_failure_;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index fe1568d..b924129 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -42,20 +42,18 @@
class CompilerDriverTest : public CommonCompilerTest {
protected:
- void CompileAll(jobject class_loader) REQUIRES(!Locks::mutator_lock_) {
- TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
- TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
+ void CompileAllAndMakeExecutable(jobject class_loader) REQUIRES(!Locks::mutator_lock_) {
+ TimingLogger timings("CompilerDriverTest::CompileAllAndMakeExecutable", false, false);
dex_files_ = GetDexFiles(class_loader);
- SetDexFilesForOatFile(dex_files_);
- compiler_driver_->CompileAll(class_loader, dex_files_, &timings);
- t.NewTiming("MakeAllExecutable");
+ CompileAll(class_loader, dex_files_, &timings);
+ TimingLogger::ScopedTiming t("MakeAllExecutable", &timings);
MakeAllExecutable(class_loader);
}
void EnsureCompiled(jobject class_loader, const char* class_name, const char* method,
const char* signature, bool is_virtual)
REQUIRES(!Locks::mutator_lock_) {
- CompileAll(class_loader);
+ CompileAllAndMakeExecutable(class_loader);
Thread::Current()->TransitionFromSuspendedToRunnable();
bool started = runtime_->Start();
CHECK(started);
@@ -106,7 +104,7 @@
// Disabled due to 10 second runtime on host
// TODO: Update the test for hash-based dex cache arrays. Bug: 30627598
TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) {
- CompileAll(nullptr);
+ CompileAllAndMakeExecutable(nullptr);
// All libcore references should resolve
ScopedObjectAccess soa(Thread::Current());
@@ -266,7 +264,7 @@
ASSERT_TRUE(dex_file->EnableWrite());
}
- CompileAll(class_loader);
+ CompileAllAndMakeExecutable(class_loader);
std::unordered_set<std::string> m = GetExpectedMethodsForClass("Main");
std::unordered_set<std::string> s = GetExpectedMethodsForClass("Second");
@@ -310,7 +308,7 @@
}
ASSERT_NE(class_loader, nullptr);
- CompileAll(class_loader);
+ CompileAllAndMakeExecutable(class_loader);
CheckVerifiedClass(class_loader, "LMain;");
CheckVerifiedClass(class_loader, "LSecond;");
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index b28c7e0..8d1ae3d 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -24,9 +24,14 @@
#include "arch/instruction_set_features.h"
#include "base/runtime_debug.h"
#include "base/variant_map.h"
+#include "class_linker.h"
#include "cmdline_parser.h"
#include "compiler_options_map-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/verification_results.h"
+#include "dex/verified_method.h"
#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
#include "simple_compiler_options_map.h"
namespace art {
@@ -44,6 +49,7 @@
no_inline_from_(),
dex_files_for_oat_file_(),
image_classes_(),
+ verification_results_(nullptr),
image_type_(ImageType::kNone),
compiling_with_core_image_(false),
baseline_(false),
@@ -141,4 +147,40 @@
return image_classes_.find(StringPiece(descriptor)) != image_classes_.end();
}
+const VerificationResults* CompilerOptions::GetVerificationResults() const {
+ DCHECK(Runtime::Current()->IsAotCompiler());
+ return verification_results_;
+}
+
+const VerifiedMethod* CompilerOptions::GetVerifiedMethod(const DexFile* dex_file,
+ uint32_t method_idx) const {
+ MethodReference ref(dex_file, method_idx);
+ return verification_results_->GetVerifiedMethod(ref);
+}
+
+bool CompilerOptions::IsMethodVerifiedWithoutFailures(uint32_t method_idx,
+ uint16_t class_def_idx,
+ const DexFile& dex_file) const {
+ const VerifiedMethod* verified_method = GetVerifiedMethod(&dex_file, method_idx);
+ if (verified_method != nullptr) {
+ return !verified_method->HasVerificationFailures();
+ }
+
+ // If we can't find verification metadata, check if this is a system class (we trust that system
+ // classes have their methods verified). If it's not, be conservative and assume the method
+ // has not been verified successfully.
+
+ // TODO: When compiling the boot image it should be safe to assume that everything is verified,
+ // even if methods are not found in the verification cache.
+ const char* descriptor = dex_file.GetClassDescriptor(dex_file.GetClassDef(class_def_idx));
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+ bool is_system_class = class_linker->FindSystemClass(self, descriptor) != nullptr;
+ if (!is_system_class) {
+ self->ClearException();
+ }
+ return is_system_class;
+}
+
} // namespace art
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index a8f246d..bd12bf7 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -47,6 +47,8 @@
enum class InstructionSet;
class InstructionSetFeatures;
class ProfileCompilationInfo;
+class VerificationResults;
+class VerifiedMethod;
// Enum for CheckProfileMethodsCompiled. Outside CompilerOptions so it can be forward-declared.
enum class ProfileMethodsCheck : uint8_t {
@@ -283,6 +285,16 @@
bool IsImageClass(const char* descriptor) const;
+ const VerificationResults* GetVerificationResults() const;
+
+ const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const;
+
+ // Checks if the specified method has been verified without failures. Returns
+ // false if the method is not in the verification results (GetVerificationResults).
+ bool IsMethodVerifiedWithoutFailures(uint32_t method_idx,
+ uint16_t class_def_idx,
+ const DexFile& dex_file) const;
+
bool ParseCompilerOptions(const std::vector<std::string>& options,
bool ignore_unrecognized,
std::string* error_msg);
@@ -381,6 +393,9 @@
// Must not be empty for real boot image, only for tests pretending to compile boot image.
HashSet<std::string> image_classes_;
+ // Results of AOT verification.
+ const VerificationResults* verification_results_;
+
ImageType image_type_;
bool compiling_with_core_image_;
bool baseline_;
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 0eab835..b9fd868 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -167,9 +167,7 @@
compiler_driver_.reset(new CompilerDriver(
compiler_options_.get(),
- /* verification_results */ nullptr,
Compiler::kOptimizing,
- /* image_classes */ nullptr,
/* thread_count */ 1,
/* swap_fd */ -1));
// Disable dedupe so we can remove compiled methods.
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index ec93222..417d794 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -28,7 +28,6 @@
#include "dex/inline_method_analyser.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
-#include "driver/compiler_driver-inl.h"
#include "driver/compiler_options.h"
#include "driver/dex_compilation_unit.h"
#include "instruction_simplifier.h"
@@ -408,7 +407,7 @@
return single_impl;
}
-static bool IsMethodUnverified(CompilerDriver* const compiler_driver, ArtMethod* method)
+static bool IsMethodUnverified(const CompilerOptions& compiler_options, ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (!method->GetDeclaringClass()->IsVerified()) {
if (Runtime::Current()->UseJitCompilation()) {
@@ -417,8 +416,9 @@
return true;
}
uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex();
- if (!compiler_driver->IsMethodVerifiedWithoutFailures(
- method->GetDexMethodIndex(), class_def_idx, *method->GetDexFile())) {
+ if (!compiler_options.IsMethodVerifiedWithoutFailures(method->GetDexMethodIndex(),
+ class_def_idx,
+ *method->GetDexFile())) {
// Method has soft or hard failures, don't analyze.
return true;
}
@@ -426,11 +426,11 @@
return false;
}
-static bool AlwaysThrows(CompilerDriver* const compiler_driver, ArtMethod* method)
+static bool AlwaysThrows(const CompilerOptions& compiler_options, ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(method != nullptr);
// Skip non-compilable and unverified methods.
- if (!method->IsCompilable() || IsMethodUnverified(compiler_driver, method)) {
+ if (!method->IsCompilable() || IsMethodUnverified(compiler_options, method)) {
return false;
}
// Skip native methods, methods with try blocks, and methods that are too large.
@@ -518,7 +518,7 @@
MaybeRecordStat(stats_, MethodCompilationStat::kInlinedInvokeVirtualOrInterface);
}
}
- } else if (!cha_devirtualize && AlwaysThrows(compiler_driver_, actual_method)) {
+ } else if (!cha_devirtualize && AlwaysThrows(codegen_->GetCompilerOptions(), actual_method)) {
// Set always throws property for non-inlined method call with single target
// (unless it was obtained through CHA, because that would imply we have
// to add the CHA dependency, which seems not worth it).
@@ -1500,7 +1500,7 @@
return false;
}
- if (IsMethodUnverified(compiler_driver_, method)) {
+ if (IsMethodUnverified(codegen_->GetCompilerOptions(), method)) {
LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotVerified)
<< "Method " << method->PrettyMethod()
<< " couldn't be verified, so it cannot be inlined";
@@ -2069,7 +2069,6 @@
codegen_,
outer_compilation_unit_,
dex_compilation_unit,
- compiler_driver_,
handles_,
inline_stats_,
total_number_of_dex_registers_ + accessor.RegistersSize(),
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 6fd0c20..8ac2163 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -38,7 +38,6 @@
CodeGenerator* codegen,
const DexCompilationUnit& outer_compilation_unit,
const DexCompilationUnit& caller_compilation_unit,
- CompilerDriver* compiler_driver,
VariableSizedHandleScope* handles,
OptimizingCompilerStats* stats,
size_t total_number_of_dex_registers,
@@ -51,7 +50,6 @@
outer_compilation_unit_(outer_compilation_unit),
caller_compilation_unit_(caller_compilation_unit),
codegen_(codegen),
- compiler_driver_(compiler_driver),
total_number_of_dex_registers_(total_number_of_dex_registers),
total_number_of_instructions_(total_number_of_instructions),
parent_(parent),
@@ -280,7 +278,6 @@
const DexCompilationUnit& outer_compilation_unit_;
const DexCompilationUnit& caller_compilation_unit_;
CodeGenerator* const codegen_;
- CompilerDriver* const compiler_driver_;
const size_t total_number_of_dex_registers_;
size_t total_number_of_instructions_;
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index 0f971e1..b75afad 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -181,7 +181,6 @@
HGraph* graph,
OptimizingCompilerStats* stats,
CodeGenerator* codegen,
- CompilerDriver* driver,
const DexCompilationUnit& dex_compilation_unit,
VariableSizedHandleScope* handles) {
ArenaVector<HOptimization*> optimizations(allocator->Adapter());
@@ -258,7 +257,6 @@
codegen,
dex_compilation_unit, // outer_compilation_unit
dex_compilation_unit, // outermost_compilation_unit
- driver,
handles,
stats,
accessor.RegistersSize(),
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index 490007d..ce44b5f 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -147,7 +147,6 @@
HGraph* graph,
OptimizingCompilerStats* stats,
CodeGenerator* codegen,
- CompilerDriver* driver,
const DexCompilationUnit& dex_compilation_unit,
VariableSizedHandleScope* handles);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 1d3fcf3..52335d3 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -321,7 +321,6 @@
graph,
compilation_stats_.get(),
codegen,
- GetCompilerDriver(),
dex_compilation_unit,
handles);
DCHECK_EQ(length, optimizations.size());
@@ -962,9 +961,9 @@
arena_stack,
dex_file,
method_idx,
- compiler_driver->GetCompilerOptions().GetInstructionSet(),
+ compiler_options.GetInstructionSet(),
kInvalidInvokeType,
- compiler_driver->GetCompilerOptions().GetDebuggable(),
+ compiler_options.GetDebuggable(),
/* osr */ false);
DCHECK(Runtime::Current()->IsAotCompiler());
@@ -1043,12 +1042,13 @@
const DexFile& dex_file,
Handle<mirror::DexCache> dex_cache) const {
CompilerDriver* compiler_driver = GetCompilerDriver();
+ const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions();
CompiledMethod* compiled_method = nullptr;
Runtime* runtime = Runtime::Current();
DCHECK(runtime->IsAotCompiler());
- const VerifiedMethod* verified_method = compiler_driver->GetVerifiedMethod(&dex_file, method_idx);
+ const VerifiedMethod* verified_method = compiler_options.GetVerifiedMethod(&dex_file, method_idx);
DCHECK(!verified_method->HasRuntimeThrow());
- if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) ||
+ if (compiler_options.IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) ||
verifier::CanCompilerHandleVerificationFailure(
verified_method->GetEncounteredVerificationFailures())) {
ArenaAllocator allocator(runtime->GetArenaPool());
@@ -1080,7 +1080,7 @@
// Go to native so that we don't block GC during compilation.
ScopedThreadSuspension sts(soa.Self(), kNative);
if (method != nullptr && UNLIKELY(method->IsIntrinsic())) {
- DCHECK(compiler_driver->GetCompilerOptions().IsBootImage());
+ DCHECK(compiler_options.IsBootImage());
codegen.reset(
TryCompileIntrinsic(&allocator,
&arena_stack,
@@ -1099,7 +1099,7 @@
&code_allocator,
dex_compilation_unit,
method,
- compiler_driver->GetCompilerOptions().IsBaseline(),
+ compiler_options.IsBaseline(),
/* osr= */ false,
&handles));
}
@@ -1128,7 +1128,7 @@
}
} else {
MethodCompilationStat method_stat;
- if (compiler_driver->GetCompilerOptions().VerifyAtRuntime()) {
+ if (compiler_options.VerifyAtRuntime()) {
method_stat = MethodCompilationStat::kNotCompiledVerifyAtRuntime;
} else {
method_stat = MethodCompilationStat::kNotCompiledVerificationError;
@@ -1137,8 +1137,8 @@
}
if (kIsDebugBuild &&
- compiler_driver->GetCompilerOptions().CompilingWithCoreImage() &&
- IsInstructionSetSupported(compiler_driver->GetCompilerOptions().GetInstructionSet())) {
+ compiler_options.CompilingWithCoreImage() &&
+ IsInstructionSetSupported(compiler_options.GetInstructionSet())) {
// For testing purposes, we put a special marker on method names
// that should be compiled with this compiler (when the
// instruction set is supported). This makes sure we're not
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index eb44dd7..8c90aa7 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -93,12 +93,12 @@
verifier_deps_.reset(deps);
}
callbacks_->SetVerifierDeps(deps);
- compiler_driver_->Verify(class_loader_, dex_files_, &timings);
+ compiler_driver_->Verify(class_loader_, dex_files_, &timings, verification_results_.get());
callbacks_->SetVerifierDeps(nullptr);
// Clear entries in the verification results to avoid hitting a DCHECK that
// we always succeed inserting a new entry after verifying.
AtomicDexRefMap<MethodReference, const VerifiedMethod*>* map =
- &compiler_driver_->GetVerificationResults()->atomic_verified_methods_;
+ &verification_results_->atomic_verified_methods_;
map->Visit([](const DexFileReference& ref ATTRIBUTE_UNUSED, const VerifiedMethod* method) {
delete method;
});
@@ -126,7 +126,7 @@
class_linker_->RegisterDexFile(*dex_file, loader.Get());
}
for (const DexFile* dex_file : dex_files_) {
- compiler_driver_->GetVerificationResults()->AddDexFile(dex_file);
+ verification_results_->AddDexFile(dex_file);
}
SetDexFilesForOatFile(dex_files_);
}