Don't encode OatQuickMethodHeader for non-compiled methods.
Requires changes to the quickening info format stored in vdex.
Large app:
Before
odex size: 5.5MB
vdex size: 48MB (49308168 bytes)
After:
odex size: 1.2MB -78%
vdex size: 48MB (49701846 bytes) +1%
bug: 62120170
Test: test.py
Change-Id: I5ae0b103dc57bdd17aa772f4e43db954d109fd44
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index d9f44d7..ed1aee6 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -29,6 +29,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex-inl.h"
+#include "bytecode_utils.h"
#include "dex_file-inl.h"
#include "dex2oat_environment_test.h"
#include "dex2oat_return_codes.h"
@@ -833,6 +834,84 @@
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());
+ GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kQuicken,
+ { input_vdex, output_vdex },
+ /* 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_file1->Fd());
+ GenerateOdexForTest(dex_location,
+ odex_location,
+ CompilerFilter::kVerify,
+ { input_vdex, output_vdex },
+ /* expect_success */ true,
+ /* use_fd */ true);
+ }
+ ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
+ CheckResult(dex_location, odex_location);
+ 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(odex_location.c_str(),
+ odex_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &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 (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+ const uint8_t* class_data = dex_file->GetClassData(class_def);
+ if (class_data != nullptr) {
+ for (ClassDataItemIterator class_it(*dex_file, class_data);
+ class_it.HasNext();
+ class_it.Next()) {
+ if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
+ for (CodeItemIterator it(*class_it.GetMethodCodeItem()); !it.Done(); it.Advance()) {
+ Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
+ ASSERT_FALSE(inst->IsQuickened());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+};
+
+TEST_F(Dex2oatUnquickenTest, UnquickenMultiDex) {
+ RunUnquickenMultiDex();
+}
+
class Dex2oatWatchdogTest : public Dex2oatTest {
protected:
void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) {