Make vdex and dexlayout compatible.
Unquicken the vdex before dexlayout, to keep the dex integrity.
bug: 37558732
Test: run-test with speed-profile
Change-Id: Ifcd5c2e4378ccb0df0a66d07f68df31d94b83220
diff --git a/compiler/Android.bp b/compiler/Android.bp
index dec8b57..6ef866a 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -28,7 +28,6 @@
"compiled_method.cc",
"debug/elf_debug_writer.cc",
"dex/dex_to_dex_compiler.cc",
- "dex/dex_to_dex_decompiler.cc",
"dex/inline_method_analyser.cc",
"dex/verified_method.cc",
"dex/verification_results.cc",
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index 43100c9..e486e2e 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "dex/dex_to_dex_decompiler.h"
+#include "dex_to_dex_decompiler.h"
#include "class_linker.h"
#include "compiler/common_compiler_test.h"
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 4c50797..3f0df3b 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -104,11 +104,12 @@
// This method should only be called for classes verified at compile time,
// which have no verifier error, nor has methods that we know will throw
// at runtime.
- AtomicMap::InsertResult result = atomic_verified_methods_.Insert(
+ atomic_verified_methods_.Insert(
ref,
/*expected*/ nullptr,
new VerifiedMethod(/* encountered_error_types */ 0, /* has_runtime_throw */ false));
- DCHECK_EQ(result, AtomicMap::kInsertResultSuccess);
+ // We don't check the result of `Insert` as we could insert twice for the same
+ // MethodReference in the presence of duplicate methods.
}
void VerificationResults::AddRejectedClass(ClassReference ref) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 4f55ed6..fbfa087 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -45,7 +45,6 @@
#include "dex_file-inl.h"
#include "dex_instruction-inl.h"
#include "dex/dex_to_dex_compiler.h"
-#include "dex/dex_to_dex_decompiler.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
#include "driver/compiler_options.h"
@@ -431,61 +430,6 @@
FreeThreadPools();
}
-// In-place unquicken the given `dex_files` based on `quickening_info`.
-static void Unquicken(const std::vector<const DexFile*>& dex_files,
- const ArrayRef<const uint8_t>& quickening_info,
- bool decompile_return_instruction) {
- const uint8_t* quickening_info_ptr = quickening_info.data();
- const uint8_t* const quickening_info_end = quickening_info.data() + quickening_info.size();
- for (const DexFile* dex_file : dex_files) {
- 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) {
- continue;
- }
- ClassDataItemIterator it(*dex_file, class_data);
- // Skip fields
- while (it.HasNextStaticField()) {
- it.Next();
- }
- while (it.HasNextInstanceField()) {
- it.Next();
- }
-
- while (it.HasNextDirectMethod()) {
- const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
- if (code_item != nullptr) {
- uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
- quickening_info_ptr += sizeof(uint32_t);
- optimizer::ArtDecompileDEX(*code_item,
- ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
- decompile_return_instruction);
- quickening_info_ptr += quickening_size;
- }
- it.Next();
- }
-
- while (it.HasNextVirtualMethod()) {
- const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
- if (code_item != nullptr) {
- uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
- quickening_info_ptr += sizeof(uint32_t);
- optimizer::ArtDecompileDEX(*code_item,
- ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
- decompile_return_instruction);
- quickening_info_ptr += quickening_size;
- }
- it.Next();
- }
- DCHECK(!it.HasNext());
- }
- }
- if (quickening_info_ptr != quickening_info_end) {
- LOG(FATAL) << "Failed to use all quickening info";
- }
-}
-
void CompilerDriver::CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
VdexFile* vdex_file,
@@ -494,15 +438,12 @@
// TODO: we unquicken unconditionnally, as we don't know
// if the boot image has changed. How exactly we'll know is under
// experimentation.
- if (vdex_file->GetQuickeningInfo().size() != 0) {
- TimingLogger::ScopedTiming t("Unquicken", timings);
- // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
- // optimization does not depend on the boot image (the optimization relies on not
- // having final fields in a class, which does not change for an app).
- Unquicken(dex_files,
- vdex_file->GetQuickeningInfo(),
- /* decompile_return_instruction */ false);
- }
+ TimingLogger::ScopedTiming t("Unquicken", timings);
+ // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
+ // optimization does not depend on the boot image (the optimization relies on not
+ // having final fields in a class, which does not change for an app).
+ VdexFile::Unquicken(dex_files, vdex_file->GetQuickeningInfo());
+
Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
new verifier::VerifierDeps(dex_files, vdex_file->GetVerifierDepsData()));
}
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 9646927..6b5387a 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -2474,11 +2474,28 @@
/* verify */ true,
/* verify_checksum */ true,
&error_msg);
- } else {
- CHECK(oat_dex_file->source_.IsRawFile())
- << static_cast<size_t>(oat_dex_file->source_.GetType());
+ } else if (oat_dex_file->source_.IsRawFile()) {
File* raw_file = oat_dex_file->source_.GetRawFile();
dex_file = DexFile::OpenDex(raw_file->Fd(), location, /* verify_checksum */ true, &error_msg);
+ } else {
+ // The source data is a vdex file.
+ CHECK(oat_dex_file->source_.IsRawData())
+ << static_cast<size_t>(oat_dex_file->source_.GetType());
+ const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData();
+ // Note: The raw data has already been checked to contain the header
+ // and all the data that the header specifies as the file size.
+ DCHECK(raw_dex_file != nullptr);
+ DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
+ const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
+ // Since the source may have had its layout changed, or may be quickened, don't verify it.
+ dex_file = DexFile::Open(raw_dex_file,
+ header->file_size_,
+ location,
+ oat_dex_file->dex_file_location_checksum_,
+ nullptr,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg);
}
if (dex_file == nullptr) {
LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 68864da..4cba36a 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -718,6 +718,10 @@
Usage("Can't have both --input-vdex-fd and --input-vdex");
}
+ if (output_vdex_fd_ != -1 && !output_vdex_.empty()) {
+ Usage("Can't have both --output-vdex-fd and --output-vdex");
+ }
+
if (!oat_filenames_.empty() && oat_fd_ != -1) {
Usage("--oat-file should not be used with --oat-fd");
}
@@ -1122,6 +1126,8 @@
ParseInputVdexFd(option);
} else if (option.starts_with("--input-vdex=")) {
input_vdex_ = option.substr(strlen("--input-vdex=")).data();
+ } else if (option.starts_with("--output-vdex=")) {
+ output_vdex_ = option.substr(strlen("--output-vdex=")).data();
} else if (option.starts_with("--output-vdex-fd=")) {
ParseOutputVdexFd(option);
} else if (option.starts_with("--oat-file=")) {
@@ -1257,6 +1263,7 @@
}
// OAT and VDEX file handling
+ bool eagerly_unquicken_vdex = DoDexLayoutOptimizations();
if (oat_fd_ == -1) {
DCHECK(!oat_filenames_.empty());
@@ -1278,12 +1285,15 @@
input_vdex_file_ = VdexFile::Open(input_vdex_,
/* writable */ false,
/* low_4gb */ false,
+ eagerly_unquicken_vdex,
&error_msg);
}
DCHECK_EQ(output_vdex_fd_, -1);
- std::string vdex_filename = ReplaceFileExtension(oat_filename, "vdex");
- if (vdex_filename == input_vdex_) {
+ std::string vdex_filename = output_vdex_.empty()
+ ? ReplaceFileExtension(oat_filename, "vdex")
+ : output_vdex_;
+ if (vdex_filename == input_vdex_ && output_vdex_.empty()) {
update_input_vdex_ = true;
std::unique_ptr<File> vdex_file(OS::OpenFileReadWrite(vdex_filename.c_str()));
vdex_files_.push_back(std::move(vdex_file));
@@ -1325,6 +1335,7 @@
"vdex",
/* writable */ false,
/* low_4gb */ false,
+ eagerly_unquicken_vdex,
&error_msg);
// If there's any problem with the passed vdex, just warn and proceed
// without it.
@@ -2089,10 +2100,6 @@
return DoProfileGuidedOptimizations();
}
- bool HasInputVdexFile() const {
- return input_vdex_file_ != nullptr || input_vdex_fd_ != -1 || !input_vdex_.empty();
- }
-
bool LoadProfile() {
DCHECK(UseProfile());
@@ -2148,16 +2155,6 @@
return dex_files_size >= very_large_threshold_;
}
- template <typename T>
- static std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) {
- std::vector<T*> result;
- result.reserve(src.size());
- for (const std::unique_ptr<T>& t : src) {
- result.push_back(t.get());
- }
- return result;
- }
-
std::vector<std::string> GetClassPathLocations(const std::string& class_path) {
// This function is used only for apps and for an app we have exactly one oat file.
DCHECK(!IsBootImage());
@@ -2690,6 +2687,7 @@
int input_vdex_fd_;
int output_vdex_fd_;
std::string input_vdex_;
+ std::string output_vdex_;
std::unique_ptr<VdexFile> input_vdex_file_;
std::vector<const char*> dex_filenames_;
std::vector<const char*> dex_locations_;
@@ -2896,13 +2894,6 @@
}
}
- if (dex2oat->DoDexLayoutOptimizations()) {
- if (dex2oat->HasInputVdexFile()) {
- LOG(ERROR) << "Dexlayout is incompatible with an input VDEX";
- return dex2oat::ReturnCode::kOther;
- }
- }
-
art::MemMap::Init(); // For ZipEntry::ExtractToMemMap, and vdex.
// Check early that the result of compilation can be written
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 9d9f8c6..a267766 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -736,12 +736,12 @@
/* use_fd */ true,
/* num_profile_classes */ 1,
{ input_vdex, output_vdex },
- /* expect_success */ false);
- EXPECT_EQ(vdex_file2.GetFile()->GetLength(), 0u);
+ /* expect_success */ true);
+ EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u);
}
ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
CheckValidity();
- ASSERT_FALSE(success_);
+ ASSERT_TRUE(success_);
}
void CheckResult(const std::string& dex_location,
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index 688201b..ea2679a 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -313,6 +313,7 @@
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
false /*writeable*/,
false /*low_4gb*/,
+ false /*unquicken */,
&error_msg /*out*/));
if (vdex == nullptr) {
std::cerr << "Could not open vdex file "
diff --git a/runtime/Android.bp b/runtime/Android.bp
index cff2cbc..1869968 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -57,6 +57,7 @@
"dex_file_annotations.cc",
"dex_file_verifier.cc",
"dex_instruction.cc",
+ "dex_to_dex_decompiler.cc",
"elf_file.cc",
"exec_utils.cc",
"fault_handler.cc",
diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h
index d5f375a..cfe27f3 100644
--- a/runtime/base/stl_util.h
+++ b/runtime/base/stl_util.h
@@ -194,6 +194,17 @@
to_update.insert(other.begin(), other.end());
}
+// Returns a copy of the passed vector that doesn't memory-own its entries.
+template <typename T>
+static inline std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) {
+ std::vector<T*> result;
+ result.reserve(src.size());
+ for (const std::unique_ptr<T>& t : src) {
+ result.push_back(t.get());
+ }
+ return result;
+}
+
} // namespace art
#endif // ART_RUNTIME_BASE_STL_UTIL_H_
diff --git a/compiler/dex/dex_to_dex_decompiler.cc b/runtime/dex_to_dex_decompiler.cc
similarity index 100%
rename from compiler/dex/dex_to_dex_decompiler.cc
rename to runtime/dex_to_dex_decompiler.cc
diff --git a/compiler/dex/dex_to_dex_decompiler.h b/runtime/dex_to_dex_decompiler.h
similarity index 88%
rename from compiler/dex/dex_to_dex_decompiler.h
rename to runtime/dex_to_dex_decompiler.h
index b5d5b91..d7cb164 100644
--- a/compiler/dex/dex_to_dex_decompiler.h
+++ b/runtime/dex_to_dex_decompiler.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
-#define ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
+#ifndef ART_RUNTIME_DEX_TO_DEX_DECOMPILER_H_
+#define ART_RUNTIME_DEX_TO_DEX_DECOMPILER_H_
#include "base/array_ref.h"
#include "dex_file.h"
@@ -36,4 +36,4 @@
} // namespace optimizer
} // namespace art
-#endif // ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
+#endif // ART_RUNTIME_DEX_TO_DEX_DECOMPILER_H_
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 4a85d479..9affeb0 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -193,7 +193,7 @@
bool writable,
bool low_4gb,
std::string* error_msg) {
- vdex_ = VdexFile::Open(vdex_filename, writable, low_4gb, error_msg);
+ vdex_ = VdexFile::Open(vdex_filename, writable, low_4gb, /* unquicken*/ false, error_msg);
if (vdex_.get() == nullptr) {
*error_msg = StringPrintf("Failed to load vdex file '%s' %s",
vdex_filename.c_str(),
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 9471cba..2c2b6fd 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -808,6 +808,7 @@
std::unique_ptr<VdexFile> vdex = VdexFile::Open(vdex_filename,
/*writeable*/false,
/*low_4gb*/false,
+ /*unquicken*/false,
&error_msg);
if (vdex == nullptr) {
status_ = kOatCannotOpen;
diff --git a/runtime/openjdkjvmti/fixed_up_dex_file.cc b/runtime/openjdkjvmti/fixed_up_dex_file.cc
index 3338358..29aebae 100644
--- a/runtime/openjdkjvmti/fixed_up_dex_file.cc
+++ b/runtime/openjdkjvmti/fixed_up_dex_file.cc
@@ -32,10 +32,8 @@
#include "fixed_up_dex_file.h"
#include "dex_file-inl.h"
-// Compiler includes.
-#include "dex/dex_to_dex_decompiler.h"
-
// Runtime includes.
+#include "dex_to_dex_decompiler.h"
#include "oat_file.h"
#include "vdex_file.h"
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 9ca7abf..e61ec23 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -905,6 +905,7 @@
std::unique_ptr<VdexFile> vdex_file(VdexFile::Open(vdex_filename,
false /* writable */,
false /* low_4gb */,
+ false, /* unquicken */
&error_msg));
if (vdex_file.get() == nullptr) {
return false;
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 945f08b..e93f04d 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -21,8 +21,10 @@
#include <memory>
#include "base/logging.h"
+#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
#include "dex_file.h"
+#include "dex_to_dex_decompiler.h"
namespace art {
@@ -54,6 +56,7 @@
std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename,
bool writable,
bool low_4gb,
+ bool unquicken,
std::string* error_msg) {
if (!OS::FileExists(vdex_filename.c_str())) {
*error_msg = "File " + vdex_filename + " does not exist.";
@@ -78,7 +81,7 @@
return nullptr;
}
- return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, error_msg);
+ return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, unquicken, error_msg);
}
std::unique_ptr<VdexFile> VdexFile::Open(int file_fd,
@@ -86,15 +89,17 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
+ bool unquicken,
std::string* error_msg) {
- std::unique_ptr<MemMap> mmap(MemMap::MapFile(vdex_length,
- writable ? PROT_READ | PROT_WRITE : PROT_READ,
- MAP_SHARED,
- file_fd,
- 0 /* start offset */,
- low_4gb,
- vdex_filename.c_str(),
- error_msg));
+ std::unique_ptr<MemMap> mmap(MemMap::MapFile(
+ vdex_length,
+ (writable || unquicken) ? PROT_READ | PROT_WRITE : PROT_READ,
+ unquicken ? MAP_PRIVATE : MAP_SHARED,
+ file_fd,
+ 0 /* start offset */,
+ low_4gb,
+ vdex_filename.c_str(),
+ error_msg));
if (mmap == nullptr) {
*error_msg = "Failed to mmap file " + vdex_filename + " : " + *error_msg;
return nullptr;
@@ -106,6 +111,16 @@
return nullptr;
}
+ if (unquicken) {
+ std::vector<std::unique_ptr<const DexFile>> unique_ptr_dex_files;
+ if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) {
+ return nullptr;
+ }
+ Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files), vdex->GetQuickeningInfo());
+ // Update the quickening info size to pretend there isn't any.
+ reinterpret_cast<Header*>(vdex->mmap_->Begin())->quickening_info_size_ = 0;
+ }
+
*error_msg = "Success";
return vdex;
}
@@ -148,4 +163,62 @@
return true;
}
+void VdexFile::Unquicken(const std::vector<const DexFile*>& dex_files,
+ const ArrayRef<const uint8_t>& quickening_info) {
+ if (quickening_info.size() == 0) {
+ // If there is no quickening info, we bail early, as the code below expects at
+ // least the size of quickening data for each method that has a code item.
+ return;
+ }
+ const uint8_t* quickening_info_ptr = quickening_info.data();
+ const uint8_t* const quickening_info_end = quickening_info.data() + quickening_info.size();
+ for (const DexFile* dex_file : dex_files) {
+ 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) {
+ continue;
+ }
+ ClassDataItemIterator it(*dex_file, class_data);
+ // Skip fields
+ while (it.HasNextStaticField()) {
+ it.Next();
+ }
+ while (it.HasNextInstanceField()) {
+ it.Next();
+ }
+
+ while (it.HasNextDirectMethod()) {
+ const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+ if (code_item != nullptr) {
+ uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
+ quickening_info_ptr += sizeof(uint32_t);
+ optimizer::ArtDecompileDEX(*code_item,
+ ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
+ /* decompile_return_instruction */ false);
+ quickening_info_ptr += quickening_size;
+ }
+ it.Next();
+ }
+
+ while (it.HasNextVirtualMethod()) {
+ const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+ if (code_item != nullptr) {
+ uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
+ quickening_info_ptr += sizeof(uint32_t);
+ optimizer::ArtDecompileDEX(*code_item,
+ ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
+ /* decompile_return_instruction */ false);
+ quickening_info_ptr += quickening_size;
+ }
+ it.Next();
+ }
+ DCHECK(!it.HasNext());
+ }
+ }
+ if (quickening_info_ptr != quickening_info_end) {
+ LOG(FATAL) << "Failed to use all quickening info";
+ }
+}
+
} // namespace art
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 9840555..9c0d9db 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -71,6 +71,8 @@
uint32_t dex_size_;
uint32_t verifier_deps_size_;
uint32_t quickening_info_size_;
+
+ friend class VdexFile;
};
typedef uint32_t VdexChecksum;
@@ -79,6 +81,7 @@
static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
bool writable,
bool low_4gb,
+ bool unquicken,
std::string* error_msg);
// Returns nullptr if the vdex file cannot be opened or is not valid.
@@ -87,6 +90,7 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
+ bool unquicken,
std::string* error_msg);
const uint8_t* Begin() const { return mmap_->Begin(); }
@@ -124,12 +128,14 @@
return reinterpret_cast<const uint32_t*>(Begin() + sizeof(Header))[dex_file_index];
}
- // Opens all the dex files contained in this vdex file. This is currently
- // used for dumping tools only, and has not been tested for use by the
- // remainder of the runtime.
+ // Opens all the dex files contained in this vdex file.
bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
std::string* error_msg);
+ // In-place unquicken the given `dex_files` based on `quickening_info`.
+ static void Unquicken(const std::vector<const DexFile*>& dex_files,
+ const ArrayRef<const uint8_t>& quickening_info);
+
private:
explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
diff --git a/runtime/vdex_file_test.cc b/runtime/vdex_file_test.cc
index 909e117..ced6e28 100644
--- a/runtime/vdex_file_test.cc
+++ b/runtime/vdex_file_test.cc
@@ -36,10 +36,12 @@
tmp.GetFilename(),
/*writable*/false,
/*low_4gb*/false,
+ /*quicken*/false,
&error_msg);
EXPECT_TRUE(vdex == nullptr);
- vdex = VdexFile::Open(tmp.GetFilename(), /*writable*/false, /*low_4gb*/false, &error_msg);
+ vdex = VdexFile::Open(
+ tmp.GetFilename(), /*writable*/false, /*low_4gb*/false, /*quicken*/ false, &error_msg);
EXPECT_TRUE(vdex == nullptr);
}
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 2b0c612..cb9c605 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3764,7 +3764,7 @@
const RegType& referrer = GetDeclaringClass();
if (!referrer.IsUnresolvedTypes() && !referrer.CanAccess(*result)) {
Fail(VERIFY_ERROR_ACCESS_CLASS) << "illegal class access: '"
- << referrer << "' -> '" << result << "'";
+ << referrer << "' -> '" << *result << "'";
}
}
return *result;
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 5e5b409..f725b89 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -605,6 +605,8 @@
fi
if [ "$TEST_VDEX" = "y" ]; then
vdex_cmdline="${dex2oat_cmdline} ${VDEX_FILTER} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
+ elif [ "$PROFILE" = "y" ] || [ "$RANDOM_PROFILE" = "y" ]; then
+ vdex_cmdline="${dex2oat_cmdline} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex --output-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
fi
fi
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 9ab9bfa..c7ad5bf 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -665,5 +665,23 @@
"description": "The tests above fail with --build-with-javac-dx.",
"env_vars": {"ANDROID_COMPILE_WITH_JACK": "false"},
"bug": "b/37636792"
+ },
+ {
+ "tests": "648-many-direct-methods",
+ "variant": "optimizing",
+ "description": "Test disabled with AOT because of dex2oatd timeouts.",
+ "bug": "b/33650497"
+ },
+ {
+ "tests": [
+ "536-checker-needs-access-check",
+ "537-checker-inline-and-unverified",
+ "569-checker-pattern-replacement",
+ "586-checker-null-array-get"
+ ],
+ "description": [
+ "Tests that have verify-at-runtime classes, but being compiled when using vdex."
+ ],
+ "variant": "speed-profile"
}
]