diff options
| -rw-r--r-- | dex2oat/dex/dex_to_dex_decompiler_test.cc | 5 | ||||
| -rw-r--r-- | dex2oat/dex2oat_test.cc | 273 | ||||
| -rw-r--r-- | dex2oat/driver/compiler_driver.cc | 5 | ||||
| -rw-r--r-- | dexoptanalyzer/dexoptanalyzer_test.cc | 18 | ||||
| -rw-r--r-- | runtime/compiler_filter.cc | 33 | ||||
| -rw-r--r-- | runtime/compiler_filter.h | 1 | ||||
| -rw-r--r-- | runtime/compiler_filter_test.cc | 14 | ||||
| -rw-r--r-- | runtime/oat.h | 4 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 24 | ||||
| -rw-r--r-- | runtime/oat_file_test.cc | 2 |
10 files changed, 313 insertions, 66 deletions
diff --git a/dex2oat/dex/dex_to_dex_decompiler_test.cc b/dex2oat/dex/dex_to_dex_decompiler_test.cc index e754d5d609..9d65436959 100644 --- a/dex2oat/dex/dex_to_dex_decompiler_test.cc +++ b/dex2oat/dex/dex_to_dex_decompiler_test.cc @@ -40,7 +40,7 @@ class DexToDexDecompilerTest : public CommonCompilerDriverTest { void CompileAll(jobject class_loader) REQUIRES(!Locks::mutator_lock_) { TimingLogger timings("DexToDexDecompilerTest::CompileAll", false, false); compiler_options_->image_type_ = CompilerOptions::ImageType::kNone; - compiler_options_->SetCompilerFilter(CompilerFilter::kVerify); + 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( @@ -77,6 +77,9 @@ class DexToDexDecompilerTest : public CommonCompilerDriverTest { updated_dex_file->EnableWrite(); CompileAll(class_loader); + // The dex files should be different after quickening. + cmp = memcmp(original_dex_file->Begin(), updated_dex_file->Begin(), updated_dex_file->Size()); + ASSERT_NE(0, cmp); // Unquicken the dex file. for (ClassAccessor accessor : updated_dex_file->GetClasses()) { diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index f425fc9a2a..e131e066ce 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -54,6 +54,7 @@ namespace art { static constexpr bool kDebugArgs = false; +static const char* kDisableCompactDex = "--compact-dex-level=none"; using android::base::StringPrintf; @@ -613,16 +614,19 @@ class Dex2oatVeryLargeTest : public Dex2oatTest { TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) { RunTest(CompilerFilter::kAssumeVerified, false, false); RunTest(CompilerFilter::kExtract, false, false); + RunTest(CompilerFilter::kQuicken, false, false); RunTest(CompilerFilter::kSpeed, false, false); RunTest(CompilerFilter::kAssumeVerified, false, false, { "--very-large-app-threshold=10000000" }); RunTest(CompilerFilter::kExtract, false, false, { "--very-large-app-threshold=10000000" }); + RunTest(CompilerFilter::kQuicken, false, false, { "--very-large-app-threshold=10000000" }); RunTest(CompilerFilter::kSpeed, false, false, { "--very-large-app-threshold=10000000" }); } TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) { RunTest(CompilerFilter::kAssumeVerified, true, false, { "--very-large-app-threshold=100" }); RunTest(CompilerFilter::kExtract, true, false, { "--very-large-app-threshold=100" }); + RunTest(CompilerFilter::kQuicken, true, true, { "--very-large-app-threshold=100" }); RunTest(CompilerFilter::kSpeed, true, true, { "--very-large-app-threshold=100" }); } @@ -869,6 +873,148 @@ TEST_F(Dex2oatLayoutTest, TestVdexLayout) { RunTestVDex(); } +class Dex2oatUnquickenTest : public Dex2oatTest { + protected: + void RunUnquickenMultiDex() { + std::string dex_location = GetScratchDir() + "/UnquickenMultiDex.jar"; + std::string odex_location = GetOdexDir() + "/UnquickenMultiDex.odex"; + std::string vdex_location = GetOdexDir() + "/UnquickenMultiDex.vdex"; + Copy(GetTestDexFileName("MultiDex"), dex_location); + + std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str())); + CHECK(vdex_file1 != nullptr) << vdex_location; + // Quicken the dex file into a vdex file. + { + std::string input_vdex = "--input-vdex-fd=-1"; + std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd()); + ASSERT_TRUE(GenerateOdexForTest(dex_location, + odex_location, + CompilerFilter::kQuicken, + { input_vdex, output_vdex }, + /* expect_success= */ true, + /* use_fd= */ true)); + EXPECT_GT(vdex_file1->GetLength(), 0u); + } + // Get the dex file checksums. + std::vector<uint32_t> checksums1; + GetDexFileChecksums(dex_location, odex_location, &checksums1); + // Unquicken by running the verify compiler filter on the vdex file. + { + std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd()); + std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd()); + ASSERT_TRUE(GenerateOdexForTest(dex_location, + odex_location, + CompilerFilter::kVerify, + { input_vdex, output_vdex, kDisableCompactDex }, + /* expect_success= */ true, + /* use_fd= */ true)); + } + ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file"; + CheckResult(dex_location, odex_location); + // Verify that the checksums did not change. + std::vector<uint32_t> checksums2; + GetDexFileChecksums(dex_location, odex_location, &checksums2); + ASSERT_EQ(checksums1.size(), checksums2.size()); + for (size_t i = 0; i != checksums1.size(); ++i) { + EXPECT_EQ(checksums1[i], checksums2[i]) << i; + } + ASSERT_TRUE(success_); + } + + void RunUnquickenMultiDexCDex() { + std::string dex_location = GetScratchDir() + "/UnquickenMultiDex.jar"; + std::string odex_location = GetOdexDir() + "/UnquickenMultiDex.odex"; + std::string odex_location2 = GetOdexDir() + "/UnquickenMultiDex2.odex"; + std::string vdex_location = GetOdexDir() + "/UnquickenMultiDex.vdex"; + std::string vdex_location2 = GetOdexDir() + "/UnquickenMultiDex2.vdex"; + Copy(GetTestDexFileName("MultiDex"), dex_location); + + std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str())); + std::unique_ptr<File> vdex_file2(OS::CreateEmptyFile(vdex_location2.c_str())); + CHECK(vdex_file1 != nullptr) << vdex_location; + CHECK(vdex_file2 != nullptr) << vdex_location2; + + // Quicken the dex file into a vdex file. + { + std::string input_vdex = "--input-vdex-fd=-1"; + std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd()); + ASSERT_TRUE(GenerateOdexForTest(dex_location, + odex_location, + CompilerFilter::kQuicken, + { input_vdex, output_vdex, "--compact-dex-level=fast"}, + /* expect_success= */ true, + /* use_fd= */ true)); + EXPECT_GT(vdex_file1->GetLength(), 0u); + } + // Unquicken by running the verify compiler filter on the vdex file. + { + std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd()); + std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2->Fd()); + ASSERT_TRUE(GenerateOdexForTest(dex_location, + odex_location2, + CompilerFilter::kVerify, + { input_vdex, output_vdex, "--compact-dex-level=none"}, + /* expect_success= */ true, + /* use_fd= */ true)); + } + ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file"; + ASSERT_EQ(vdex_file2->FlushCloseOrErase(), 0) << "Could not flush and close vdex file"; + CheckResult(dex_location, odex_location2); + ASSERT_TRUE(success_); + } + + void CheckResult(const std::string& dex_location, const std::string& odex_location) { + std::string error_msg; + std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1, + odex_location.c_str(), + odex_location.c_str(), + /*executable=*/ false, + /*low_4gb=*/ false, + dex_location, + &error_msg)); + ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; + ASSERT_GE(odex_file->GetOatDexFiles().size(), 1u); + + // Iterate over the dex files and ensure there is no quickened instruction. + for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) { + std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg); + for (ClassAccessor accessor : dex_file->GetClasses()) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + for (const DexInstructionPcPair& inst : method.GetInstructions()) { + ASSERT_FALSE(inst->IsQuickened()) << inst->Opcode() << " " << output_; + } + } + } + } + } + + void GetDexFileChecksums(const std::string& dex_location, + const std::string& odex_location, + /*out*/std::vector<uint32_t>* checksums) { + std::string error_msg; + std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1, + odex_location.c_str(), + odex_location.c_str(), + /*executable=*/ false, + /*low_4gb=*/ false, + dex_location, + &error_msg)); + ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; + ASSERT_GE(odex_file->GetOatDexFiles().size(), 1u); + for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) { + checksums->push_back(oat_dex_file->GetDexFileLocationChecksum()); + } + } +}; + +TEST_F(Dex2oatUnquickenTest, UnquickenMultiDex) { + RunUnquickenMultiDex(); +} + +TEST_F(Dex2oatUnquickenTest, UnquickenMultiDexCDex) { + RunUnquickenMultiDexCDex(); +} + class Dex2oatWatchdogTest : public Dex2oatTest { protected: void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) { @@ -966,7 +1112,7 @@ class Dex2oatClassLoaderContextTest : public Dex2oatTest { ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, - CompilerFilter::kVerify, + CompilerFilter::kQuicken, extra_args, expected_success, /*use_fd=*/ false, @@ -1034,7 +1180,7 @@ TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFilesBackedByOdex) { ASSERT_TRUE(GenerateOdexForTest(stripped_classpath, odex_for_classpath, - CompilerFilter::kVerify, + CompilerFilter::kQuicken, {}, true)); @@ -1163,7 +1309,7 @@ TEST_F(Dex2oatDeterminism, UnloadCompile) { const int res = GenerateOdexForTestWithStatus( GetLibCoreDexFileNames(), base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, &error_msg, {"--force-determinism", "--avoid-storing-invocation"}); ASSERT_EQ(res, 0); @@ -1180,7 +1326,7 @@ TEST_F(Dex2oatDeterminism, UnloadCompile) { const int res2 = GenerateOdexForTestWithStatus( GetLibCoreDexFileNames(), base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, &error_msg, {"--force-determinism", "--avoid-storing-invocation", "--compile-individually"}); ASSERT_EQ(res2, 0); @@ -1265,7 +1411,7 @@ TEST_F(Dex2oatTest, LayoutSections) { const int res = GenerateOdexForTestWithStatus( {dex->GetLocation()}, oat_filename, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, &error_msg, {"--profile-file=" + profile_file.GetFilename()}); EXPECT_EQ(res, 0); @@ -1374,7 +1520,7 @@ TEST_F(Dex2oatTest, GenerateCompactDex) { const int res = GenerateOdexForTestWithStatus( { dex_location }, oat_filename, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, &error_msg, {"--compact-dex-level=fast"}); EXPECT_EQ(res, 0); @@ -1434,7 +1580,7 @@ TEST_F(Dex2oatVerifierAbort, HardFail) { const int res_fail = GenerateOdexForTestWithStatus( {dex->GetLocation()}, base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, &error_msg, {"--abort-on-hard-verifier-error"}); EXPECT_NE(0, res_fail); @@ -1442,7 +1588,7 @@ TEST_F(Dex2oatVerifierAbort, HardFail) { const int res_no_fail = GenerateOdexForTestWithStatus( {dex->GetLocation()}, base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, &error_msg, {"--no-abort-on-hard-verifier-error"}); EXPECT_EQ(0, res_no_fail); @@ -1457,7 +1603,7 @@ TEST_F(Dex2oatVerifierAbort, SoftFail) { const int res_fail = GenerateOdexForTestWithStatus( {dex->GetLocation()}, base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, &error_msg, {"--abort-on-soft-verifier-error"}); EXPECT_NE(0, res_fail); @@ -1465,7 +1611,7 @@ TEST_F(Dex2oatVerifierAbort, SoftFail) { const int res_no_fail = GenerateOdexForTestWithStatus( {dex->GetLocation()}, base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, &error_msg, {"--no-abort-on-soft-verifier-error"}); EXPECT_EQ(0, res_no_fail); @@ -1511,7 +1657,7 @@ TEST_F(Dex2oatTest, UncompressedTest) { const std::string base_oat_name = out_dir + "/base.oat"; ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(), base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, { }, /*expect_success=*/ true, /*use_fd=*/ false, @@ -1528,7 +1674,7 @@ TEST_F(Dex2oatTest, EmptyUncompressedDexTest) { int status = GenerateOdexForTestWithStatus( { GetTestDexFileName("MainEmptyUncompressed") }, base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, &error_msg, { }, /*use_fd*/ false); @@ -1544,7 +1690,7 @@ TEST_F(Dex2oatTest, EmptyUncompressedAlignedDexTest) { int status = GenerateOdexForTestWithStatus( { GetTestDexFileName("MainEmptyUncompressedAligned") }, base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, &error_msg, { }, /*use_fd*/ false); @@ -1683,7 +1829,7 @@ TEST_F(Dex2oatTest, CompactDexGenerationFailureMultiDex) { const std::string odex_location = GetOdexDir() + "/output.odex"; ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, - CompilerFilter::kVerify, + CompilerFilter::kQuicken, { "--compact-dex-level=fast" }, true)); } @@ -1697,7 +1843,7 @@ TEST_F(Dex2oatTest, StderrLoggerOutput) { ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, - CompilerFilter::kVerify, + CompilerFilter::kQuicken, { "--runtime-arg", "-Xuse-stderr-logger" }, true)); // Look for some random part of dex2oat logging. With the stderr logger this should be captured, @@ -1843,10 +1989,89 @@ TEST_F(Dex2oatTest, DontExtract) { EXPECT_TRUE(found_fast_verify) << "Expected to find " << kFastVerifyString << "\n" << output_; }; + // Generate a quickened dex by using the input dm file to verify. + generate_and_check(CompilerFilter::Filter::kQuicken); // Use verify compiler filter to check that FastVerify works for that filter too. generate_and_check(CompilerFilter::Filter::kVerify); } +// Test that dex files with quickened opcodes aren't dequickened. +TEST_F(Dex2oatTest, QuickenedInput) { + std::string error_msg; + ScratchFile temp_dex; + MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("ManyMethods"), [] (DexFile* dex) { + bool mutated_successfully = false; + // Change the dex instructions to make an opcode that spans past the end of the code item. + for (ClassAccessor accessor : dex->GetClasses()) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + CodeItemInstructionAccessor instructions = method.GetInstructions(); + // Make a quickened instruction that doesn't run past the end of the code item. + if (instructions.InsnsSizeInCodeUnits() > 2) { + const_cast<Instruction&>(instructions.InstructionAt(0)).SetOpcode( + Instruction::IGET_BYTE_QUICK); + mutated_successfully = true; + } + } + } + CHECK(mutated_successfully) + << "Failed to find candidate code item with only one code unit in last instruction."; + }); + + const std::string& dex_location = temp_dex.GetFilename(); + std::string odex_location = GetOdexDir() + "/quickened.odex"; + std::string vdex_location = GetOdexDir() + "/quickened.vdex"; + std::unique_ptr<File> vdex_output(OS::CreateEmptyFile(vdex_location.c_str())); + // Quicken the dex + { + std::string input_vdex = "--input-vdex-fd=-1"; + std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_output->Fd()); + ASSERT_TRUE(GenerateOdexForTest(dex_location, + odex_location, + CompilerFilter::kQuicken, + // Disable cdex since we want to compare against the original + // dex file after unquickening. + { input_vdex, output_vdex, kDisableCompactDex }, + /* expect_success= */ true, + /* use_fd= */ true)); + } + // Unquicken by running the verify compiler filter on the vdex file and verify it matches. + std::string odex_location2 = GetOdexDir() + "/unquickened.odex"; + std::string vdex_location2 = GetOdexDir() + "/unquickened.vdex"; + std::unique_ptr<File> vdex_unquickened(OS::CreateEmptyFile(vdex_location2.c_str())); + { + std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_output->Fd()); + std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_unquickened->Fd()); + ASSERT_TRUE(GenerateOdexForTest(dex_location, + odex_location2, + CompilerFilter::kVerify, + // Disable cdex to avoid needing to write out the shared + // section. + { input_vdex, output_vdex, kDisableCompactDex }, + /* expect_success= */ true, + /* use_fd= */ true)); + } + ASSERT_EQ(vdex_unquickened->Flush(), 0) << "Could not flush and close vdex file"; + ASSERT_TRUE(success_); + { + // Check that hte vdex has one dex and compare it to the original one. + std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location2.c_str(), + /*writable*/ false, + /*low_4gb*/ false, + /*unquicken*/ false, + &error_msg)); + std::vector<std::unique_ptr<const DexFile>> dex_files; + bool result = vdex->OpenAllDexFiles(&dex_files, &error_msg); + ASSERT_TRUE(result) << error_msg; + ASSERT_EQ(dex_files.size(), 1u) << error_msg; + ScratchFile temp; + ASSERT_TRUE(temp.GetFile()->WriteFully(dex_files[0]->Begin(), dex_files[0]->Size())); + ASSERT_EQ(temp.GetFile()->Flush(), 0) << "Could not flush extracted dex"; + EXPECT_EQ(temp.GetFile()->Compare(temp_dex.GetFile()), 0); + } + ASSERT_EQ(vdex_output->FlushCloseOrErase(), 0) << "Could not flush and close"; + ASSERT_EQ(vdex_unquickened->FlushCloseOrErase(), 0) << "Could not flush and close"; +} + // Test that compact dex generation with invalid dex files doesn't crash dex2oat. b/75970654 TEST_F(Dex2oatTest, CompactDexInvalidSource) { ScratchFile invalid_dex; @@ -1874,7 +2099,7 @@ TEST_F(Dex2oatTest, CompactDexInvalidSource) { int status = GenerateOdexForTestWithStatus( {dex_location}, odex_location, - CompilerFilter::kVerify, + CompilerFilter::kQuicken, &error_msg, { "--compact-dex-level=fast" }); ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_; @@ -1913,7 +2138,7 @@ TEST_F(Dex2oatTest, CompactDexInZip) { status = GenerateOdexForTestWithStatus( { invalid_dex_zip.GetFilename() }, GetOdexDir() + "/output_apk.odex", - CompilerFilter::kVerify, + CompilerFilter::kQuicken, &error_msg, { "--compact-dex-level=fast" }); ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_; @@ -1921,7 +2146,7 @@ TEST_F(Dex2oatTest, CompactDexInZip) { status = GenerateOdexForTestWithStatus( { invalid_dex.GetFilename() }, GetOdexDir() + "/output.odex", - CompilerFilter::kVerify, + CompilerFilter::kQuicken, &error_msg, { "--compact-dex-level=fast" }); ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_; @@ -1969,7 +2194,7 @@ TEST_F(Dex2oatTest, ZipFd) { const std::string base_oat_name = out_dir + "/base.oat"; ASSERT_TRUE(GenerateOdexForTest(zip_location, base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, extra_args, /*expect_success=*/ true, /*use_fd=*/ false, @@ -2068,7 +2293,7 @@ TEST_F(Dex2oatTest, DexFileFd) { }; ASSERT_TRUE(GenerateOdexForTest(dex_location, base_oat_name, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, extra_args, /*expect_success=*/ true, /*use_fd=*/ false, @@ -2255,7 +2480,7 @@ TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) { // The class path should not be valid and should fail being stored. EXPECT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"), odex_location, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, { "--class-loader-context=" + stored_context }, /*expect_success=*/ true, /*use_fd=*/ false, @@ -2267,7 +2492,7 @@ TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) { // The stored context should match what we expect even though it's invalid. EXPECT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"), odex_location, - CompilerFilter::Filter::kVerify, + CompilerFilter::Filter::kQuicken, { "--class-loader-context=" + valid_context, "--stored-class-loader-context=" + stored_context }, /*expect_success=*/ true, @@ -2323,7 +2548,7 @@ TEST_F(LinkageTest, LinkageEnabled) { const int res_fail = GenerateOdexForTestWithStatus( {dex->GetLocation()}, base_oat_name, - CompilerFilter::Filter::kSpeed, + CompilerFilter::Filter::kQuicken, &error_msg, {"--check-linkage-conditions", "--crash-on-linkage-violation"}); EXPECT_NE(0, res_fail); @@ -2331,7 +2556,7 @@ TEST_F(LinkageTest, LinkageEnabled) { const int res_no_fail = GenerateOdexForTestWithStatus( {dex->GetLocation()}, base_oat_name, - CompilerFilter::Filter::kSpeed, + CompilerFilter::Filter::kQuicken, &error_msg, {"--check-linkage-conditions"}); EXPECT_EQ(0, res_no_fail); diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc index c9f99a4bcd..c08227a1b8 100644 --- a/dex2oat/driver/compiler_driver.cc +++ b/dex2oat/driver/compiler_driver.cc @@ -355,11 +355,8 @@ static optimizer::DexToDexCompiler::CompilationLevel GetDexToDexCompilationLevel if (dex_file.GetContainer() != nullptr && dex_file.GetContainer()->IsReadOnly()) { return optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile; } - if (!driver.GetCompilerOptions().IsQuickeningCompilationEnabled()) { - // b/170086509 Quickening compilation is being deprecated. - return optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile; - } auto* const runtime = Runtime::Current(); + DCHECK(driver.GetCompilerOptions().IsQuickeningCompilationEnabled()); const char* descriptor = dex_file.GetClassDescriptor(class_def); ClassLinker* class_linker = runtime->GetClassLinker(); ObjPtr<mirror::Class> klass = class_linker->FindClass(self, descriptor, class_loader); diff --git a/dexoptanalyzer/dexoptanalyzer_test.cc b/dexoptanalyzer/dexoptanalyzer_test.cc index d8321d6c55..651fa4ae7b 100644 --- a/dexoptanalyzer/dexoptanalyzer_test.cc +++ b/dexoptanalyzer/dexoptanalyzer_test.cc @@ -104,7 +104,7 @@ TEST_F(DexoptAnalyzerTest, DexNoOat) { Verify(dex_location, CompilerFilter::kSpeed); Verify(dex_location, CompilerFilter::kExtract); - Verify(dex_location, CompilerFilter::kVerify); + Verify(dex_location, CompilerFilter::kQuicken); Verify(dex_location, CompilerFilter::kSpeedProfile); Verify(dex_location, CompilerFilter::kSpeed, false, false, nullptr); } @@ -116,7 +116,7 @@ TEST_F(DexoptAnalyzerTest, OatUpToDate) { GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); Verify(dex_location, CompilerFilter::kSpeed); - Verify(dex_location, CompilerFilter::kVerify); + Verify(dex_location, CompilerFilter::kQuicken); Verify(dex_location, CompilerFilter::kExtract); Verify(dex_location, CompilerFilter::kEverything); Verify(dex_location, CompilerFilter::kSpeed, false, false, nullptr); @@ -129,19 +129,19 @@ TEST_F(DexoptAnalyzerTest, ProfileOatUpToDate) { GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile); Verify(dex_location, CompilerFilter::kSpeedProfile, false); - Verify(dex_location, CompilerFilter::kVerify, false); + Verify(dex_location, CompilerFilter::kQuicken, false); Verify(dex_location, CompilerFilter::kSpeedProfile, true); - Verify(dex_location, CompilerFilter::kVerify, true); + Verify(dex_location, CompilerFilter::kQuicken, true); } TEST_F(DexoptAnalyzerTest, Downgrade) { std::string dex_location = GetScratchDir() + "/Downgrade.jar"; Copy(GetDexSrc1(), dex_location); - GenerateOatForTest(dex_location.c_str(), CompilerFilter::kVerify); + GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken); Verify(dex_location, CompilerFilter::kSpeedProfile, false, true); + Verify(dex_location, CompilerFilter::kQuicken, false, true); Verify(dex_location, CompilerFilter::kVerify, false, true); - Verify(dex_location, CompilerFilter::kExtract, false, true); } // Case: We have a MultiDEX file and up-to-date OAT file for it. @@ -195,7 +195,7 @@ TEST_F(DexoptAnalyzerTest, OatImageOutOfDate) { /*with_alternate_image=*/true); Verify(dex_location, CompilerFilter::kExtract); - Verify(dex_location, CompilerFilter::kVerify); + Verify(dex_location, CompilerFilter::kQuicken); Verify(dex_location, CompilerFilter::kSpeed); } @@ -212,7 +212,7 @@ TEST_F(DexoptAnalyzerTest, OatVerifyAtRuntimeImageOutOfDate) { /*with_alternate_image=*/true); Verify(dex_location, CompilerFilter::kExtract); - Verify(dex_location, CompilerFilter::kVerify); + Verify(dex_location, CompilerFilter::kQuicken); } // Case: We have a DEX file and an ODEX file, but no OAT file. @@ -272,7 +272,7 @@ TEST_F(DexoptAnalyzerTest, ResourceOnlyDex) { Verify(dex_location, CompilerFilter::kSpeed); Verify(dex_location, CompilerFilter::kExtract); - Verify(dex_location, CompilerFilter::kVerify); + Verify(dex_location, CompilerFilter::kQuicken); } // Case: We have a DEX file, an ODEX file and an OAT file. diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc index 6291329f5a..9ce25333cb 100644 --- a/runtime/compiler_filter.cc +++ b/runtime/compiler_filter.cc @@ -26,7 +26,8 @@ bool CompilerFilter::IsAotCompilationEnabled(Filter filter) { switch (filter) { case CompilerFilter::kAssumeVerified: case CompilerFilter::kExtract: - case CompilerFilter::kVerify: return false; + case CompilerFilter::kVerify: + case CompilerFilter::kQuicken: return false; case CompilerFilter::kSpaceProfile: case CompilerFilter::kSpace: @@ -44,6 +45,7 @@ bool CompilerFilter::IsJniCompilationEnabled(Filter filter) { case CompilerFilter::kExtract: case CompilerFilter::kVerify: return false; + case CompilerFilter::kQuicken: case CompilerFilter::kSpaceProfile: case CompilerFilter::kSpace: case CompilerFilter::kSpeedProfile: @@ -54,8 +56,21 @@ bool CompilerFilter::IsJniCompilationEnabled(Filter filter) { UNREACHABLE(); } -bool CompilerFilter::IsQuickeningCompilationEnabled(Filter filter ATTRIBUTE_UNUSED) { - return false; +bool CompilerFilter::IsQuickeningCompilationEnabled(Filter filter) { + switch (filter) { + case CompilerFilter::kAssumeVerified: + case CompilerFilter::kExtract: + case CompilerFilter::kVerify: return false; + + case CompilerFilter::kQuicken: + case CompilerFilter::kSpaceProfile: + case CompilerFilter::kSpace: + case CompilerFilter::kSpeedProfile: + case CompilerFilter::kSpeed: + case CompilerFilter::kEverythingProfile: + case CompilerFilter::kEverything: return true; + } + UNREACHABLE(); } bool CompilerFilter::IsAnyCompilationEnabled(Filter filter) { @@ -70,6 +85,7 @@ bool CompilerFilter::IsVerificationEnabled(Filter filter) { case CompilerFilter::kExtract: return false; case CompilerFilter::kVerify: + case CompilerFilter::kQuicken: case CompilerFilter::kSpaceProfile: case CompilerFilter::kSpace: case CompilerFilter::kSpeedProfile: @@ -91,6 +107,7 @@ bool CompilerFilter::DependsOnProfile(Filter filter) { case CompilerFilter::kAssumeVerified: case CompilerFilter::kExtract: case CompilerFilter::kVerify: + case CompilerFilter::kQuicken: case CompilerFilter::kSpace: case CompilerFilter::kSpeed: case CompilerFilter::kEverything: return false; @@ -107,6 +124,7 @@ CompilerFilter::Filter CompilerFilter::GetNonProfileDependentFilterFrom(Filter f case CompilerFilter::kAssumeVerified: case CompilerFilter::kExtract: case CompilerFilter::kVerify: + case CompilerFilter::kQuicken: case CompilerFilter::kSpace: case CompilerFilter::kSpeed: case CompilerFilter::kEverything: @@ -131,6 +149,7 @@ CompilerFilter::Filter CompilerFilter::GetSafeModeFilterFrom(Filter filter) { case CompilerFilter::kAssumeVerified: case CompilerFilter::kExtract: case CompilerFilter::kVerify: + case CompilerFilter::kQuicken: return filter; case CompilerFilter::kSpace: @@ -139,7 +158,7 @@ CompilerFilter::Filter CompilerFilter::GetSafeModeFilterFrom(Filter filter) { case CompilerFilter::kSpaceProfile: case CompilerFilter::kSpeedProfile: case CompilerFilter::kEverythingProfile: - return CompilerFilter::kVerify; + return CompilerFilter::kQuicken; } UNREACHABLE(); } @@ -157,6 +176,7 @@ std::string CompilerFilter::NameOfFilter(Filter filter) { case CompilerFilter::kAssumeVerified: return "assume-verified"; case CompilerFilter::kExtract: return "extract"; case CompilerFilter::kVerify: return "verify"; + case CompilerFilter::kQuicken: return "quicken"; case CompilerFilter::kSpaceProfile: return "space-profile"; case CompilerFilter::kSpace: return "space"; case CompilerFilter::kSpeedProfile: return "speed-profile"; @@ -177,7 +197,7 @@ bool CompilerFilter::ParseCompilerFilter(const char* option, Filter* filter) { } else if (strcmp(option, "interpret-only") == 0) { LOG(WARNING) << "'interpret-only' is an obsolete compiler filter name that will be " << "removed in future releases, please use 'quicken' instead."; - *filter = kVerify; + *filter = kQuicken; } else if (strcmp(option, "verify-profile") == 0) { LOG(WARNING) << "'verify-profile' is an obsolete compiler filter name that will be " << "removed in future releases, please use 'verify' instead."; @@ -201,8 +221,7 @@ bool CompilerFilter::ParseCompilerFilter(const char* option, Filter* filter) { } else if (strcmp(option, "verify") == 0) { *filter = kVerify; } else if (strcmp(option, "quicken") == 0) { - // b/170086509 'quicken' becomes an alias to 'verify. - *filter = kVerify; + *filter = kQuicken; } else if (strcmp(option, "space") == 0) { *filter = kSpace; } else if (strcmp(option, "space-profile") == 0) { diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h index 0b930a433b..a0166833d3 100644 --- a/runtime/compiler_filter.h +++ b/runtime/compiler_filter.h @@ -33,6 +33,7 @@ class CompilerFilter final { kAssumeVerified, // Skip verification but mark all classes as verified anyway. kExtract, // Delay verication to runtime, do not compile anything. kVerify, // Only verify classes. + kQuicken, // Verify, quicken, and compile JNI stubs. kSpaceProfile, // Maximize space savings based on profile. kSpace, // Maximize space savings. kSpeedProfile, // Maximize runtime performance based on profile. diff --git a/runtime/compiler_filter_test.cc b/runtime/compiler_filter_test.cc index df7c8e74a8..9b4f845b2c 100644 --- a/runtime/compiler_filter_test.cc +++ b/runtime/compiler_filter_test.cc @@ -43,6 +43,7 @@ TEST(CompilerFilterTest, ParseCompilerFilter) { TestCompilerFilterName(CompilerFilter::kAssumeVerified, "assume-verified"); TestCompilerFilterName(CompilerFilter::kExtract, "extract"); TestCompilerFilterName(CompilerFilter::kVerify, "verify"); + TestCompilerFilterName(CompilerFilter::kQuicken, "quicken"); TestCompilerFilterName(CompilerFilter::kSpaceProfile, "space-profile"); TestCompilerFilterName(CompilerFilter::kSpace, "space"); TestCompilerFilterName(CompilerFilter::kSpeedProfile, "speed-profile"); @@ -57,12 +58,13 @@ TEST(CompilerFilterTest, SafeModeFilter) { TestSafeModeFilter(CompilerFilter::kAssumeVerified, "assume-verified"); TestSafeModeFilter(CompilerFilter::kExtract, "extract"); TestSafeModeFilter(CompilerFilter::kVerify, "verify"); - TestSafeModeFilter(CompilerFilter::kVerify, "space-profile"); - TestSafeModeFilter(CompilerFilter::kVerify, "space"); - TestSafeModeFilter(CompilerFilter::kVerify, "speed-profile"); - TestSafeModeFilter(CompilerFilter::kVerify, "speed"); - TestSafeModeFilter(CompilerFilter::kVerify, "everything-profile"); - TestSafeModeFilter(CompilerFilter::kVerify, "everything"); + TestSafeModeFilter(CompilerFilter::kQuicken, "quicken"); + TestSafeModeFilter(CompilerFilter::kQuicken, "space-profile"); + TestSafeModeFilter(CompilerFilter::kQuicken, "space"); + TestSafeModeFilter(CompilerFilter::kQuicken, "speed-profile"); + TestSafeModeFilter(CompilerFilter::kQuicken, "speed"); + TestSafeModeFilter(CompilerFilter::kQuicken, "everything-profile"); + TestSafeModeFilter(CompilerFilter::kQuicken, "everything"); } } // namespace art diff --git a/runtime/oat.h b/runtime/oat.h index f43aa11c23..0fbb09a652 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,8 +32,8 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } }; - // Last oat version changed reason: Deprecation of 'quicken'. - static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '8', '8', '\0' } }; + // Last oat version changed reason: Changes of ABI for conflict trampoline. + static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '8', '7', '\0' } }; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; static constexpr const char* kDebuggableKey = "debuggable"; diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 223b6f4fae..92347b1043 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -233,7 +233,7 @@ TEST_F(OatFileAssistantTest, DexNoOat) { EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract)); EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken)); EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeedProfile)); EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, @@ -278,7 +278,7 @@ TEST_F(OatFileAssistantTest, OdexUpToDate) { EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed)); EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken)); EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract)); EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, @@ -310,7 +310,7 @@ TEST_F(OatFileAssistantTest, OdexUpToDatePartialBootImage) { EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed)); EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken)); EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract)); EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, @@ -345,7 +345,7 @@ TEST_F(OatFileAssistantTest, OdexUpToDateSymLink) { EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed)); EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken)); EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract)); EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, @@ -379,7 +379,7 @@ TEST_F(OatFileAssistantTest, OatUpToDate) { EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed)); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken)); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract)); EXPECT_EQ(OatFileAssistant::kDex2OatForFilter, @@ -420,7 +420,7 @@ TEST_F(OatFileAssistantTest, GetDexOptNeededWithFd) { EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed)); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken)); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract)); EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, @@ -617,11 +617,11 @@ TEST_F(OatFileAssistantTest, ProfileOatUpToDate) { EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeedProfile, false)); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify, false)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken, false)); EXPECT_EQ(OatFileAssistant::kDex2OatForFilter, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeedProfile, true)); EXPECT_EQ(OatFileAssistant::kDex2OatForFilter, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify, true)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken, true)); EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); @@ -776,7 +776,7 @@ TEST_F(OatFileAssistantTest, OatImageOutOfDate) { EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract)); EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken)); EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed)); @@ -811,7 +811,7 @@ TEST_F(OatFileAssistantTest, OatVerifyAtRuntimeImageOutOfDate) { EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract)); EXPECT_EQ(OatFileAssistant::kDex2OatForFilter, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken)); EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); @@ -861,7 +861,7 @@ TEST_F(OatFileAssistantTest, ResourceOnlyDex) { EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract)); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, - GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify)); + GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kQuicken)); EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus()); @@ -972,7 +972,7 @@ TEST_F(OatFileAssistantTest, LoadExecInterpretOnlyOatUpToDate) { std::string dex_location = GetScratchDir() + "/LoadExecInterpretOnlyOatUpToDate.jar"; Copy(GetDexSrc1(), dex_location); - GenerateOatForTest(dex_location.c_str(), CompilerFilter::kVerify); + GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken); ScopedNonWritable scoped_non_writable(dex_location); ASSERT_TRUE(scoped_non_writable.IsSuccessful()); diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc index f33235732a..8222a8aaae 100644 --- a/runtime/oat_file_test.cc +++ b/runtime/oat_file_test.cc @@ -57,7 +57,7 @@ TEST_F(OatFileTest, ChangingMultiDexUncompressed) { std::string dex_location = GetScratchDir() + "/MultiDexUncompressedAligned.jar"; Copy(GetTestDexFileName("MultiDexUncompressedAligned"), dex_location); - GenerateOatForTest(dex_location.c_str(), CompilerFilter::kVerify); + GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken); std::string oat_location; std::string error_msg; |