diff options
-rw-r--r-- | compiler/dex/quick_compiler_callbacks.h | 9 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 59 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 5 | ||||
-rw-r--r-- | compiler/driver/compiler_driver_test.cc | 1 | ||||
-rw-r--r-- | compiler/image_test.cc | 2 | ||||
-rw-r--r-- | compiler/oat_test.cc | 8 | ||||
-rw-r--r-- | compiler/verifier_deps_test.cc | 133 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 15 | ||||
-rw-r--r-- | runtime/compiler_callbacks.h | 1 | ||||
-rw-r--r-- | runtime/verifier/verifier_deps.cc | 3 | ||||
-rw-r--r-- | runtime/verifier/verifier_deps.h | 12 |
11 files changed, 198 insertions, 50 deletions
diff --git a/compiler/dex/quick_compiler_callbacks.h b/compiler/dex/quick_compiler_callbacks.h index 34fd88b498..db0fdaa72f 100644 --- a/compiler/dex/quick_compiler_callbacks.h +++ b/compiler/dex/quick_compiler_callbacks.h @@ -18,6 +18,7 @@ #define ART_COMPILER_DEX_QUICK_COMPILER_CALLBACKS_H_ #include "compiler_callbacks.h" +#include "verifier/verifier_deps.h" namespace art { @@ -46,16 +47,16 @@ class QuickCompilerCallbacks FINAL : public CompilerCallbacks { } verifier::VerifierDeps* GetVerifierDeps() const OVERRIDE { - return verifier_deps_; + return verifier_deps_.get(); } - void SetVerifierDeps(verifier::VerifierDeps* deps) { - verifier_deps_ = deps; + void SetVerifierDeps(verifier::VerifierDeps* deps) OVERRIDE { + verifier_deps_.reset(deps); } private: VerificationResults* const verification_results_; - verifier::VerifierDeps* verifier_deps_; + std::unique_ptr<verifier::VerifierDeps> verifier_deps_; }; } // namespace art diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 1b87725230..7d045b1d73 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -39,6 +39,7 @@ #include "compiled_class.h" #include "compiled_method.h" #include "compiler.h" +#include "compiler_callbacks.h" #include "compiler_driver-inl.h" #include "dex_compilation_unit.h" #include "dex_file-inl.h" @@ -393,6 +394,7 @@ static void SetupIntrinsic(Thread* self, void CompilerDriver::CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files, + verifier::VerifierDeps* verifier_deps, TimingLogger* timings) { DCHECK(!Runtime::Current()->IsStarted()); @@ -404,7 +406,7 @@ void CompilerDriver::CompileAll(jobject class_loader, // 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, timings); + PreCompile(class_loader, dex_files, verifier_deps, 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 @@ -676,7 +678,7 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t InitializeThreadPools(); - PreCompile(jclass_loader, dex_files, timings); + PreCompile(jclass_loader, dex_files, /* verifier_deps */ nullptr, timings); // Can we run DEX-to-DEX compiler on this class ? optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level = @@ -873,6 +875,7 @@ inline void CompilerDriver::CheckThreadPools() { void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, + verifier::VerifierDeps* verifier_deps, TimingLogger* timings) { CheckThreadPools(); @@ -906,7 +909,7 @@ void CompilerDriver::PreCompile(jobject class_loader, VLOG(compiler) << "Resolve const-strings: " << GetMemoryUsageString(false); } - Verify(class_loader, dex_files, timings); + Verify(class_loader, dex_files, verifier_deps, timings); VLOG(compiler) << "Verify: " << GetMemoryUsageString(false); if (had_hard_verifier_failure_ && GetCompilerOptions().AbortOnHardVerifierFailure()) { @@ -1932,15 +1935,61 @@ void CompilerDriver::SetVerified(jobject class_loader, } } -void CompilerDriver::Verify(jobject class_loader, +void CompilerDriver::Verify(jobject jclass_loader, const std::vector<const DexFile*>& dex_files, + verifier::VerifierDeps* verifier_deps, TimingLogger* timings) { + if (verifier_deps != nullptr) { + TimingLogger::ScopedTiming t("Fast Verify", timings); + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<2> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader( + hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader))); + MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(nullptr)); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + if (verifier_deps->ValidateDependencies(class_loader, soa.Self())) { + // We successfully validated the dependencies, now update class status + // of verified classes. Note that the dependencies also record which classes + // could not be fully verified; we could try again, but that would hurt verification + // time. So instead we assume these classes still need to be verified at + // runtime. + for (const DexFile* dex_file : dex_files) { + // Fetch the list of unverified classes and turn it into a set for faster + // lookups. + const std::vector<uint16_t>& unverified_classes = + verifier_deps->GetUnverifiedClasses(*dex_file); + std::set<uint16_t> set(unverified_classes.begin(), unverified_classes.end()); + for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) { + const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); + const char* descriptor = dex_file->GetClassDescriptor(class_def); + cls.Assign(class_linker->FindClass(soa.Self(), descriptor, class_loader)); + if (cls.Get() == nullptr) { + CHECK(soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); + } else if (set.find(class_def.class_idx_) == set.end()) { + ObjectLock<mirror::Class> lock(soa.Self(), cls); + mirror::Class::SetStatus(cls, mirror::Class::kStatusVerified, soa.Self()); + } + } + } + return; + } + } + + // If there is no passed `verifier_deps` (because of non-existing vdex), or + // the passed `verifier_deps` is not valid anymore, create a new one for + // non boot image compilation. The verifier will need it to record the new dependencies. + // Then dex2oat can update the vdex file with these new dependencies. + if (!GetCompilerOptions().IsBootImage()) { + Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps( + new verifier::VerifierDeps(dex_files)); + } // 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, + VerifyDexFile(jclass_loader, *dex_file, dex_files, parallel_thread_pool_.get(), diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 4a48f9c841..c8d6cb0d4d 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -50,6 +50,7 @@ class DexCache; namespace verifier { class MethodVerifier; +class VerifierDeps; class VerifierDepsTest; } // namespace verifier @@ -117,6 +118,7 @@ class CompilerDriver { void CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files, + verifier::VerifierDeps* verifier_deps, TimingLogger* timings) REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_, !dex_to_dex_references_lock_); @@ -415,6 +417,7 @@ class CompilerDriver { private: void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, + verifier::VerifierDeps* verifier_deps, TimingLogger* timings) REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_); @@ -437,7 +440,9 @@ class CompilerDriver { void Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files, + verifier::VerifierDeps* verifier_deps, TimingLogger* timings); + void VerifyDexFile(jobject class_loader, const DexFile& dex_file, const std::vector<const DexFile*>& dex_files, diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 845028d427..9679a796cb 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -43,6 +43,7 @@ class CompilerDriverTest : public CommonCompilerTest { TimingLogger::ScopedTiming t(__FUNCTION__, &timings); compiler_driver_->CompileAll(class_loader, GetDexFiles(class_loader), + /* verifier_deps */ nullptr, &timings); t.NewTiming("MakeAllExecutable"); MakeAllExecutable(class_loader); diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 8fdf6fca68..fcb8979459 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -189,7 +189,7 @@ void CompilationHelper::Compile(CompilerDriver* driver, TimingLogger timings("ImageTest::WriteRead", false, false); TimingLogger::ScopedTiming t("CompileAll", &timings); driver->SetDexFilesForOatFile(class_path); - driver->CompileAll(class_loader, class_path, &timings); + driver->CompileAll(class_loader, class_path, /* verifier_deps */ nullptr, &timings); t.NewTiming("WriteElf"); SafeMap<std::string, std::string> key_value_store; diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 64ee574889..102637f01b 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -377,7 +377,8 @@ TEST_F(OatTest, WriteRead) { if (kCompile) { TimingLogger timings2("OatTest::WriteRead", false, false); compiler_driver_->SetDexFilesForOatFile(class_linker->GetBootClassPath()); - compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings2); + compiler_driver_->CompileAll( + class_loader, class_linker->GetBootClassPath(), /* verifier_deps */ nullptr, &timings2); } ScratchFile tmp_oat, tmp_vdex(tmp_oat, ".vdex"); @@ -391,7 +392,8 @@ TEST_F(OatTest, WriteRead) { ASSERT_TRUE(success); if (kCompile) { // OatWriter strips the code, regenerate to compare - compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings); + compiler_driver_->CompileAll( + class_loader, class_linker->GetBootClassPath(), /* verifier_deps */ nullptr, &timings); } std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp_oat.GetFilename(), tmp_oat.GetFilename(), @@ -515,7 +517,7 @@ TEST_F(OatTest, EmptyTextSection) { soa.Decode<mirror::ClassLoader>(class_loader).Ptr()); } compiler_driver_->SetDexFilesForOatFile(dex_files); - compiler_driver_->CompileAll(class_loader, dex_files, &timings); + compiler_driver_->CompileAll(class_loader, dex_files, /* verifier_deps */ nullptr, &timings); ScratchFile tmp_oat, tmp_vdex(tmp_oat, ".vdex"); SafeMap<std::string, std::string> key_value_store; diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index 8d2a0e7860..6b690aab40 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -72,6 +72,22 @@ class VerifierDepsTest : public CommonCompilerTest { return klass; } + void SetupCompilerDriver() { + compiler_options_->boot_image_ = false; + compiler_driver_->InitializeThreadPools(); + } + + void VerifyWithCompilerDriver(verifier::VerifierDeps* deps) { + TimingLogger timings("Verify", false, false); + // The compiler driver handles the verifier deps in the callbacks, so + // remove what this class did for unit testing. + verifier_deps_.reset(nullptr); + callbacks_->SetVerifierDeps(nullptr); + compiler_driver_->Verify(class_loader_, dex_files_, deps, &timings); + // The compiler driver may have updated the VerifierDeps in the callback object. + verifier_deps_.reset(callbacks_->GetVerifierDeps()); + } + void SetVerifierDeps(const std::vector<const DexFile*>& dex_files) { verifier_deps_.reset(new verifier::VerifierDeps(dex_files)); VerifierDepsCompilerCallbacks* callbacks = @@ -156,15 +172,12 @@ class VerifierDepsTest : public CommonCompilerTest { } void VerifyDexFile(const char* multidex = nullptr) { - std::string error_msg; { ScopedObjectAccess soa(Thread::Current()); LoadDexFile(&soa, "VerifierDeps", multidex); } - TimingLogger timings("Verify", false, false); - compiler_options_->boot_image_ = false; - compiler_driver_->InitializeThreadPools(); - compiler_driver_->Verify(class_loader_, dex_files_, &timings); + SetupCompilerDriver(); + VerifyWithCompilerDriver(/* verifier_deps */ nullptr); } bool TestAssignabilityRecording(const std::string& dst, @@ -185,6 +198,33 @@ class VerifierDepsTest : public CommonCompilerTest { return true; } + // Check that the status of classes in `class_loader_` match the + // expected status in `deps`. + void VerifyClassStatus(const verifier::VerifierDeps& deps) { + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<2> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader_handle( + hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_))); + MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(nullptr)); + for (const DexFile* dex_file : dex_files_) { + const std::vector<uint16_t>& unverified_classes = deps.GetUnverifiedClasses(*dex_file); + std::set<uint16_t> set(unverified_classes.begin(), unverified_classes.end()); + for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) { + const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); + const char* descriptor = dex_file->GetClassDescriptor(class_def); + cls.Assign(class_linker_->FindClass(soa.Self(), descriptor, class_loader_handle)); + if (cls.Get() == nullptr) { + CHECK(soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); + } else if (set.find(class_def.class_idx_) == set.end()) { + ASSERT_EQ(cls->GetStatus(), mirror::Class::kStatusVerified); + } else { + ASSERT_LT(cls->GetStatus(), mirror::Class::kStatusVerified); + } + } + } + } + bool HasUnverifiedClass(const std::string& cls) { const DexFile::TypeId* type_id = primary_dex_file_->FindTypeId(cls.c_str()); DCHECK(type_id != nullptr); @@ -1160,7 +1200,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { MutableHandle<mirror::ClassLoader> new_class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr)); { new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_TRUE(verifier_deps_->Verify(new_class_loader, soa.Self())); + ASSERT_TRUE(verifier_deps_->ValidateDependencies(new_class_loader, soa.Self())); } std::vector<uint8_t> buffer; @@ -1170,7 +1210,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { { VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_TRUE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_TRUE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } // Fiddle with the dependencies to make sure we catch any change and fail to verify. @@ -1181,7 +1221,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); deps->assignable_types_.insert(*deps->unassignable_types_.begin()); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1190,7 +1230,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); deps->unassignable_types_.insert(*deps->assignable_types_.begin()); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } // Mess up with classes. @@ -1208,7 +1248,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1225,7 +1265,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1242,7 +1282,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } // Mess up with fields. @@ -1261,7 +1301,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1279,7 +1319,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1297,7 +1337,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1316,7 +1356,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } // Mess up with methods. @@ -1338,7 +1378,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1357,7 +1397,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1376,7 +1416,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1396,7 +1436,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1415,7 +1455,7 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); } { @@ -1434,7 +1474,56 @@ TEST_F(VerifierDepsTest, VerifyDeps) { } ASSERT_TRUE(found); new_class_loader.Assign(soa.Decode<mirror::ClassLoader>(LoadDex("VerifierDeps"))); - ASSERT_FALSE(decoded_deps.Verify(new_class_loader, soa.Self())); + ASSERT_FALSE(decoded_deps.ValidateDependencies(new_class_loader, soa.Self())); + } + } +} + +TEST_F(VerifierDepsTest, CompilerDriver) { + SetupCompilerDriver(); + + // Test both multi-dex and single-dex configuration. + for (const char* multi : { "MultiDex", static_cast<const char*>(nullptr) }) { + // Test that the compiler driver behaves as expected when the dependencies + // verify and when they don't verify. + for (bool verify_failure : { false, true }) { + { + ScopedObjectAccess soa(Thread::Current()); + LoadDexFile(&soa, "VerifierDeps", multi); + } + VerifyWithCompilerDriver(/* verifier_deps */ nullptr); + + std::vector<uint8_t> buffer; + verifier_deps_->Encode(dex_files_, &buffer); + + { + ScopedObjectAccess soa(Thread::Current()); + LoadDexFile(&soa, "VerifierDeps", multi); + } + verifier::VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer)); + if (verify_failure) { + // Just taint the decoded VerifierDeps with one invalid entry. + VerifierDeps::DexFileDeps* deps = decoded_deps.GetDexFileDeps(*primary_dex_file_); + bool found = false; + for (const auto& entry : deps->classes_) { + if (entry.IsResolved()) { + deps->classes_.insert(VerifierDeps::ClassResolution( + entry.GetDexTypeIndex(), VerifierDeps::kUnresolvedMarker)); + found = true; + break; + } + } + ASSERT_TRUE(found); + } + VerifyWithCompilerDriver(&decoded_deps); + + if (verify_failure) { + ASSERT_FALSE(verifier_deps_ == nullptr); + ASSERT_FALSE(verifier_deps_->Equals(decoded_deps)); + } else { + ASSERT_TRUE(verifier_deps_ == nullptr); + VerifyClassStatus(decoded_deps); + } } } } diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 28d628920c..1180bdeabb 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1497,12 +1497,6 @@ class Dex2Oat FINAL { dex_files_ = MakeNonOwningPointerVector(opened_dex_files_); - if (!IsBootImage()) { - // Collect verification dependencies when compiling an app. - verifier_deps_.reset(new verifier::VerifierDeps(dex_files_)); - callbacks_->SetVerifierDeps(verifier_deps_.get()); - } - // We had to postpone the swap decision till now, as this is the point when we actually // know about the dex files we're going to use. @@ -1660,7 +1654,7 @@ class Dex2Oat FINAL { swap_fd_, profile_compilation_info_.get())); driver_->SetDexFilesForOatFile(dex_files_); - driver_->CompileAll(class_loader_, dex_files_, timings_); + driver_->CompileAll(class_loader_, dex_files_, /* verifier_deps */ nullptr, timings_); } // Notes on the interleaving of creating the images and oat files to @@ -1785,13 +1779,13 @@ class Dex2Oat FINAL { { TimingLogger::ScopedTiming t2("dex2oat Write VDEX", timings_); DCHECK(IsBootImage() || oat_files_.size() == 1u); - DCHECK_EQ(IsBootImage(), verifier_deps_ == nullptr); + verifier::VerifierDeps* verifier_deps = callbacks_->GetVerifierDeps(); for (size_t i = 0, size = oat_files_.size(); i != size; ++i) { File* vdex_file = vdex_files_[i].get(); std::unique_ptr<BufferedOutputStream> vdex_out( MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(vdex_file))); - if (!oat_writers_[i]->WriteVerifierDeps(vdex_out.get(), verifier_deps_.get())) { + if (!oat_writers_[i]->WriteVerifierDeps(vdex_out.get(), verifier_deps)) { LOG(ERROR) << "Failed to write verifier dependencies into VDEX " << vdex_file->GetPath(); return false; } @@ -2645,9 +2639,6 @@ class Dex2Oat FINAL { std::vector<std::vector<const DexFile*>> dex_files_per_oat_file_; std::unordered_map<const DexFile*, size_t> dex_file_oat_index_map_; - // Collector of verifier dependencies. - std::unique_ptr<verifier::VerifierDeps> verifier_deps_; - // Backing storage. std::vector<std::string> char_backing_storage_; diff --git a/runtime/compiler_callbacks.h b/runtime/compiler_callbacks.h index 00dedef1e7..806653a265 100644 --- a/runtime/compiler_callbacks.h +++ b/runtime/compiler_callbacks.h @@ -47,6 +47,7 @@ class CompilerCallbacks { virtual bool IsRelocationPossible() = 0; virtual verifier::VerifierDeps* GetVerifierDeps() const = 0; + virtual void SetVerifierDeps(verifier::VerifierDeps* deps ATTRIBUTE_UNUSED) {} bool IsBootImage() { return mode_ == CallbackMode::kCompileBootImage; diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc index bdf63cb45b..c395612d72 100644 --- a/runtime/verifier/verifier_deps.cc +++ b/runtime/verifier/verifier_deps.cc @@ -607,7 +607,8 @@ void VerifierDeps::Dump(VariableIndentationOutputStream* vios) const { } } -bool VerifierDeps::Verify(Handle<mirror::ClassLoader> class_loader, Thread* self) const { +bool VerifierDeps::ValidateDependencies(Handle<mirror::ClassLoader> class_loader, + Thread* self) const { for (const auto& entry : dex_deps_) { if (!VerifyDexFile(class_loader, *entry.first, *entry.second, self)) { return false; diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h index eea0299f6b..7b419d4260 100644 --- a/runtime/verifier/verifier_deps.h +++ b/runtime/verifier/verifier_deps.h @@ -109,11 +109,18 @@ class VerifierDeps { void Dump(VariableIndentationOutputStream* vios) const NO_THREAD_SAFETY_ANALYSIS; - // Verify the encoded dependencies of this `VerifierDeps`. + // Verify the encoded dependencies of this `VerifierDeps` are still valid. // NO_THREAD_SAFETY_ANALYSIS, as this must be called on a read-only `VerifierDeps`. - bool Verify(Handle<mirror::ClassLoader> class_loader, Thread* self) const + bool ValidateDependencies(Handle<mirror::ClassLoader> class_loader, Thread* self) const NO_THREAD_SAFETY_ANALYSIS; + // NO_THREAD_SAFETY_ANALSYS, as this is queried when the VerifierDeps are + // fully created. + const std::vector<uint16_t>& GetUnverifiedClasses(const DexFile& dex_file) const + NO_THREAD_SAFETY_ANALYSIS { + return GetDexFileDeps(dex_file)->unverified_classes_; + } + private: static constexpr uint16_t kUnresolvedMarker = static_cast<uint16_t>(-1); @@ -317,6 +324,7 @@ class VerifierDeps { ART_FRIEND_TEST(VerifierDepsTest, EncodeDecode); ART_FRIEND_TEST(VerifierDepsTest, EncodeDecodeMulti); ART_FRIEND_TEST(VerifierDepsTest, VerifyDeps); + ART_FRIEND_TEST(VerifierDepsTest, CompilerDriver); }; } // namespace verifier |