Merge "Fix build rules for statically linked oatdump on host."
diff --git a/compiler/Android.bp b/compiler/Android.bp
index e2a450d..1737376 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -254,7 +254,10 @@
},
},
},
- shared_libs: ["libart"],
+ shared_libs: [
+ "libart",
+ "libart-dexlayout",
+ ],
}
art_cc_library {
@@ -291,7 +294,10 @@
},
},
},
- shared_libs: ["libartd"],
+ shared_libs: [
+ "libartd",
+ "libartd-dexlayout"
+ ],
}
art_cc_library {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index c62e214..e155e10 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1980,8 +1980,16 @@
// 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()) {
+ // Create the main VerifierDeps, and set it to this thread.
Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
new verifier::VerifierDeps(dex_files));
+ Thread::Current()->SetVerifierDeps(
+ Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps());
+ // Create per-thread VerifierDeps to avoid contention on the main one.
+ // We will merge them after verification.
+ for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) {
+ worker->GetThread()->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
@@ -1995,6 +2003,19 @@
parallel_thread_count_,
timings);
}
+
+ if (!GetCompilerOptions().IsBootImage()) {
+ verifier::VerifierDeps* main_deps =
+ Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps();
+ // Merge all VerifierDeps into the main one.
+ for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) {
+ verifier::VerifierDeps* thread_deps = worker->GetThread()->GetVerifierDeps();
+ worker->GetThread()->SetVerifierDeps(nullptr);
+ main_deps->MergeWith(*thread_deps, dex_files);;
+ delete thread_deps;
+ }
+ Thread::Current()->SetVerifierDeps(nullptr);
+ }
}
class VerifyClassVisitor : public CompilationVisitor {
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index fcb8979..5629dff 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -211,7 +211,9 @@
&driver->GetCompilerOptions(),
oat_file.GetFile()));
elf_writers.back()->Start();
- oat_writers.emplace_back(new OatWriter(/*compiling_boot_image*/true, &timings));
+ oat_writers.emplace_back(new OatWriter(/*compiling_boot_image*/true,
+ &timings,
+ /*profile_compilation_info*/nullptr));
}
std::vector<OutputStream*> rodata;
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 102637f..9458576 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -125,7 +125,9 @@
SafeMap<std::string, std::string>& key_value_store,
bool verify) {
TimingLogger timings("WriteElf", false, false);
- OatWriter oat_writer(/*compiling_boot_image*/false, &timings);
+ OatWriter oat_writer(/*compiling_boot_image*/false,
+ &timings,
+ /*profile_compilation_info*/nullptr);
for (const DexFile* dex_file : dex_files) {
ArrayRef<const uint8_t> raw_dex_file(
reinterpret_cast<const uint8_t*>(&dex_file->GetHeader()),
@@ -145,7 +147,9 @@
SafeMap<std::string, std::string>& key_value_store,
bool verify) {
TimingLogger timings("WriteElf", false, false);
- OatWriter oat_writer(/*compiling_boot_image*/false, &timings);
+ OatWriter oat_writer(/*compiling_boot_image*/false,
+ &timings,
+ /*profile_compilation_info*/nullptr);
for (const char* dex_filename : dex_filenames) {
if (!oat_writer.AddDexFileSource(dex_filename, dex_filename)) {
return false;
@@ -161,7 +165,9 @@
SafeMap<std::string, std::string>& key_value_store,
bool verify) {
TimingLogger timings("WriteElf", false, false);
- OatWriter oat_writer(/*compiling_boot_image*/false, &timings);
+ OatWriter oat_writer(/*compiling_boot_image*/false,
+ &timings,
+ /*profile_compilation_info*/nullptr);
if (!oat_writer.AddZippedDexFilesSource(std::move(zip_fd), location)) {
return false;
}
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index bde00cf..eed9d11 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -33,6 +33,7 @@
#include "debug/method_debug_info.h"
#include "dex/verification_results.h"
#include "dex_file-inl.h"
+#include "dexlayout.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
#include "gc/space/image_space.h"
@@ -276,7 +277,7 @@
DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
<< "file_offset=" << file_offset << " offset_=" << offset_
-OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings)
+OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info)
: write_state_(WriteState::kAddingDexFileSources),
timings_(timings),
raw_dex_files_(),
@@ -337,7 +338,8 @@
size_oat_class_method_bitmaps_(0),
size_oat_class_method_offsets_(0),
relative_patcher_(nullptr),
- absolute_patch_locations_() {
+ absolute_patch_locations_(),
+ profile_compilation_info_(info) {
}
bool OatWriter::AddDexFileSource(const char* filename,
@@ -2081,7 +2083,11 @@
if (!SeekToDexFile(out, file, oat_dex_file)) {
return false;
}
- if (oat_dex_file->source_.IsZipEntry()) {
+ if (profile_compilation_info_ != nullptr) {
+ if (!LayoutAndWriteDexFile(out, oat_dex_file)) {
+ return false;
+ }
+ } else if (oat_dex_file->source_.IsZipEntry()) {
if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
return false;
}
@@ -2146,6 +2152,39 @@
return true;
}
+bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) {
+ TimingLogger::ScopedTiming split("Dex Layout", timings_);
+ std::string error_msg;
+ std::string location(oat_dex_file->GetLocation());
+ std::unique_ptr<const DexFile> dex_file;
+ if (oat_dex_file->source_.IsZipEntry()) {
+ ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
+ std::unique_ptr<MemMap> mem_map(
+ zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg));
+ dex_file = DexFile::Open(location,
+ zip_entry->GetCrc32(),
+ std::move(mem_map),
+ /* verify */ true,
+ /* verify_checksum */ true,
+ &error_msg);
+ } else {
+ DCHECK(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);
+ }
+ Options options;
+ options.output_to_memmap_ = true;
+ DexLayout dex_layout(options, profile_compilation_info_, nullptr);
+ dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0);
+ std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap());
+ if (!WriteDexFile(out, oat_dex_file, mem_map->Begin())) {
+ return false;
+ }
+ // Set the checksum of the new oat dex file to be the original file's checksum.
+ oat_dex_file->dex_file_location_checksum_ = dex_file->GetLocationChecksum();
+ return true;
+}
+
bool OatWriter::WriteDexFile(OutputStream* out,
File* file,
OatDexFile* oat_dex_file,
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index b92ba76..f9671d7 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -38,6 +38,7 @@
class CompiledMethod;
class CompilerDriver;
class ImageWriter;
+class ProfileCompilationInfo;
class OutputStream;
class TimingLogger;
class TypeLookupTable;
@@ -110,7 +111,7 @@
kDefault = kCreate
};
- OatWriter(bool compiling_boot_image, TimingLogger* timings);
+ OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info);
// To produce a valid oat file, the user must first add sources with any combination of
// - AddDexFileSource(),
@@ -258,6 +259,7 @@
bool WriteDexFiles(OutputStream* out, File* file);
bool WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file);
bool SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file);
+ bool LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file);
bool WriteDexFile(OutputStream* out,
File* file,
OatDexFile* oat_dex_file,
@@ -422,6 +424,9 @@
// The locations of absolute patches relative to the start of the executable section.
dchecked_vector<uintptr_t> absolute_patch_locations_;
+ // Profile info used to generate new layout of files.
+ ProfileCompilationInfo* profile_compilation_info_;
+
DISALLOW_COPY_AND_ASSIGN(OatWriter);
};
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index e4bef34..110430f 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -1281,20 +1281,20 @@
// For compressed strings we need to clear 0x7 from temp1, for uncompressed we need to clear
// 0xf. We also need to prepare the character extraction mask `uncompressed ? 0xffffu : 0xffu`.
// The compression flag is now in the highest bit of temp3, so let's play some tricks.
- __ orr(temp3, temp3, 0xffu << 23); // uncompressed ? 0xff800000u : 0x7ff80000u
- __ bic(temp1, temp1, Operand(temp3, vixl32::LSR, 31 - 3)); // &= ~(uncompressed ? 0xfu : 0x7u)
+ __ Orr(temp3, temp3, 0xffu << 23); // uncompressed ? 0xff800000u : 0x7ff80000u
+ __ Bic(temp1, temp1, Operand(temp3, vixl32::LSR, 31 - 3)); // &= ~(uncompressed ? 0xfu : 0x7u)
__ Asr(temp3, temp3, 7u); // uncompressed ? 0xffff0000u : 0xff0000u.
__ Lsr(temp2, temp2, temp1); // Extract second character.
__ Lsr(temp3, temp3, 16u); // uncompressed ? 0xffffu : 0xffu
__ Lsr(out, temp_reg, temp1); // Extract first character.
- __ and_(temp2, temp2, temp3);
- __ and_(out, out, temp3);
+ __ And(temp2, temp2, temp3);
+ __ And(out, out, temp3);
} else {
- __ bic(temp1, temp1, 0xf);
+ __ Bic(temp1, temp1, 0xf);
__ Lsr(temp2, temp2, temp1);
__ Lsr(out, temp_reg, temp1);
- __ movt(temp2, 0);
- __ movt(out, 0);
+ __ Movt(temp2, 0);
+ __ Movt(out, 0);
}
__ Sub(out, out, temp2);
@@ -1313,10 +1313,10 @@
// need to treat as unsigned. Start by freeing the bit with an ADD and continue
// further down by a LSRS+SBC which will flip the meaning of the flag but allow
// `subs temp0, #2; bhi different_compression_loop` to serve as the loop condition.
- __ add(temp0, temp0, temp0); // Unlike LSL, this ADD is always 16-bit.
+ __ Add(temp0, temp0, temp0); // Unlike LSL, this ADD is always 16-bit.
// `temp1` will hold the compressed data pointer, `temp2` the uncompressed data pointer.
- __ mov(temp1, str);
- __ mov(temp2, arg);
+ __ Mov(temp1, str);
+ __ Mov(temp2, arg);
__ Lsrs(temp3, temp3, 1u); // Continue the move of the compression flag.
{
AssemblerAccurateScope aas(assembler->GetVIXLAssembler(),
@@ -1326,11 +1326,11 @@
__ mov(cs, temp1, arg); // Preserves flags.
__ mov(cs, temp2, str); // Preserves flags.
}
- __ sbc(temp0, temp0, 0); // Complete the move of the compression flag.
+ __ Sbc(temp0, temp0, 0); // Complete the move of the compression flag.
// Adjust temp1 and temp2 from string pointers to data pointers.
- __ add(temp1, temp1, value_offset);
- __ add(temp2, temp2, value_offset);
+ __ Add(temp1, temp1, value_offset);
+ __ Add(temp2, temp2, value_offset);
vixl32::Label different_compression_loop;
vixl32::Label different_compression_diff;
@@ -1340,7 +1340,7 @@
__ Bind(&different_compression_loop);
__ Ldrb(temp_reg, MemOperand(temp1, c_char_size, PostIndex));
__ Ldrh(temp3, MemOperand(temp2, char_size, PostIndex));
- __ cmp(temp_reg, temp3);
+ __ Cmp(temp_reg, temp3);
__ B(ne, &different_compression_diff);
__ Subs(temp0, temp0, 2);
__ B(hi, &different_compression_loop);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 604d99c..2382b72 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1211,7 +1211,7 @@
roots);
if (code == nullptr) {
- code_cache->ClearData(self, stack_map_data);
+ code_cache->ClearData(self, stack_map_data, roots_data);
return false;
}
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 03d3f4e..dcf3619 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -154,6 +154,7 @@
}
CHECK(method != nullptr);
+ Thread::Current()->SetVerifierDeps(callbacks_->GetVerifierDeps());
MethodVerifier verifier(Thread::Current(),
primary_dex_file_,
dex_cache_handle,
@@ -169,6 +170,7 @@
false /* verify to dump */,
true /* allow_thread_suspension */);
verifier.Verify();
+ Thread::Current()->SetVerifierDeps(nullptr);
return !verifier.HasFailures();
}
@@ -230,7 +232,6 @@
const DexFile::TypeId* type_id = primary_dex_file_->FindTypeId(cls.c_str());
DCHECK(type_id != nullptr);
dex::TypeIndex index = primary_dex_file_->GetIndexForTypeId(*type_id);
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (const auto& dex_dep : verifier_deps_->dex_deps_) {
for (dex::TypeIndex entry : dex_dep.second->unverified_classes_) {
if (index == entry) {
@@ -246,7 +247,6 @@
bool HasAssignable(const std::string& expected_destination,
const std::string& expected_source,
bool expected_is_assignable) {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
const DexFile& dex_file = *dex_dep.first;
auto& storage = expected_is_assignable ? dex_dep.second->assignable_types_
@@ -268,7 +268,6 @@
bool HasClass(const std::string& expected_klass,
bool expected_resolved,
const std::string& expected_access_flags = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
for (auto& entry : dex_dep.second->classes_) {
if (expected_resolved != entry.IsResolved()) {
@@ -303,7 +302,6 @@
bool expected_resolved,
const std::string& expected_access_flags = "",
const std::string& expected_decl_klass = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
for (auto& entry : dex_dep.second->fields_) {
if (expected_resolved != entry.IsResolved()) {
@@ -357,7 +355,6 @@
bool expected_resolved,
const std::string& expected_access_flags = "",
const std::string& expected_decl_klass = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
auto& storage = (expected_kind == "direct") ? dex_dep.second->direct_methods_
: (expected_kind == "virtual") ? dex_dep.second->virtual_methods_
@@ -406,13 +403,10 @@
}
size_t NumberOfCompiledDexFiles() {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
return verifier_deps_->dex_deps_.size();
}
size_t HasEachKindOfRecord() {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
bool has_strings = false;
bool has_assignability = false;
bool has_classes = false;
@@ -463,8 +457,6 @@
ScopedObjectAccess soa(Thread::Current());
LoadDexFile(&soa);
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
uint32_t id_Main1 = verifier_deps_->GetIdFromString(*primary_dex_file_, "LMain;");
ASSERT_LT(id_Main1, primary_dex_file_->NumStringIds());
ASSERT_EQ("LMain;", verifier_deps_->GetStringFromId(*primary_dex_file_, id_Main1));
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 05a5d0f..0924aec 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -89,6 +89,7 @@
],
static_libs: [
"libart-compiler",
+ "libart-dexlayout",
"libart",
"libvixl-arm",
"libvixl-arm64",
@@ -118,6 +119,7 @@
],
static_libs: [
"libartd-compiler",
+ "libartd-dexlayout",
"libartd",
"libvixld-arm",
"libvixld-arm64",
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 65703a2..20b5bba 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -270,6 +270,7 @@
"|balanced"
"|speed-profile"
"|speed"
+ "|layout-profile"
"|everything-profile"
"|everything):");
UsageError(" select compiler filter.");
@@ -1479,13 +1480,15 @@
// Unzip or copy dex files straight to the oat file.
std::unique_ptr<MemMap> opened_dex_files_map;
std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
+ // Dexlayout verifies the dex file, so disable dex file verification in that case.
+ bool verify = compiler_options_->GetCompilerFilter() != CompilerFilter::kLayoutProfile;
if (!oat_writers_[i]->WriteAndOpenDexFiles(
kIsVdexEnabled ? vdex_files_[i].get() : oat_files_[i].get(),
rodata_.back(),
instruction_set_,
instruction_set_features_.get(),
key_value_store_.get(),
- /* verify */ true,
+ verify,
&opened_dex_files_map,
&opened_dex_files)) {
return false;
@@ -2273,7 +2276,9 @@
compiler_options_.get(),
oat_file.get()));
elf_writers_.back()->Start();
- oat_writers_.emplace_back(new OatWriter(IsBootImage(), timings_));
+ bool do_dexlayout = compiler_options_->GetCompilerFilter() == CompilerFilter::kLayoutProfile;
+ oat_writers_.emplace_back(new OatWriter(
+ IsBootImage(), timings_, do_dexlayout ? profile_compilation_info_.get() : nullptr));
}
}
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index fa32178..714a58c 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -24,6 +24,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/stringprintf.h"
+#include "dex_file-inl.h"
#include "dex2oat_environment_test.h"
#include "oat.h"
#include "oat_file.h"
@@ -551,4 +552,107 @@
RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" });
}
+static const char kDexFileLayoutInputProfile[] = "cHJvADAwMgABAAwAAQABAOqMEeFEZXhOb09hdC5qYXIBAAEA";
+
+static void WriteFileBase64(const char* base64, const char* location) {
+ // Decode base64.
+ CHECK(base64 != nullptr);
+ size_t length;
+ std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
+ CHECK(bytes.get() != nullptr);
+
+ // Write to provided file.
+ std::unique_ptr<File> file(OS::CreateEmptyFile(location));
+ CHECK(file.get() != nullptr);
+ if (!file->WriteFully(bytes.get(), length)) {
+ PLOG(FATAL) << "Failed to write base64 as file";
+ }
+ if (file->FlushCloseOrErase() != 0) {
+ PLOG(FATAL) << "Could not flush and close test file.";
+ }
+}
+
+class Dex2oatLayoutTest : public Dex2oatTest {
+ protected:
+ void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
+ CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
+ // Ignore, we'll do our own checks.
+ }
+
+ void RunTest() {
+ std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
+ std::string profile_location = GetScratchDir() + "/primary.prof";
+ std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
+
+ Copy(GetDexSrc2(), dex_location);
+ WriteFileBase64(kDexFileLayoutInputProfile, profile_location.c_str());
+
+ const std::vector<std::string>& extra_args = { "--profile-file=" + profile_location };
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kLayoutProfile, extra_args);
+
+ CheckValidity();
+ ASSERT_TRUE(success_);
+ CheckResult(dex_location, odex_location);
+ }
+ void CheckResult(const std::string& dex_location, const std::string& odex_location) {
+ // Host/target independent checks.
+ 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;
+
+ const char* location = dex_location.c_str();
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
+ EXPECT_EQ(dex_files.size(), 1U);
+ std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
+
+ for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
+ std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg);
+ ASSERT_TRUE(new_dex_file != nullptr);
+ uint32_t class_def_count = new_dex_file->NumClassDefs();
+ ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
+ ASSERT_GE(class_def_count, 2U);
+
+ // The new layout swaps the classes at indexes 0 and 1.
+ std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_);
+ std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_);
+ std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_);
+ std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_);
+ EXPECT_EQ(old_class0, new_class1);
+ EXPECT_EQ(old_class1, new_class0);
+ }
+
+ EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kLayoutProfile);
+ }
+
+ // Check whether the dex2oat run was really successful.
+ void CheckValidity() {
+ if (kIsTargetBuild) {
+ CheckTargetValidity();
+ } else {
+ CheckHostValidity();
+ }
+ }
+
+ void CheckTargetValidity() {
+ // TODO: Ignore for now.
+ }
+
+ // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
+ void CheckHostValidity() {
+ EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
+ }
+ };
+
+TEST_F(Dex2oatLayoutTest, TestLayout) {
+ RunTest();
+}
+
} // namespace art
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index b9266f7..9ee9ebd 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -12,28 +12,46 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-art_cc_binary {
- name: "dexlayout",
+art_cc_defaults {
+ name: "libart-dexlayout-defaults",
host_supported: true,
srcs: [
- "dexlayout_main.cc",
"dexlayout.cc",
"dex_ir.cc",
"dex_ir_builder.cc",
"dex_visualize.cc",
"dex_writer.cc",
],
+ export_include_dirs: ["."],
+ shared_libs: ["libbase"],
+ static_libs: ["libz"],
+}
+
+art_cc_library {
+ name: "libart-dexlayout",
+ defaults: ["libart-dexlayout-defaults"],
+ shared_libs: ["libart"],
+}
+
+art_cc_library {
+ name: "libartd-dexlayout",
+ defaults: ["libart-dexlayout-defaults"],
+ shared_libs: ["libartd"],
+}
+
+art_cc_binary {
+ name: "dexlayout",
+ host_supported: true,
+ srcs: ["dexlayout_main.cc"],
cflags: ["-Wall"],
shared_libs: [
"libart",
- "libbase",
+ "libart-dexlayout",
],
}
art_cc_test {
name: "art_dexlayout_tests",
- defaults: [
- "art_gtest_defaults",
- ],
+ defaults: ["art_gtest_defaults"],
srcs: ["dexlayout_test.cc"],
}
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 67f3e09..fe2bcce 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -56,6 +56,36 @@
entry.end_address_, entry.reg_)));
}
+static uint32_t GetCodeItemSize(const DexFile& dex_file, const DexFile::CodeItem& disk_code_item) {
+ uintptr_t code_item_start = reinterpret_cast<uintptr_t>(&disk_code_item);
+ uint32_t insns_size = disk_code_item.insns_size_in_code_units_;
+ uint32_t tries_size = disk_code_item.tries_size_;
+ if (tries_size == 0) {
+ uintptr_t insns_end = reinterpret_cast<uintptr_t>(&disk_code_item.insns_[insns_size]);
+ return insns_end - code_item_start;
+ } else {
+ uint32_t last_handler_off = 0;
+ for (uint32_t i = 0; i < tries_size; ++i) {
+ // Iterate over the try items to find the last catch handler.
+ const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i);
+ uint16_t handler_off = disk_try_item->handler_off_;
+ if (handler_off > last_handler_off) {
+ last_handler_off = handler_off;
+ }
+ }
+ // Decode the final handler to see where it ends.
+ const uint8_t* handler_data = DexFile::GetCatchHandlerData(disk_code_item, last_handler_off);
+ int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
+ if (uleb128_count <= 0) {
+ uleb128_count = -uleb128_count + 1;
+ }
+ for (int32_t i = 0; i < uleb128_count; ++i) {
+ DecodeUnsignedLeb128(&handler_data);
+ }
+ return reinterpret_cast<uintptr_t>(handler_data) - code_item_start;
+ }
+}
+
static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
const uint8_t* stream = debug_info_stream;
DecodeUnsignedLeb128(&stream); // line_start
@@ -384,11 +414,9 @@
if (dex_type_list == nullptr) {
return nullptr;
}
- // TODO: Create more efficient lookup for existing type lists.
- for (std::unique_ptr<TypeList>& type_list : TypeLists()) {
- if (type_list->GetOffset() == offset) {
- return type_list.get();
- }
+ auto found_type_list = TypeLists().find(offset);
+ if (found_type_list != TypeLists().end()) {
+ return found_type_list->second.get();
}
TypeIdVector* type_vector = new TypeIdVector();
uint32_t size = dex_type_list->Size();
@@ -404,10 +432,9 @@
if (static_data == nullptr) {
return nullptr;
}
- for (std::unique_ptr<EncodedArrayItem>& existing_array_item : EncodedArrayItems()) {
- if (existing_array_item->GetOffset() == offset) {
- return existing_array_item.get();
- }
+ auto found_encoded_array_item = EncodedArrayItems().find(offset);
+ if (found_encoded_array_item != EncodedArrayItems().end()) {
+ return found_encoded_array_item->second.get();
}
uint32_t size = DecodeUnsignedLeb128(&static_data);
EncodedValueVector* values = new EncodedValueVector();
@@ -422,10 +449,9 @@
AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* annotation,
uint32_t offset) {
- for (std::unique_ptr<AnnotationItem>& existing_annotation_item : AnnotationItems()) {
- if (existing_annotation_item->GetOffset() == offset) {
- return existing_annotation_item.get();
- }
+ auto found_annotation_item = AnnotationItems().find(offset);
+ if (found_annotation_item != AnnotationItems().end()) {
+ return found_annotation_item->second.get();
}
uint8_t visibility = annotation->visibility_;
const uint8_t* annotation_data = annotation->annotation_;
@@ -444,10 +470,9 @@
if (disk_annotations_item.size_ == 0 && offset == 0) {
return nullptr;
}
- for (std::unique_ptr<AnnotationSetItem>& existing_anno_set_item : AnnotationSetItems()) {
- if (existing_anno_set_item->GetOffset() == offset) {
- return existing_anno_set_item.get();
- }
+ auto found_anno_set_item = AnnotationSetItems().find(offset);
+ if (found_anno_set_item != AnnotationSetItems().end()) {
+ return found_anno_set_item->second.get();
}
std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) {
@@ -467,10 +492,9 @@
AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
- for (std::unique_ptr<AnnotationsDirectoryItem>& anno_dir_item : AnnotationsDirectoryItems()) {
- if (anno_dir_item->GetOffset() == offset) {
- return anno_dir_item.get();
- }
+ auto found_anno_dir_item = AnnotationsDirectoryItems().find(offset);
+ if (found_anno_dir_item != AnnotationsDirectoryItems().end()) {
+ return found_anno_dir_item->second.get();
}
const DexFile::AnnotationSetItem* class_set_item =
dex_file.GetClassAnnotationSet(disk_annotations_item);
@@ -535,11 +559,9 @@
const DexFile& dex_file, MethodId* method_id,
const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
AnnotationSetRefList* set_ref_list = nullptr;
- for (std::unique_ptr<AnnotationSetRefList>& existing_set_ref_list : AnnotationSetRefLists()) {
- if (existing_set_ref_list->GetOffset() == offset) {
- set_ref_list = existing_set_ref_list.get();
- break;
- }
+ auto found_set_ref_list = AnnotationSetRefLists().find(offset);
+ if (found_set_ref_list != AnnotationSetRefLists().end()) {
+ set_ref_list = found_set_ref_list->second.get();
}
if (set_ref_list == nullptr) {
std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
@@ -610,9 +632,10 @@
tries->push_back(std::unique_ptr<const TryItem>(try_item));
}
}
- // TODO: Calculate the size of the code item.
+ uint32_t size = GetCodeItemSize(dex_file, disk_code_item);
CodeItem* code_item = new CodeItem(
registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list);
+ code_item->SetSize(size);
code_items_.AddItem(code_item, offset);
// Add "fixup" references to types, strings, methods, and fields.
// This is temporary, as we will probably want more detailed parsing of the
@@ -690,8 +713,8 @@
virtual_methods->push_back(
std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii)));
}
- // TODO: Calculate the size of the class data.
class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods);
+ class_data->SetSize(cdii.EndDataPointer() - encoded_data);
class_datas_.AddItem(class_data, offset);
}
return class_data;
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 38eb0b1..a2d1190 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -19,6 +19,7 @@
#ifndef ART_DEXLAYOUT_DEX_IR_H_
#define ART_DEXLAYOUT_DEX_IR_H_
+#include <map>
#include <vector>
#include <stdint.h>
@@ -98,34 +99,52 @@
};
// Collections become owners of the objects added by moving them into unique pointers.
-template<class T> class CollectionWithOffset {
+template<class T> class CollectionBase {
public:
- CollectionWithOffset() = default;
- std::vector<std::unique_ptr<T>>& Collection() { return collection_; }
- // Read-time support methods
- void AddItem(T* object, uint32_t offset) {
- object->SetOffset(offset);
- collection_.push_back(std::unique_ptr<T>(object));
- }
+ CollectionBase() = default;
+
+ uint32_t GetOffset() const { return offset_; }
+ void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
+
+ private:
+ uint32_t offset_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(CollectionBase);
+};
+
+template<class T> class CollectionVector : public CollectionBase<T> {
+ public:
+ CollectionVector() = default;
+
void AddIndexedItem(T* object, uint32_t offset, uint32_t index) {
object->SetOffset(offset);
object->SetIndex(index);
collection_.push_back(std::unique_ptr<T>(object));
}
- // Ordinary object insertion into collection.
- void Insert(T object ATTRIBUTE_UNUSED) {
- // TODO(sehr): add ordered insertion support.
- UNIMPLEMENTED(FATAL) << "Insertion not ready";
- }
- uint32_t GetOffset() const { return offset_; }
- void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
uint32_t Size() const { return collection_.size(); }
+ std::vector<std::unique_ptr<T>>& Collection() { return collection_; }
private:
std::vector<std::unique_ptr<T>> collection_;
- uint32_t offset_ = 0;
- DISALLOW_COPY_AND_ASSIGN(CollectionWithOffset);
+ DISALLOW_COPY_AND_ASSIGN(CollectionVector);
+};
+
+template<class T> class CollectionMap : public CollectionBase<T> {
+ public:
+ CollectionMap() = default;
+
+ void AddItem(T* object, uint32_t offset) {
+ object->SetOffset(offset);
+ collection_.emplace(offset, std::unique_ptr<T>(object));
+ }
+ uint32_t Size() const { return collection_.size(); }
+ std::map<uint32_t, std::unique_ptr<T>>& Collection() { return collection_; }
+
+ private:
+ std::map<uint32_t, std::unique_ptr<T>> collection_;
+
+ DISALLOW_COPY_AND_ASSIGN(CollectionMap);
};
class Collections {
@@ -138,22 +157,23 @@
std::vector<std::unique_ptr<FieldId>>& FieldIds() { return field_ids_.Collection(); }
std::vector<std::unique_ptr<MethodId>>& MethodIds() { return method_ids_.Collection(); }
std::vector<std::unique_ptr<ClassDef>>& ClassDefs() { return class_defs_.Collection(); }
- std::vector<std::unique_ptr<StringData>>& StringDatas() { return string_datas_.Collection(); }
- std::vector<std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
- std::vector<std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems()
+ std::map<uint32_t, std::unique_ptr<StringData>>& StringDatas()
+ { return string_datas_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems()
{ return encoded_array_items_.Collection(); }
- std::vector<std::unique_ptr<AnnotationItem>>& AnnotationItems()
+ std::map<uint32_t, std::unique_ptr<AnnotationItem>>& AnnotationItems()
{ return annotation_items_.Collection(); }
- std::vector<std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems()
+ std::map<uint32_t, std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems()
{ return annotation_set_items_.Collection(); }
- std::vector<std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists()
+ std::map<uint32_t, std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists()
{ return annotation_set_ref_lists_.Collection(); }
- std::vector<std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems()
+ std::map<uint32_t, std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems()
{ return annotations_directory_items_.Collection(); }
- std::vector<std::unique_ptr<DebugInfoItem>>& DebugInfoItems()
+ std::map<uint32_t, std::unique_ptr<DebugInfoItem>>& DebugInfoItems()
{ return debug_info_items_.Collection(); }
- std::vector<std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); }
- std::vector<std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); }
void CreateStringId(const DexFile& dex_file, uint32_t i);
void CreateTypeId(const DexFile& dex_file, uint32_t i);
@@ -204,7 +224,7 @@
uint32_t DebugInfoItemsOffset() const { return debug_info_items_.GetOffset(); }
uint32_t CodeItemsOffset() const { return code_items_.GetOffset(); }
uint32_t ClassDatasOffset() const { return class_datas_.GetOffset(); }
- uint32_t MapItemOffset() const { return map_item_offset_; }
+ uint32_t MapListOffset() const { return map_list_offset_; }
void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); }
void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); }
@@ -226,7 +246,7 @@
void SetDebugInfoItemsOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); }
void SetCodeItemsOffset(uint32_t new_offset) { code_items_.SetOffset(new_offset); }
void SetClassDatasOffset(uint32_t new_offset) { class_datas_.SetOffset(new_offset); }
- void SetMapItemOffset(uint32_t new_offset) { map_item_offset_ = new_offset; }
+ void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; }
uint32_t StringIdsSize() const { return string_ids_.Size(); }
uint32_t TypeIdsSize() const { return type_ids_.Size(); }
@@ -254,25 +274,25 @@
const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset);
MethodItem* GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii);
- CollectionWithOffset<StringId> string_ids_;
- CollectionWithOffset<TypeId> type_ids_;
- CollectionWithOffset<ProtoId> proto_ids_;
- CollectionWithOffset<FieldId> field_ids_;
- CollectionWithOffset<MethodId> method_ids_;
- CollectionWithOffset<ClassDef> class_defs_;
+ CollectionVector<StringId> string_ids_;
+ CollectionVector<TypeId> type_ids_;
+ CollectionVector<ProtoId> proto_ids_;
+ CollectionVector<FieldId> field_ids_;
+ CollectionVector<MethodId> method_ids_;
+ CollectionVector<ClassDef> class_defs_;
- CollectionWithOffset<StringData> string_datas_;
- CollectionWithOffset<TypeList> type_lists_;
- CollectionWithOffset<EncodedArrayItem> encoded_array_items_;
- CollectionWithOffset<AnnotationItem> annotation_items_;
- CollectionWithOffset<AnnotationSetItem> annotation_set_items_;
- CollectionWithOffset<AnnotationSetRefList> annotation_set_ref_lists_;
- CollectionWithOffset<AnnotationsDirectoryItem> annotations_directory_items_;
- CollectionWithOffset<DebugInfoItem> debug_info_items_;
- CollectionWithOffset<CodeItem> code_items_;
- CollectionWithOffset<ClassData> class_datas_;
+ CollectionMap<StringData> string_datas_;
+ CollectionMap<TypeList> type_lists_;
+ CollectionMap<EncodedArrayItem> encoded_array_items_;
+ CollectionMap<AnnotationItem> annotation_items_;
+ CollectionMap<AnnotationSetItem> annotation_set_items_;
+ CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_;
+ CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_;
+ CollectionMap<DebugInfoItem> debug_info_items_;
+ CollectionMap<CodeItem> code_items_;
+ CollectionMap<ClassData> class_datas_;
- uint32_t map_item_offset_ = 0;
+ uint32_t map_list_offset_ = 0;
DISALLOW_COPY_AND_ASSIGN(Collections);
};
@@ -539,20 +559,20 @@
class MethodItem : public Item {
public:
- MethodItem(uint32_t access_flags, const MethodId* method_id, const CodeItem* code)
+ MethodItem(uint32_t access_flags, const MethodId* method_id, CodeItem* code)
: access_flags_(access_flags), method_id_(method_id), code_(code) { }
~MethodItem() OVERRIDE { }
uint32_t GetAccessFlags() const { return access_flags_; }
const MethodId* GetMethodId() const { return method_id_; }
- const CodeItem* GetCodeItem() const { return code_; }
+ CodeItem* GetCodeItem() { return code_; }
void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
private:
uint32_t access_flags_;
const MethodId* method_id_;
- const CodeItem* code_; // This can be nullptr.
+ CodeItem* code_; // This can be nullptr.
DISALLOW_COPY_AND_ASSIGN(MethodItem);
};
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 68ff2a2..d0c5bf9 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -71,7 +71,7 @@
collections.CreateClassDef(dex_file, i);
}
// MapItem.
- collections.SetMapItemOffset(disk_header.map_off_);
+ collections.SetMapListOffset(disk_header.map_off_);
CheckAndSetRemainingOffsets(dex_file, &collections);
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index 05ad98f..02274b2 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -263,11 +263,13 @@
DumpStringId(method_id->Name(), class_index);
}
- void DumpMethodItem(const dex_ir::MethodItem* method, const DexFile* dex_file, int class_index) {
- if (profile_info_ != nullptr) {
+ void DumpMethodItem(dex_ir::MethodItem* method,
+ const DexFile* dex_file,
+ int class_index,
+ ProfileCompilationInfo* profile_info) {
+ if (profile_info != nullptr) {
uint32_t method_idx = method->GetMethodId()->GetIndex();
- MethodReference mr(dex_file, method_idx);
- if (!profile_info_->ContainsMethod(mr)) {
+ if (!profile_info->ContainsMethod(MethodReference(dex_file, method_idx))) {
return;
}
}
@@ -344,14 +346,17 @@
* Dumps a gnuplot data file showing the parts of the dex_file that belong to each class.
* If profiling information is present, it dumps only those classes that are marked as hot.
*/
-void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index) {
+void VisualizeDexLayout(dex_ir::Header* header,
+ const DexFile* dex_file,
+ size_t dex_file_index,
+ ProfileCompilationInfo* profile_info) {
std::unique_ptr<Dumper> dumper(new Dumper(header->GetCollections(), dex_file_index));
const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) {
dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index);
dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
- if (profile_info_ != nullptr && !profile_info_->ContainsClass(*dex_file, type_idx)) {
+ if (profile_info != nullptr && !profile_info->ContainsClass(*dex_file, type_idx)) {
continue;
}
dumper->DumpAddressRange(class_def, class_index);
@@ -384,12 +389,12 @@
}
if (class_data->DirectMethods()) {
for (auto& method_item : *class_data->DirectMethods()) {
- dumper->DumpMethodItem(method_item.get(), dex_file, class_index);
+ dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info);
}
}
if (class_data->VirtualMethods()) {
for (auto& method_item : *class_data->VirtualMethods()) {
- dumper->DumpMethodItem(method_item.get(), dex_file, class_index);
+ dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info);
}
}
}
diff --git a/dexlayout/dex_visualize.h b/dexlayout/dex_visualize.h
index b1d2ed7..09f8306 100644
--- a/dexlayout/dex_visualize.h
+++ b/dexlayout/dex_visualize.h
@@ -28,11 +28,15 @@
namespace art {
class DexFile;
+class ProfileCompilationInfo;
namespace dex_ir {
class Header;
} // namespace dex_ir
-void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index);
+void VisualizeDexLayout(dex_ir::Header* header,
+ const DexFile* dex_file,
+ size_t dex_file_index,
+ ProfileCompilationInfo* profile_info);
} // namespace art
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index dba5da0..7ffa38b 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -104,7 +104,9 @@
}
size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) {
- return dex_file_->PwriteFully(buffer, length, offset) ? length : 0;
+ DCHECK_LE(offset + length, mem_map_->Size());
+ memcpy(mem_map_->Begin() + offset, buffer, length);
+ return length;
}
size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) {
@@ -236,12 +238,13 @@
void DexWriter::WriteStrings() {
uint32_t string_data_off[1];
- for (std::unique_ptr<dex_ir::StringId>& string_id : header_.GetCollections().StringIds()) {
+ for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) {
string_data_off[0] = string_id->DataItem()->GetOffset();
Write(string_data_off, string_id->GetSize(), string_id->GetOffset());
}
- for (std::unique_ptr<dex_ir::StringData>& string_data : header_.GetCollections().StringDatas()) {
+ for (auto& string_data_pair : header_->GetCollections().StringDatas()) {
+ std::unique_ptr<dex_ir::StringData>& string_data = string_data_pair.second;
uint32_t offset = string_data->GetOffset();
offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset);
Write(string_data->Data(), strlen(string_data->Data()), offset);
@@ -250,7 +253,7 @@
void DexWriter::WriteTypes() {
uint32_t descriptor_idx[1];
- for (std::unique_ptr<dex_ir::TypeId>& type_id : header_.GetCollections().TypeIds()) {
+ for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) {
descriptor_idx[0] = type_id->GetStringId()->GetIndex();
Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset());
}
@@ -259,7 +262,8 @@
void DexWriter::WriteTypeLists() {
uint32_t size[1];
uint16_t list[1];
- for (std::unique_ptr<dex_ir::TypeList>& type_list : header_.GetCollections().TypeLists()) {
+ for (auto& type_list_pair : header_->GetCollections().TypeLists()) {
+ std::unique_ptr<dex_ir::TypeList>& type_list = type_list_pair.second;
size[0] = type_list->GetTypeList()->size();
uint32_t offset = type_list->GetOffset();
offset += Write(size, sizeof(uint32_t), offset);
@@ -272,7 +276,7 @@
void DexWriter::WriteProtos() {
uint32_t buffer[3];
- for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_.GetCollections().ProtoIds()) {
+ for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) {
buffer[0] = proto_id->Shorty()->GetIndex();
buffer[1] = proto_id->ReturnType()->GetIndex();
buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset();
@@ -282,7 +286,7 @@
void DexWriter::WriteFields() {
uint16_t buffer[4];
- for (std::unique_ptr<dex_ir::FieldId>& field_id : header_.GetCollections().FieldIds()) {
+ for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) {
buffer[0] = field_id->Class()->GetIndex();
buffer[1] = field_id->Type()->GetIndex();
buffer[2] = field_id->Name()->GetIndex();
@@ -293,7 +297,7 @@
void DexWriter::WriteMethods() {
uint16_t buffer[4];
- for (std::unique_ptr<dex_ir::MethodId>& method_id : header_.GetCollections().MethodIds()) {
+ for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) {
buffer[0] = method_id->Class()->GetIndex();
buffer[1] = method_id->Proto()->GetIndex();
buffer[2] = method_id->Name()->GetIndex();
@@ -303,16 +307,16 @@
}
void DexWriter::WriteEncodedArrays() {
- for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array :
- header_.GetCollections().EncodedArrayItems()) {
+ for (auto& encoded_array_pair : header_->GetCollections().EncodedArrayItems()) {
+ std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array = encoded_array_pair.second;
WriteEncodedArray(encoded_array->GetEncodedValues(), encoded_array->GetOffset());
}
}
void DexWriter::WriteAnnotations() {
uint8_t visibility[1];
- for (std::unique_ptr<dex_ir::AnnotationItem>& annotation :
- header_.GetCollections().AnnotationItems()) {
+ for (auto& annotation_pair : header_->GetCollections().AnnotationItems()) {
+ std::unique_ptr<dex_ir::AnnotationItem>& annotation = annotation_pair.second;
visibility[0] = annotation->GetVisibility();
size_t offset = annotation->GetOffset();
offset += Write(visibility, sizeof(uint8_t), offset);
@@ -323,8 +327,8 @@
void DexWriter::WriteAnnotationSets() {
uint32_t size[1];
uint32_t annotation_off[1];
- for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set :
- header_.GetCollections().AnnotationSetItems()) {
+ for (auto& annotation_set_pair : header_->GetCollections().AnnotationSetItems()) {
+ std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set = annotation_set_pair.second;
size[0] = annotation_set->GetItems()->size();
size_t offset = annotation_set->GetOffset();
offset += Write(size, sizeof(uint32_t), offset);
@@ -338,8 +342,8 @@
void DexWriter::WriteAnnotationSetRefs() {
uint32_t size[1];
uint32_t annotations_off[1];
- for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref :
- header_.GetCollections().AnnotationSetRefLists()) {
+ for (auto& anno_set_ref_pair : header_->GetCollections().AnnotationSetRefLists()) {
+ std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref = anno_set_ref_pair.second;
size[0] = annotation_set_ref->GetItems()->size();
size_t offset = annotation_set_ref->GetOffset();
offset += Write(size, sizeof(uint32_t), offset);
@@ -353,8 +357,9 @@
void DexWriter::WriteAnnotationsDirectories() {
uint32_t directory_buffer[4];
uint32_t annotation_buffer[2];
- for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory :
- header_.GetCollections().AnnotationsDirectoryItems()) {
+ for (auto& annotations_directory_pair : header_->GetCollections().AnnotationsDirectoryItems()) {
+ std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory =
+ annotations_directory_pair.second;
directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
annotations_directory->GetClassAnnotation()->GetOffset();
directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 :
@@ -393,15 +398,17 @@
}
void DexWriter::WriteDebugInfoItems() {
- for (std::unique_ptr<dex_ir::DebugInfoItem>& info : header_.GetCollections().DebugInfoItems()) {
- Write(info->GetDebugInfo(), info->GetDebugInfoSize(), info->GetOffset());
+ for (auto& debug_info_pair : header_->GetCollections().DebugInfoItems()) {
+ std::unique_ptr<dex_ir::DebugInfoItem>& debug_info = debug_info_pair.second;
+ Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), debug_info->GetOffset());
}
}
void DexWriter::WriteCodeItems() {
uint16_t uint16_buffer[4];
uint32_t uint32_buffer[2];
- for (std::unique_ptr<dex_ir::CodeItem>& code_item : header_.GetCollections().CodeItems()) {
+ for (auto& code_item_pair : header_->GetCollections().CodeItems()) {
+ std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second;
uint16_buffer[0] = code_item->RegistersSize();
uint16_buffer[1] = code_item->InsSize();
uint16_buffer[2] = code_item->OutsSize();
@@ -446,7 +453,7 @@
void DexWriter::WriteClasses() {
uint32_t class_def_buffer[8];
- for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_.GetCollections().ClassDefs()) {
+ for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
class_def_buffer[0] = class_def->ClassType()->GetIndex();
class_def_buffer[1] = class_def->GetAccessFlags();
class_def_buffer[2] = class_def->Superclass() == nullptr ? DexFile::kDexNoIndex :
@@ -464,7 +471,8 @@
Write(class_def_buffer, class_def->GetSize(), offset);
}
- for (std::unique_ptr<dex_ir::ClassData>& class_data : header_.GetCollections().ClassDatas()) {
+ for (auto& class_data_pair : header_->GetCollections().ClassDatas()) {
+ std::unique_ptr<dex_ir::ClassData>& class_data = class_data_pair.second;
size_t offset = class_data->GetOffset();
offset += WriteUleb128(class_data->StaticFields()->size(), offset);
offset += WriteUleb128(class_data->InstanceFields()->size(), offset);
@@ -491,7 +499,7 @@
};
void DexWriter::WriteMapItem() {
- dex_ir::Collections& collection = header_.GetCollections();
+ dex_ir::Collections& collection = header_->GetCollections();
std::priority_queue<MapItemContainer> queue;
// Header and index section.
@@ -522,7 +530,7 @@
}
// Data section.
- queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapItemOffset()));
+ queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
if (collection.TypeListsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(),
collection.TypeListsOffset()));
@@ -564,7 +572,7 @@
collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset()));
}
- uint32_t offset = collection.MapItemOffset();
+ uint32_t offset = collection.MapListOffset();
uint16_t uint16_buffer[2];
uint32_t uint32_buffer[2];
uint16_buffer[1] = 0;
@@ -583,19 +591,19 @@
void DexWriter::WriteHeader() {
uint32_t buffer[20];
- dex_ir::Collections& collections = header_.GetCollections();
+ dex_ir::Collections& collections = header_->GetCollections();
size_t offset = 0;
- offset += Write(header_.Magic(), 8 * sizeof(uint8_t), offset);
- buffer[0] = header_.Checksum();
+ offset += Write(header_->Magic(), 8 * sizeof(uint8_t), offset);
+ buffer[0] = header_->Checksum();
offset += Write(buffer, sizeof(uint32_t), offset);
- offset += Write(header_.Signature(), 20 * sizeof(uint8_t), offset);
- uint32_t file_size = header_.FileSize();
+ offset += Write(header_->Signature(), 20 * sizeof(uint8_t), offset);
+ uint32_t file_size = header_->FileSize();
buffer[0] = file_size;
- buffer[1] = header_.GetSize();
- buffer[2] = header_.EndianTag();
- buffer[3] = header_.LinkSize();
- buffer[4] = header_.LinkOffset();
- buffer[5] = collections.MapItemOffset();
+ buffer[1] = header_->GetSize();
+ buffer[2] = header_->EndianTag();
+ buffer[3] = header_->LinkSize();
+ buffer[4] = header_->LinkOffset();
+ buffer[5] = collections.MapListOffset();
buffer[6] = collections.StringIdsSize();
buffer[7] = collections.StringIdsOffset();
buffer[8] = collections.TypeIdsSize();
@@ -617,12 +625,7 @@
Write(buffer, 20 * sizeof(uint32_t), offset);
}
-void DexWriter::WriteFile() {
- if (dex_file_.get() == nullptr) {
- fprintf(stderr, "Can't open output dex file\n");
- return;
- }
-
+void DexWriter::WriteMemMap() {
WriteStrings();
WriteTypes();
WriteTypeLists();
@@ -641,8 +644,9 @@
WriteHeader();
}
-void DexWriter::OutputDexFile(dex_ir::Header& header, const char* file_name) {
- (new DexWriter(header, file_name))->WriteFile();
+void DexWriter::Output(dex_ir::Header* header, MemMap* mem_map) {
+ DexWriter dex_writer(header, mem_map);
+ dex_writer.WriteMemMap();
}
} // namespace art
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index 9104295..fb76e5c 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -21,19 +21,19 @@
#include "base/unix_file/fd_file.h"
#include "dex_ir.h"
+#include "mem_map.h"
#include "os.h"
namespace art {
class DexWriter {
public:
- DexWriter(dex_ir::Header& header, const char* file_name) : header_(header),
- dex_file_(OS::CreateEmptyFileWriteOnly(file_name)) { }
+ DexWriter(dex_ir::Header* header, MemMap* mem_map) : header_(header), mem_map_(mem_map) { }
- static void OutputDexFile(dex_ir::Header& header, const char* file_name);
+ static void Output(dex_ir::Header* header, MemMap* mem_map);
private:
- void WriteFile();
+ void WriteMemMap();
size_t Write(const void* buffer, size_t length, size_t offset);
size_t WriteSleb128(uint32_t value, size_t offset);
@@ -62,13 +62,12 @@
void WriteMapItem();
void WriteHeader();
- dex_ir::Header& header_;
- std::unique_ptr<File> dex_file_;
+ dex_ir::Header* const header_;
+ MemMap* const mem_map_;
DISALLOW_COPY_AND_ASSIGN(DexWriter);
};
-
} // namespace art
#endif // ART_DEXLAYOUT_DEX_WRITER_H_
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index aa80655..cfe4837 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -37,27 +37,13 @@
#include "dex_visualize.h"
#include "dex_writer.h"
#include "jit/offline_profiling_info.h"
+#include "mem_map.h"
#include "os.h"
#include "utils.h"
namespace art {
/*
- * Options parsed in main driver.
- */
-struct Options options_;
-
-/*
- * Output file. Defaults to stdout.
- */
-FILE* out_file_ = stdout;
-
-/*
- * Profile information file.
- */
-ProfileCompilationInfo* profile_info_ = nullptr;
-
-/*
* Flags for use with createAccessFlagStr().
*/
enum AccessFor {
@@ -301,420 +287,65 @@
/*
* Dumps a string value with some escape characters.
*/
-static void DumpEscapedString(const char* p) {
- fputs("\"", out_file_);
+static void DumpEscapedString(const char* p, FILE* out_file) {
+ fputs("\"", out_file);
for (; *p; p++) {
switch (*p) {
case '\\':
- fputs("\\\\", out_file_);
+ fputs("\\\\", out_file);
break;
case '\"':
- fputs("\\\"", out_file_);
+ fputs("\\\"", out_file);
break;
case '\t':
- fputs("\\t", out_file_);
+ fputs("\\t", out_file);
break;
case '\n':
- fputs("\\n", out_file_);
+ fputs("\\n", out_file);
break;
case '\r':
- fputs("\\r", out_file_);
+ fputs("\\r", out_file);
break;
default:
- putc(*p, out_file_);
+ putc(*p, out_file);
} // switch
} // for
- fputs("\"", out_file_);
+ fputs("\"", out_file);
}
/*
* Dumps a string as an XML attribute value.
*/
-static void DumpXmlAttribute(const char* p) {
+static void DumpXmlAttribute(const char* p, FILE* out_file) {
for (; *p; p++) {
switch (*p) {
case '&':
- fputs("&", out_file_);
+ fputs("&", out_file);
break;
case '<':
- fputs("<", out_file_);
+ fputs("<", out_file);
break;
case '>':
- fputs(">", out_file_);
+ fputs(">", out_file);
break;
case '"':
- fputs(""", out_file_);
+ fputs(""", out_file);
break;
case '\t':
- fputs("	", out_file_);
+ fputs("	", out_file);
break;
case '\n':
- fputs("
", out_file_);
+ fputs("
", out_file);
break;
case '\r':
- fputs("
", out_file_);
+ fputs("
", out_file);
break;
default:
- putc(*p, out_file_);
+ putc(*p, out_file);
} // switch
} // for
}
-// Forward declare to resolve circular dependence.
-static void DumpEncodedValue(const dex_ir::EncodedValue* data);
-
-/*
- * Dumps encoded annotation.
- */
-static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
- fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
- // Display all name=value pairs.
- for (auto& subannotation : *annotation->GetAnnotationElements()) {
- fputc(' ', out_file_);
- fputs(subannotation->GetName()->Data(), out_file_);
- fputc('=', out_file_);
- DumpEncodedValue(subannotation->GetValue());
- }
-}
-/*
- * Dumps encoded value.
- */
-static void DumpEncodedValue(const dex_ir::EncodedValue* data) {
- switch (data->Type()) {
- case DexFile::kDexAnnotationByte:
- fprintf(out_file_, "%" PRId8, data->GetByte());
- break;
- case DexFile::kDexAnnotationShort:
- fprintf(out_file_, "%" PRId16, data->GetShort());
- break;
- case DexFile::kDexAnnotationChar:
- fprintf(out_file_, "%" PRIu16, data->GetChar());
- break;
- case DexFile::kDexAnnotationInt:
- fprintf(out_file_, "%" PRId32, data->GetInt());
- break;
- case DexFile::kDexAnnotationLong:
- fprintf(out_file_, "%" PRId64, data->GetLong());
- break;
- case DexFile::kDexAnnotationFloat: {
- fprintf(out_file_, "%g", data->GetFloat());
- break;
- }
- case DexFile::kDexAnnotationDouble: {
- fprintf(out_file_, "%g", data->GetDouble());
- break;
- }
- case DexFile::kDexAnnotationString: {
- dex_ir::StringId* string_id = data->GetStringId();
- if (options_.output_format_ == kOutputPlain) {
- DumpEscapedString(string_id->Data());
- } else {
- DumpXmlAttribute(string_id->Data());
- }
- break;
- }
- case DexFile::kDexAnnotationType: {
- dex_ir::TypeId* type_id = data->GetTypeId();
- fputs(type_id->GetStringId()->Data(), out_file_);
- break;
- }
- case DexFile::kDexAnnotationField:
- case DexFile::kDexAnnotationEnum: {
- dex_ir::FieldId* field_id = data->GetFieldId();
- fputs(field_id->Name()->Data(), out_file_);
- break;
- }
- case DexFile::kDexAnnotationMethod: {
- dex_ir::MethodId* method_id = data->GetMethodId();
- fputs(method_id->Name()->Data(), out_file_);
- break;
- }
- case DexFile::kDexAnnotationArray: {
- fputc('{', out_file_);
- // Display all elements.
- for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
- fputc(' ', out_file_);
- DumpEncodedValue(value.get());
- }
- fputs(" }", out_file_);
- break;
- }
- case DexFile::kDexAnnotationAnnotation: {
- DumpEncodedAnnotation(data->GetEncodedAnnotation());
- break;
- }
- case DexFile::kDexAnnotationNull:
- fputs("null", out_file_);
- break;
- case DexFile::kDexAnnotationBoolean:
- fputs(StrBool(data->GetBoolean()), out_file_);
- break;
- default:
- fputs("????", out_file_);
- break;
- } // switch
-}
-
-/*
- * Dumps the file header.
- */
-static void DumpFileHeader(dex_ir::Header* header) {
- char sanitized[8 * 2 + 1];
- dex_ir::Collections& collections = header->GetCollections();
- fprintf(out_file_, "DEX file header:\n");
- Asciify(sanitized, header->Magic(), 8);
- fprintf(out_file_, "magic : '%s'\n", sanitized);
- fprintf(out_file_, "checksum : %08x\n", header->Checksum());
- fprintf(out_file_, "signature : %02x%02x...%02x%02x\n",
- header->Signature()[0], header->Signature()[1],
- header->Signature()[DexFile::kSha1DigestSize - 2],
- header->Signature()[DexFile::kSha1DigestSize - 1]);
- fprintf(out_file_, "file_size : %d\n", header->FileSize());
- fprintf(out_file_, "header_size : %d\n", header->HeaderSize());
- fprintf(out_file_, "link_size : %d\n", header->LinkSize());
- fprintf(out_file_, "link_off : %d (0x%06x)\n",
- header->LinkOffset(), header->LinkOffset());
- fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
- fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
- collections.StringIdsOffset(), collections.StringIdsOffset());
- fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize());
- fprintf(out_file_, "type_ids_off : %d (0x%06x)\n",
- collections.TypeIdsOffset(), collections.TypeIdsOffset());
- fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize());
- fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n",
- collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
- fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize());
- fprintf(out_file_, "field_ids_off : %d (0x%06x)\n",
- collections.FieldIdsOffset(), collections.FieldIdsOffset());
- fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize());
- fprintf(out_file_, "method_ids_off : %d (0x%06x)\n",
- collections.MethodIdsOffset(), collections.MethodIdsOffset());
- fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
- fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
- collections.ClassDefsOffset(), collections.ClassDefsOffset());
- fprintf(out_file_, "data_size : %d\n", header->DataSize());
- fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
- header->DataOffset(), header->DataOffset());
-}
-
-/*
- * Dumps a class_def_item.
- */
-static void DumpClassDef(dex_ir::Header* header, int idx) {
- // General class information.
- dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
- fprintf(out_file_, "Class #%d header:\n", idx);
- fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
- fprintf(out_file_, "access_flags : %d (0x%04x)\n",
- class_def->GetAccessFlags(), class_def->GetAccessFlags());
- uint32_t superclass_idx = class_def->Superclass() == nullptr ?
- DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
- fprintf(out_file_, "superclass_idx : %d\n", superclass_idx);
- fprintf(out_file_, "interfaces_off : %d (0x%06x)\n",
- class_def->InterfacesOffset(), class_def->InterfacesOffset());
- uint32_t source_file_offset = 0xffffffffU;
- if (class_def->SourceFile() != nullptr) {
- source_file_offset = class_def->SourceFile()->GetIndex();
- }
- fprintf(out_file_, "source_file_idx : %d\n", source_file_offset);
- uint32_t annotations_offset = 0;
- if (class_def->Annotations() != nullptr) {
- annotations_offset = class_def->Annotations()->GetOffset();
- }
- fprintf(out_file_, "annotations_off : %d (0x%06x)\n",
- annotations_offset, annotations_offset);
- if (class_def->GetClassData() == nullptr) {
- fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0);
- } else {
- fprintf(out_file_, "class_data_off : %d (0x%06x)\n",
- class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
- }
-
- // Fields and methods.
- dex_ir::ClassData* class_data = class_def->GetClassData();
- if (class_data != nullptr && class_data->StaticFields() != nullptr) {
- fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size());
- } else {
- fprintf(out_file_, "static_fields_size : 0\n");
- }
- if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
- fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
- } else {
- fprintf(out_file_, "instance_fields_size: 0\n");
- }
- if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
- fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
- } else {
- fprintf(out_file_, "direct_methods_size : 0\n");
- }
- if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
- fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
- } else {
- fprintf(out_file_, "virtual_methods_size: 0\n");
- }
- fprintf(out_file_, "\n");
-}
-
-/**
- * Dumps an annotation set item.
- */
-static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
- if (set_item == nullptr || set_item->GetItems()->size() == 0) {
- fputs(" empty-annotation-set\n", out_file_);
- return;
- }
- for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
- if (annotation == nullptr) {
- continue;
- }
- fputs(" ", out_file_);
- switch (annotation->GetVisibility()) {
- case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break;
- case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
- case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break;
- default: fputs("VISIBILITY_UNKNOWN ", out_file_); break;
- } // switch
- DumpEncodedAnnotation(annotation->GetAnnotation());
- fputc('\n', out_file_);
- }
-}
-
-/*
- * Dumps class annotations.
- */
-static void DumpClassAnnotations(dex_ir::Header* header, int idx) {
- dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
- dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
- if (annotations_directory == nullptr) {
- return; // none
- }
-
- fprintf(out_file_, "Class #%d annotations:\n", idx);
-
- dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
- dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
- dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
- dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
-
- // Annotations on the class itself.
- if (class_set_item != nullptr) {
- fprintf(out_file_, "Annotations on class\n");
- DumpAnnotationSetItem(class_set_item);
- }
-
- // Annotations on fields.
- if (fields != nullptr) {
- for (auto& field : *fields) {
- const dex_ir::FieldId* field_id = field->GetFieldId();
- const uint32_t field_idx = field_id->GetIndex();
- const char* field_name = field_id->Name()->Data();
- fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
- DumpAnnotationSetItem(field->GetAnnotationSetItem());
- }
- }
-
- // Annotations on methods.
- if (methods != nullptr) {
- for (auto& method : *methods) {
- const dex_ir::MethodId* method_id = method->GetMethodId();
- const uint32_t method_idx = method_id->GetIndex();
- const char* method_name = method_id->Name()->Data();
- fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
- DumpAnnotationSetItem(method->GetAnnotationSetItem());
- }
- }
-
- // Annotations on method parameters.
- if (parameters != nullptr) {
- for (auto& parameter : *parameters) {
- const dex_ir::MethodId* method_id = parameter->GetMethodId();
- const uint32_t method_idx = method_id->GetIndex();
- const char* method_name = method_id->Name()->Data();
- fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
- uint32_t j = 0;
- for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
- fprintf(out_file_, "#%u\n", j);
- DumpAnnotationSetItem(annotation);
- ++j;
- }
- }
- }
-
- fputc('\n', out_file_);
-}
-
-/*
- * Dumps an interface that a class declares to implement.
- */
-static void DumpInterface(const dex_ir::TypeId* type_item, int i) {
- const char* interface_name = type_item->GetStringId()->Data();
- if (options_.output_format_ == kOutputPlain) {
- fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
- } else {
- std::string dot(DescriptorToDotWrapper(interface_name));
- fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
- }
-}
-
-/*
- * Dumps the catches table associated with the code.
- */
-static void DumpCatches(const dex_ir::CodeItem* code) {
- const uint16_t tries_size = code->TriesSize();
-
- // No catch table.
- if (tries_size == 0) {
- fprintf(out_file_, " catches : (none)\n");
- return;
- }
-
- // Dump all table entries.
- fprintf(out_file_, " catches : %d\n", tries_size);
- std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
- for (uint32_t i = 0; i < tries_size; i++) {
- const dex_ir::TryItem* try_item = (*tries)[i].get();
- const uint32_t start = try_item->StartAddr();
- const uint32_t end = start + try_item->InsnCount();
- fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end);
- for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
- const dex_ir::TypeId* type_id = handler->GetTypeId();
- const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
- fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress());
- } // for
- } // for
-}
-
-/*
- * Dumps all positions table entries associated with the code.
- */
-static void DumpPositionInfo(const dex_ir::CodeItem* code) {
- dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
- if (debug_info == nullptr) {
- return;
- }
- std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
- for (size_t i = 0; i < positions.size(); ++i) {
- fprintf(out_file_, " 0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
- }
-}
-
-/*
- * Dumps all locals table entries associated with the code.
- */
-static void DumpLocalInfo(const dex_ir::CodeItem* code) {
- dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
- if (debug_info == nullptr) {
- return;
- }
- std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
- for (size_t i = 0; i < locals.size(); ++i) {
- dex_ir::LocalInfo* entry = locals[i].get();
- fprintf(out_file_, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
- entry->start_address_, entry->end_address_, entry->reg_,
- entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
- }
-}
-
/*
* Helper for dumpInstruction(), which builds the string
* representation for the index in the given instruction.
@@ -723,11 +354,10 @@
static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
const Instruction* dec_insn,
size_t buf_size) {
- static const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max();
std::unique_ptr<char[]> buf(new char[buf_size]);
// Determine index and width of the string.
uint32_t index = 0;
- uint32_t secondary_index = kInvalidIndex;
+ uint32_t secondary_index = DexFile::kDexNoIndex;
uint32_t width = 4;
switch (Instruction::FormatOf(dec_insn->Opcode())) {
// SOME NOT SUPPORTED:
@@ -756,7 +386,6 @@
index = dec_insn->VRegB();
secondary_index = dec_insn->VRegH();
width = 4;
- break;
default:
break;
} // switch
@@ -821,9 +450,6 @@
case Instruction::kIndexFieldOffset:
outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
break;
- // SOME NOT SUPPORTED:
- // case Instruction::kIndexVaries:
- // case Instruction::kIndexInlineMethod:
case Instruction::kIndexMethodAndProtoRef: {
std::string method("<method?>");
std::string proto("<proto?>");
@@ -840,8 +466,11 @@
}
outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
method.c_str(), proto.c_str(), width, index, width, secondary_index);
- }
- break;
+ }
+ break;
+ // SOME NOT SUPPORTED:
+ // case Instruction::kIndexVaries:
+ // case Instruction::kIndexInlineMethod:
default:
outSize = snprintf(buf.get(), buf_size, "<?>");
break;
@@ -858,11 +487,365 @@
}
/*
+ * Dumps encoded annotation.
+ */
+void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
+ fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
+ // Display all name=value pairs.
+ for (auto& subannotation : *annotation->GetAnnotationElements()) {
+ fputc(' ', out_file_);
+ fputs(subannotation->GetName()->Data(), out_file_);
+ fputc('=', out_file_);
+ DumpEncodedValue(subannotation->GetValue());
+ }
+}
+/*
+ * Dumps encoded value.
+ */
+void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
+ switch (data->Type()) {
+ case DexFile::kDexAnnotationByte:
+ fprintf(out_file_, "%" PRId8, data->GetByte());
+ break;
+ case DexFile::kDexAnnotationShort:
+ fprintf(out_file_, "%" PRId16, data->GetShort());
+ break;
+ case DexFile::kDexAnnotationChar:
+ fprintf(out_file_, "%" PRIu16, data->GetChar());
+ break;
+ case DexFile::kDexAnnotationInt:
+ fprintf(out_file_, "%" PRId32, data->GetInt());
+ break;
+ case DexFile::kDexAnnotationLong:
+ fprintf(out_file_, "%" PRId64, data->GetLong());
+ break;
+ case DexFile::kDexAnnotationFloat: {
+ fprintf(out_file_, "%g", data->GetFloat());
+ break;
+ }
+ case DexFile::kDexAnnotationDouble: {
+ fprintf(out_file_, "%g", data->GetDouble());
+ break;
+ }
+ case DexFile::kDexAnnotationString: {
+ dex_ir::StringId* string_id = data->GetStringId();
+ if (options_.output_format_ == kOutputPlain) {
+ DumpEscapedString(string_id->Data(), out_file_);
+ } else {
+ DumpXmlAttribute(string_id->Data(), out_file_);
+ }
+ break;
+ }
+ case DexFile::kDexAnnotationType: {
+ dex_ir::TypeId* type_id = data->GetTypeId();
+ fputs(type_id->GetStringId()->Data(), out_file_);
+ break;
+ }
+ case DexFile::kDexAnnotationField:
+ case DexFile::kDexAnnotationEnum: {
+ dex_ir::FieldId* field_id = data->GetFieldId();
+ fputs(field_id->Name()->Data(), out_file_);
+ break;
+ }
+ case DexFile::kDexAnnotationMethod: {
+ dex_ir::MethodId* method_id = data->GetMethodId();
+ fputs(method_id->Name()->Data(), out_file_);
+ break;
+ }
+ case DexFile::kDexAnnotationArray: {
+ fputc('{', out_file_);
+ // Display all elements.
+ for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
+ fputc(' ', out_file_);
+ DumpEncodedValue(value.get());
+ }
+ fputs(" }", out_file_);
+ break;
+ }
+ case DexFile::kDexAnnotationAnnotation: {
+ DumpEncodedAnnotation(data->GetEncodedAnnotation());
+ break;
+ }
+ case DexFile::kDexAnnotationNull:
+ fputs("null", out_file_);
+ break;
+ case DexFile::kDexAnnotationBoolean:
+ fputs(StrBool(data->GetBoolean()), out_file_);
+ break;
+ default:
+ fputs("????", out_file_);
+ break;
+ } // switch
+}
+
+/*
+ * Dumps the file header.
+ */
+void DexLayout::DumpFileHeader() {
+ char sanitized[8 * 2 + 1];
+ dex_ir::Collections& collections = header_->GetCollections();
+ fprintf(out_file_, "DEX file header:\n");
+ Asciify(sanitized, header_->Magic(), 8);
+ fprintf(out_file_, "magic : '%s'\n", sanitized);
+ fprintf(out_file_, "checksum : %08x\n", header_->Checksum());
+ fprintf(out_file_, "signature : %02x%02x...%02x%02x\n",
+ header_->Signature()[0], header_->Signature()[1],
+ header_->Signature()[DexFile::kSha1DigestSize - 2],
+ header_->Signature()[DexFile::kSha1DigestSize - 1]);
+ fprintf(out_file_, "file_size : %d\n", header_->FileSize());
+ fprintf(out_file_, "header_size : %d\n", header_->HeaderSize());
+ fprintf(out_file_, "link_size : %d\n", header_->LinkSize());
+ fprintf(out_file_, "link_off : %d (0x%06x)\n",
+ header_->LinkOffset(), header_->LinkOffset());
+ fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
+ fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
+ collections.StringIdsOffset(), collections.StringIdsOffset());
+ fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize());
+ fprintf(out_file_, "type_ids_off : %d (0x%06x)\n",
+ collections.TypeIdsOffset(), collections.TypeIdsOffset());
+ fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize());
+ fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n",
+ collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
+ fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize());
+ fprintf(out_file_, "field_ids_off : %d (0x%06x)\n",
+ collections.FieldIdsOffset(), collections.FieldIdsOffset());
+ fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize());
+ fprintf(out_file_, "method_ids_off : %d (0x%06x)\n",
+ collections.MethodIdsOffset(), collections.MethodIdsOffset());
+ fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
+ fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
+ collections.ClassDefsOffset(), collections.ClassDefsOffset());
+ fprintf(out_file_, "data_size : %d\n", header_->DataSize());
+ fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
+ header_->DataOffset(), header_->DataOffset());
+}
+
+/*
+ * Dumps a class_def_item.
+ */
+void DexLayout::DumpClassDef(int idx) {
+ // General class information.
+ dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+ fprintf(out_file_, "Class #%d header:\n", idx);
+ fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
+ fprintf(out_file_, "access_flags : %d (0x%04x)\n",
+ class_def->GetAccessFlags(), class_def->GetAccessFlags());
+ uint32_t superclass_idx = class_def->Superclass() == nullptr ?
+ DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
+ fprintf(out_file_, "superclass_idx : %d\n", superclass_idx);
+ fprintf(out_file_, "interfaces_off : %d (0x%06x)\n",
+ class_def->InterfacesOffset(), class_def->InterfacesOffset());
+ uint32_t source_file_offset = 0xffffffffU;
+ if (class_def->SourceFile() != nullptr) {
+ source_file_offset = class_def->SourceFile()->GetIndex();
+ }
+ fprintf(out_file_, "source_file_idx : %d\n", source_file_offset);
+ uint32_t annotations_offset = 0;
+ if (class_def->Annotations() != nullptr) {
+ annotations_offset = class_def->Annotations()->GetOffset();
+ }
+ fprintf(out_file_, "annotations_off : %d (0x%06x)\n",
+ annotations_offset, annotations_offset);
+ if (class_def->GetClassData() == nullptr) {
+ fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0);
+ } else {
+ fprintf(out_file_, "class_data_off : %d (0x%06x)\n",
+ class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
+ }
+
+ // Fields and methods.
+ dex_ir::ClassData* class_data = class_def->GetClassData();
+ if (class_data != nullptr && class_data->StaticFields() != nullptr) {
+ fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size());
+ } else {
+ fprintf(out_file_, "static_fields_size : 0\n");
+ }
+ if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
+ fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
+ } else {
+ fprintf(out_file_, "instance_fields_size: 0\n");
+ }
+ if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
+ fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
+ } else {
+ fprintf(out_file_, "direct_methods_size : 0\n");
+ }
+ if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
+ fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
+ } else {
+ fprintf(out_file_, "virtual_methods_size: 0\n");
+ }
+ fprintf(out_file_, "\n");
+}
+
+/**
+ * Dumps an annotation set item.
+ */
+void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
+ if (set_item == nullptr || set_item->GetItems()->size() == 0) {
+ fputs(" empty-annotation-set\n", out_file_);
+ return;
+ }
+ for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
+ if (annotation == nullptr) {
+ continue;
+ }
+ fputs(" ", out_file_);
+ switch (annotation->GetVisibility()) {
+ case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break;
+ case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
+ case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break;
+ default: fputs("VISIBILITY_UNKNOWN ", out_file_); break;
+ } // switch
+ DumpEncodedAnnotation(annotation->GetAnnotation());
+ fputc('\n', out_file_);
+ }
+}
+
+/*
+ * Dumps class annotations.
+ */
+void DexLayout::DumpClassAnnotations(int idx) {
+ dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+ dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
+ if (annotations_directory == nullptr) {
+ return; // none
+ }
+
+ fprintf(out_file_, "Class #%d annotations:\n", idx);
+
+ dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
+ dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
+ dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
+ dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
+
+ // Annotations on the class itself.
+ if (class_set_item != nullptr) {
+ fprintf(out_file_, "Annotations on class\n");
+ DumpAnnotationSetItem(class_set_item);
+ }
+
+ // Annotations on fields.
+ if (fields != nullptr) {
+ for (auto& field : *fields) {
+ const dex_ir::FieldId* field_id = field->GetFieldId();
+ const uint32_t field_idx = field_id->GetIndex();
+ const char* field_name = field_id->Name()->Data();
+ fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
+ DumpAnnotationSetItem(field->GetAnnotationSetItem());
+ }
+ }
+
+ // Annotations on methods.
+ if (methods != nullptr) {
+ for (auto& method : *methods) {
+ const dex_ir::MethodId* method_id = method->GetMethodId();
+ const uint32_t method_idx = method_id->GetIndex();
+ const char* method_name = method_id->Name()->Data();
+ fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
+ DumpAnnotationSetItem(method->GetAnnotationSetItem());
+ }
+ }
+
+ // Annotations on method parameters.
+ if (parameters != nullptr) {
+ for (auto& parameter : *parameters) {
+ const dex_ir::MethodId* method_id = parameter->GetMethodId();
+ const uint32_t method_idx = method_id->GetIndex();
+ const char* method_name = method_id->Name()->Data();
+ fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
+ uint32_t j = 0;
+ for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
+ fprintf(out_file_, "#%u\n", j);
+ DumpAnnotationSetItem(annotation);
+ ++j;
+ }
+ }
+ }
+
+ fputc('\n', out_file_);
+}
+
+/*
+ * Dumps an interface that a class declares to implement.
+ */
+void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
+ const char* interface_name = type_item->GetStringId()->Data();
+ if (options_.output_format_ == kOutputPlain) {
+ fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
+ } else {
+ std::string dot(DescriptorToDotWrapper(interface_name));
+ fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
+ }
+}
+
+/*
+ * Dumps the catches table associated with the code.
+ */
+void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
+ const uint16_t tries_size = code->TriesSize();
+
+ // No catch table.
+ if (tries_size == 0) {
+ fprintf(out_file_, " catches : (none)\n");
+ return;
+ }
+
+ // Dump all table entries.
+ fprintf(out_file_, " catches : %d\n", tries_size);
+ std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
+ for (uint32_t i = 0; i < tries_size; i++) {
+ const dex_ir::TryItem* try_item = (*tries)[i].get();
+ const uint32_t start = try_item->StartAddr();
+ const uint32_t end = start + try_item->InsnCount();
+ fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end);
+ for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
+ const dex_ir::TypeId* type_id = handler->GetTypeId();
+ const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
+ fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress());
+ } // for
+ } // for
+}
+
+/*
+ * Dumps all positions table entries associated with the code.
+ */
+void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) {
+ dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
+ if (debug_info == nullptr) {
+ return;
+ }
+ std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
+ for (size_t i = 0; i < positions.size(); ++i) {
+ fprintf(out_file_, " 0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
+ }
+}
+
+/*
+ * Dumps all locals table entries associated with the code.
+ */
+void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) {
+ dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
+ if (debug_info == nullptr) {
+ return;
+ }
+ std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
+ for (size_t i = 0; i < locals.size(); ++i) {
+ dex_ir::LocalInfo* entry = locals[i].get();
+ fprintf(out_file_, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
+ entry->start_address_, entry->end_address_, entry->reg_,
+ entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
+ }
+}
+
+/*
* Dumps a single instruction.
*/
-static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code,
- uint32_t code_offset, uint32_t insn_idx, uint32_t insn_width,
- const Instruction* dec_insn) {
+void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
+ uint32_t code_offset,
+ uint32_t insn_idx,
+ uint32_t insn_width,
+ const Instruction* dec_insn) {
// Address of instruction (expressed as byte offset).
fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
@@ -901,7 +884,7 @@
// Set up additional argument.
std::unique_ptr<char[]> index_buf;
if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
- index_buf = IndexString(header, dec_insn, 200);
+ index_buf = IndexString(header_, dec_insn, 200);
}
// Dump the instruction.
@@ -1073,9 +1056,8 @@
/*
* Dumps a bytecode disassembly.
*/
-static void DumpBytecodes(dex_ir::Header* header, uint32_t idx,
- const dex_ir::CodeItem* code, uint32_t code_offset) {
- dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
+void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
+ dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
const char* name = method_id->Name()->Data();
std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1094,7 +1076,7 @@
fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
break;
}
- DumpInstruction(header, code, code_offset, insn_idx, insn_width, instruction);
+ DumpInstruction(code, code_offset, insn_idx, insn_width, instruction);
insn_idx += insn_width;
} // for
}
@@ -1102,8 +1084,7 @@
/*
* Dumps code of a method.
*/
-static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeItem* code,
- uint32_t code_offset) {
+void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
fprintf(out_file_, " registers : %d\n", code->RegistersSize());
fprintf(out_file_, " ins : %d\n", code->InsSize());
fprintf(out_file_, " outs : %d\n", code->OutsSize());
@@ -1112,7 +1093,7 @@
// Bytecode disassembly, if requested.
if (options_.disassemble_) {
- DumpBytecodes(header, idx, code, code_offset);
+ DumpBytecodes(idx, code, code_offset);
}
// Try-catch blocks.
@@ -1128,14 +1109,13 @@
/*
* Dumps a method.
*/
-static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags,
- const dex_ir::CodeItem* code, int i) {
+void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) {
// Bail for anything private if export only requested.
if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
return;
}
- dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
+ dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
const char* name = method_id->Name()->Data();
char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1150,7 +1130,7 @@
fprintf(out_file_, " code : (none)\n");
} else {
fprintf(out_file_, " code -\n");
- DumpCode(header, idx, code, code->GetOffset());
+ DumpCode(idx, code, code->GetOffset());
}
if (options_.disassemble_) {
fputc('\n', out_file_);
@@ -1233,14 +1213,13 @@
/*
* Dumps a static (class) field.
*/
-static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags,
- int i, dex_ir::EncodedValue* init) {
+void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) {
// Bail for anything private if export only requested.
if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
return;
}
- dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx);
+ dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
const char* name = field_id->Name()->Data();
const char* type_descriptor = field_id->Type()->GetStringId()->Data();
const char* back_descriptor = field_id->Class()->GetStringId()->Data();
@@ -1281,8 +1260,8 @@
/*
* Dumps an instance field.
*/
-static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int i) {
- DumpSField(header, idx, flags, i, nullptr);
+void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) {
+ DumpSField(idx, flags, i, nullptr);
}
/*
@@ -1293,19 +1272,19 @@
* If "*last_package" is nullptr or does not match the current class' package,
* the value will be replaced with a newly-allocated string.
*/
-static void DumpClass(dex_ir::Header* header, int idx, char** last_package) {
- dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
+void DexLayout::DumpClass(int idx, char** last_package) {
+ dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
// Omitting non-public class.
if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
return;
}
if (options_.show_section_headers_) {
- DumpClassDef(header, idx);
+ DumpClassDef(idx);
}
if (options_.show_annotations_) {
- DumpClassAnnotations(header, idx);
+ DumpClassAnnotations(idx);
}
// For the XML output, show the package name. Ideally we'd gather
@@ -1313,7 +1292,7 @@
// package name wouldn't jump around, but that's not a great plan
// for something that needs to run on the device.
const char* class_descriptor =
- header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
+ header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
if (!(class_descriptor[0] == 'L' &&
class_descriptor[strlen(class_descriptor)-1] == ';')) {
// Arrays and primitives should not be defined explicitly. Keep going?
@@ -1406,8 +1385,7 @@
dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
if (static_fields != nullptr) {
for (uint32_t i = 0; i < static_fields->size(); i++) {
- DumpSField(header,
- (*static_fields)[i]->GetFieldId()->GetIndex(),
+ DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(),
(*static_fields)[i]->GetAccessFlags(),
i,
i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
@@ -1423,8 +1401,7 @@
dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
if (instance_fields != nullptr) {
for (uint32_t i = 0; i < instance_fields->size(); i++) {
- DumpIField(header,
- (*instance_fields)[i]->GetFieldId()->GetIndex(),
+ DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(),
(*instance_fields)[i]->GetAccessFlags(),
i);
} // for
@@ -1439,8 +1416,7 @@
dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
if (direct_methods != nullptr) {
for (uint32_t i = 0; i < direct_methods->size(); i++) {
- DumpMethod(header,
- (*direct_methods)[i]->GetMethodId()->GetIndex(),
+ DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(),
(*direct_methods)[i]->GetAccessFlags(),
(*direct_methods)[i]->GetCodeItem(),
i);
@@ -1456,8 +1432,7 @@
dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
if (virtual_methods != nullptr) {
for (uint32_t i = 0; i < virtual_methods->size(); i++) {
- DumpMethod(header,
- (*virtual_methods)[i]->GetMethodId()->GetIndex(),
+ DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(),
(*virtual_methods)[i]->GetAccessFlags(),
(*virtual_methods)[i]->GetCodeItem(),
i);
@@ -1481,24 +1456,10 @@
free(access_str);
}
-/*
- * Dumps the requested sections of the file.
- */
-static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) {
- if (options_.verbose_) {
- fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
- file_name, dex_file->GetHeader().magic_ + 4);
- }
- std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
-
- if (options_.visualize_pattern_) {
- VisualizeDexLayout(header.get(), dex_file, dex_file_index);
- return;
- }
-
+void DexLayout::DumpDexFile() {
// Headers.
if (options_.show_file_headers_) {
- DumpFileHeader(header.get());
+ DumpFileHeader();
}
// Open XML context.
@@ -1508,9 +1469,9 @@
// Iterate over all classes.
char* package = nullptr;
- const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
+ const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
for (uint32_t i = 0; i < class_defs_size; i++) {
- DumpClass(header.get(), i, &package);
+ DumpClass(i, &package);
} // for
// Free the last package allocated.
@@ -1523,20 +1484,227 @@
if (options_.output_format_ == kOutputXml) {
fprintf(out_file_, "</api>\n");
}
+}
- // Output dex file.
- if (options_.output_dex_directory_ != nullptr) {
+std::vector<dex_ir::ClassDef*> DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
+ std::vector<dex_ir::ClassDef*> new_class_def_order;
+ for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+ dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
+ if (info_->ContainsClass(*dex_file, type_idx)) {
+ new_class_def_order.push_back(class_def.get());
+ }
+ }
+ for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+ dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
+ if (!info_->ContainsClass(*dex_file, type_idx)) {
+ new_class_def_order.push_back(class_def.get());
+ }
+ }
+ uint32_t class_defs_offset = header_->GetCollections().ClassDefsOffset();
+ uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
+ for (uint32_t i = 0; i < new_class_def_order.size(); ++i) {
+ dex_ir::ClassDef* class_def = new_class_def_order[i];
+ class_def->SetIndex(i);
+ class_def->SetOffset(class_defs_offset);
+ class_defs_offset += dex_ir::ClassDef::ItemSize();
+ if (class_def->GetClassData() != nullptr) {
+ class_def->GetClassData()->SetOffset(class_data_offset);
+ class_data_offset += class_def->GetClassData()->GetSize();
+ }
+ }
+ return new_class_def_order;
+}
+
+int32_t DexLayout::LayoutCodeItems(std::vector<dex_ir::ClassDef*> new_class_def_order) {
+ int32_t diff = 0;
+ uint32_t offset = header_->GetCollections().CodeItemsOffset();
+ for (dex_ir::ClassDef* class_def : new_class_def_order) {
+ dex_ir::ClassData* class_data = class_def->GetClassData();
+ if (class_data != nullptr) {
+ class_data->SetOffset(class_data->GetOffset() + diff);
+ for (auto& method : *class_data->DirectMethods()) {
+ dex_ir::CodeItem* code_item = method->GetCodeItem();
+ if (code_item != nullptr) {
+ diff += UnsignedLeb128Size(offset) - UnsignedLeb128Size(code_item->GetOffset());
+ code_item->SetOffset(offset);
+ offset += RoundUp(code_item->GetSize(), 4);
+ }
+ }
+ for (auto& method : *class_data->VirtualMethods()) {
+ dex_ir::CodeItem* code_item = method->GetCodeItem();
+ if (code_item != nullptr) {
+ diff += UnsignedLeb128Size(offset) - UnsignedLeb128Size(code_item->GetOffset());
+ code_item->SetOffset(offset);
+ offset += RoundUp(code_item->GetSize(), 4);
+ }
+ }
+ }
+ }
+
+ return diff;
+}
+
+// Adjust offsets of every item in the specified section by diff bytes.
+template<class T> void DexLayout::FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map,
+ uint32_t diff) {
+ for (auto& pair : map) {
+ std::unique_ptr<T>& item = pair.second;
+ item->SetOffset(item->GetOffset() + diff);
+ }
+}
+
+// Adjust offsets of all sections with an address after the specified offset by diff bytes.
+void DexLayout::FixupSections(uint32_t offset, uint32_t diff) {
+ dex_ir::Collections& collections = header_->GetCollections();
+ uint32_t map_list_offset = collections.MapListOffset();
+ if (map_list_offset > offset) {
+ collections.SetMapListOffset(map_list_offset + diff);
+ }
+
+ uint32_t type_lists_offset = collections.TypeListsOffset();
+ if (type_lists_offset > offset) {
+ collections.SetTypeListsOffset(type_lists_offset + diff);
+ FixupSection(collections.TypeLists(), diff);
+ }
+
+ uint32_t annotation_set_ref_lists_offset = collections.AnnotationSetRefListsOffset();
+ if (annotation_set_ref_lists_offset > offset) {
+ collections.SetAnnotationSetRefListsOffset(annotation_set_ref_lists_offset + diff);
+ FixupSection(collections.AnnotationSetRefLists(), diff);
+ }
+
+ uint32_t annotation_set_items_offset = collections.AnnotationSetItemsOffset();
+ if (annotation_set_items_offset > offset) {
+ collections.SetAnnotationSetItemsOffset(annotation_set_items_offset + diff);
+ FixupSection(collections.AnnotationSetItems(), diff);
+ }
+
+ uint32_t class_datas_offset = collections.ClassDatasOffset();
+ if (class_datas_offset > offset) {
+ collections.SetClassDatasOffset(class_datas_offset + diff);
+ FixupSection(collections.ClassDatas(), diff);
+ }
+
+ uint32_t code_items_offset = collections.CodeItemsOffset();
+ if (code_items_offset > offset) {
+ collections.SetCodeItemsOffset(code_items_offset + diff);
+ FixupSection(collections.CodeItems(), diff);
+ }
+
+ uint32_t string_datas_offset = collections.StringDatasOffset();
+ if (string_datas_offset > offset) {
+ collections.SetStringDatasOffset(string_datas_offset + diff);
+ FixupSection(collections.StringDatas(), diff);
+ }
+
+ uint32_t debug_info_items_offset = collections.DebugInfoItemsOffset();
+ if (debug_info_items_offset > offset) {
+ collections.SetDebugInfoItemsOffset(debug_info_items_offset + diff);
+ FixupSection(collections.DebugInfoItems(), diff);
+ }
+
+ uint32_t annotation_items_offset = collections.AnnotationItemsOffset();
+ if (annotation_items_offset > offset) {
+ collections.SetAnnotationItemsOffset(annotation_items_offset + diff);
+ FixupSection(collections.AnnotationItems(), diff);
+ }
+
+ uint32_t encoded_array_items_offset = collections.EncodedArrayItemsOffset();
+ if (encoded_array_items_offset > offset) {
+ collections.SetEncodedArrayItemsOffset(encoded_array_items_offset + diff);
+ FixupSection(collections.EncodedArrayItems(), diff);
+ }
+
+ uint32_t annotations_directory_items_offset = collections.AnnotationsDirectoryItemsOffset();
+ if (annotations_directory_items_offset > offset) {
+ collections.SetAnnotationsDirectoryItemsOffset(annotations_directory_items_offset + diff);
+ FixupSection(collections.AnnotationsDirectoryItems(), diff);
+ }
+}
+
+void DexLayout::LayoutOutputFile(const DexFile* dex_file) {
+ std::vector<dex_ir::ClassDef*> new_class_def_order = LayoutClassDefsAndClassData(dex_file);
+ int32_t diff = LayoutCodeItems(new_class_def_order);
+ // Adjust diff to be 4-byte aligned.
+ diff = RoundUp(diff, 4);
+ // Move sections after ClassData by diff bytes.
+ FixupSections(header_->GetCollections().ClassDatasOffset(), diff);
+ // Update file size.
+ header_->SetFileSize(header_->FileSize() + diff);
+}
+
+void DexLayout::OutputDexFile(const std::string& dex_file_location) {
+ std::string error_msg;
+ std::unique_ptr<File> new_file;
+ if (!options_.output_to_memmap_) {
std::string output_location(options_.output_dex_directory_);
- size_t last_slash = dex_file->GetLocation().rfind('/');
- output_location.append(dex_file->GetLocation().substr(last_slash));
- DexWriter::OutputDexFile(*header, output_location.c_str());
+ size_t last_slash = dex_file_location.rfind("/");
+ std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
+ if (output_location == dex_file_directory) {
+ output_location = dex_file_location + ".new";
+ } else if (last_slash != std::string::npos) {
+ output_location += dex_file_location.substr(last_slash);
+ } else {
+ output_location += "/" + dex_file_location + ".new";
+ }
+ new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
+ ftruncate(new_file->Fd(), header_->FileSize());
+ mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED,
+ new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
+ } else {
+ mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(),
+ PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
+ }
+ if (mem_map_ == nullptr) {
+ LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
+ if (new_file.get() != nullptr) {
+ new_file->Erase();
+ }
+ return;
+ }
+ DexWriter::Output(header_, mem_map_.get());
+ if (new_file != nullptr) {
+ UNUSED(new_file->FlushCloseOrErase());
+ }
+}
+
+/*
+ * Dumps the requested sections of the file.
+ */
+void DexLayout::ProcessDexFile(const char* file_name,
+ const DexFile* dex_file,
+ size_t dex_file_index) {
+ std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
+ SetHeader(header.get());
+
+ if (options_.verbose_) {
+ fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
+ file_name, dex_file->GetHeader().magic_ + 4);
+ }
+
+ if (options_.visualize_pattern_) {
+ VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
+ return;
+ }
+
+ // Dump dex file.
+ if (options_.dump_) {
+ DumpDexFile();
+ }
+
+ // Output dex file as file or memmap.
+ if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) {
+ if (info_ != nullptr) {
+ LayoutOutputFile(dex_file);
+ }
+ OutputDexFile(dex_file->GetLocation());
}
}
/*
* Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
*/
-int ProcessFile(const char* file_name) {
+int DexLayout::ProcessFile(const char* file_name) {
if (options_.verbose_) {
fprintf(out_file_, "Processing '%s'...\n", file_name);
}
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index a5bd992..ac1a4a6 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -26,8 +26,13 @@
#include <stdint.h>
#include <stdio.h>
+#include "dex_ir.h"
+#include "mem_map.h"
+
namespace art {
+class DexFile;
+class Instruction;
class ProfileCompilationInfo;
/* Supported output formats. */
@@ -37,28 +42,90 @@
};
/* Command-line options. */
-struct Options {
- bool build_dex_ir_;
- bool checksum_only_;
- bool disassemble_;
- bool exports_only_;
- bool ignore_bad_checksum_;
- bool show_annotations_;
- bool show_file_headers_;
- bool show_section_headers_;
- bool verbose_;
- bool visualize_pattern_;
- OutputFormat output_format_;
- const char* output_dex_directory_;
- const char* output_file_name_;
- const char* profile_file_name_;
+class Options {
+ public:
+ Options() = default;
+
+ bool dump_ = false;
+ bool build_dex_ir_ = false;
+ bool checksum_only_ = false;
+ bool disassemble_ = false;
+ bool exports_only_ = false;
+ bool ignore_bad_checksum_ = false;
+ bool output_to_memmap_ = false;
+ bool show_annotations_ = false;
+ bool show_file_headers_ = false;
+ bool show_section_headers_ = false;
+ bool verbose_ = false;
+ bool visualize_pattern_ = false;
+ OutputFormat output_format_ = kOutputPlain;
+ const char* output_dex_directory_ = nullptr;
+ const char* output_file_name_ = nullptr;
+ const char* profile_file_name_ = nullptr;
};
-/* Prototypes. */
-extern struct Options options_;
-extern FILE* out_file_;
-extern ProfileCompilationInfo* profile_info_;
-int ProcessFile(const char* file_name);
+class DexLayout {
+ public:
+ DexLayout(Options& options,
+ ProfileCompilationInfo* info,
+ FILE* out_file,
+ dex_ir::Header*
+ header = nullptr)
+ : options_(options), info_(info), out_file_(out_file), header_(header) { }
+
+ int ProcessFile(const char* file_name);
+ void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index);
+
+ dex_ir::Header* GetHeader() const { return header_; }
+ void SetHeader(dex_ir::Header* header) { header_ = header; }
+
+ MemMap* GetAndReleaseMemMap() { return mem_map_.release(); }
+
+ private:
+ void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item);
+ void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
+ void DumpCatches(const dex_ir::CodeItem* code);
+ void DumpClass(int idx, char** last_package);
+ void DumpClassAnnotations(int idx);
+ void DumpClassDef(int idx);
+ void DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
+ void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation);
+ void DumpEncodedValue(const dex_ir::EncodedValue* data);
+ void DumpFileHeader();
+ void DumpIField(uint32_t idx, uint32_t flags, int i);
+ void DumpInstruction(const dex_ir::CodeItem* code,
+ uint32_t code_offset,
+ uint32_t insn_idx,
+ uint32_t insn_width,
+ const Instruction* dec_insn);
+ void DumpInterface(const dex_ir::TypeId* type_item, int i);
+ void DumpLocalInfo(const dex_ir::CodeItem* code);
+ void DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i);
+ void DumpPositionInfo(const dex_ir::CodeItem* code);
+ void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init);
+ void DumpDexFile();
+
+ std::vector<dex_ir::ClassDef*> LayoutClassDefsAndClassData(const DexFile* dex_file);
+ int32_t LayoutCodeItems(std::vector<dex_ir::ClassDef*> new_class_def_order);
+ template<class T> void FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map, uint32_t diff);
+ void FixupSections(uint32_t offset, uint32_t diff);
+
+ // Creates a new layout for the dex file based on profile info.
+ // Currently reorders ClassDefs, ClassDataItems, and CodeItems.
+ void LayoutOutputFile(const DexFile* dex_file);
+ void OutputDexFile(const std::string& dex_file_location);
+
+ void DumpCFG(const DexFile* dex_file, int idx);
+ void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code);
+
+ Options& options_;
+ ProfileCompilationInfo* info_;
+ FILE* out_file_;
+ dex_ir::Header* header_;
+ std::unique_ptr<MemMap> mem_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(DexLayout);
+};
} // namespace art
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 825dd50..5f8a118 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -68,64 +68,67 @@
InitLogging(argv, Runtime::Aborter);
MemMap::Init();
- // Reset options.
+ Options options;
+ options.dump_ = true;
+ options.verbose_ = true;
bool want_usage = false;
- memset(&options_, 0, sizeof(options_));
- options_.verbose_ = true;
// Parse all arguments.
while (1) {
- const int ic = getopt(argc, argv, "abcdefghil:o:p:sw:");
+ const int ic = getopt(argc, argv, "abcdefghil:mo:p:sw:");
if (ic < 0) {
break; // done
}
switch (ic) {
case 'a': // display annotations
- options_.show_annotations_ = true;
+ options.show_annotations_ = true;
break;
case 'b': // build dex_ir
- options_.build_dex_ir_ = true;
+ options.build_dex_ir_ = true;
break;
case 'c': // verify the checksum then exit
- options_.checksum_only_ = true;
+ options.checksum_only_ = true;
break;
case 'd': // disassemble Dalvik instructions
- options_.disassemble_ = true;
+ options.disassemble_ = true;
break;
case 'e': // exported items only
- options_.exports_only_ = true;
+ options.exports_only_ = true;
break;
case 'f': // display outer file header
- options_.show_file_headers_ = true;
+ options.show_file_headers_ = true;
break;
case 'h': // display section headers, i.e. all meta-data
- options_.show_section_headers_ = true;
+ options.show_section_headers_ = true;
break;
case 'i': // continue even if checksum is bad
- options_.ignore_bad_checksum_ = true;
+ options.ignore_bad_checksum_ = true;
break;
case 'l': // layout
if (strcmp(optarg, "plain") == 0) {
- options_.output_format_ = kOutputPlain;
+ options.output_format_ = kOutputPlain;
} else if (strcmp(optarg, "xml") == 0) {
- options_.output_format_ = kOutputXml;
- options_.verbose_ = false;
+ options.output_format_ = kOutputXml;
+ options.verbose_ = false;
} else {
want_usage = true;
}
break;
+ case 'm': // output dex files to a memmap
+ options.output_to_memmap_ = true;
+ break;
case 'o': // output file
- options_.output_file_name_ = optarg;
+ options.output_file_name_ = optarg;
break;
case 'p': // profile file
- options_.profile_file_name_ = optarg;
+ options.profile_file_name_ = optarg;
break;
case 's': // visualize access pattern
- options_.visualize_pattern_ = true;
- options_.verbose_ = false;
+ options.visualize_pattern_ = true;
+ options.verbose_ = false;
break;
case 'w': // output dex files directory
- options_.output_dex_directory_ = optarg;
+ options.output_dex_directory_ = optarg;
break;
default:
want_usage = true;
@@ -138,7 +141,7 @@
fprintf(stderr, "%s: no file specified\n", kProgramName);
want_usage = true;
}
- if (options_.checksum_only_ && options_.ignore_bad_checksum_) {
+ if (options.checksum_only_ && options.ignore_bad_checksum_) {
fprintf(stderr, "Can't specify both -c and -i\n");
want_usage = true;
}
@@ -148,32 +151,37 @@
}
// Open alternative output file.
- if (options_.output_file_name_) {
- out_file_ = fopen(options_.output_file_name_, "w");
- if (!out_file_) {
- fprintf(stderr, "Can't open %s\n", options_.output_file_name_);
+ FILE* out_file = stdout;
+ if (options.output_file_name_) {
+ out_file = fopen(options.output_file_name_, "w");
+ if (!out_file) {
+ fprintf(stderr, "Can't open %s\n", options.output_file_name_);
return 1;
}
}
// Open profile file.
- if (options_.profile_file_name_) {
- int profile_fd = open(options_.profile_file_name_, O_RDONLY);
+ ProfileCompilationInfo* profile_info = nullptr;
+ if (options.profile_file_name_) {
+ int profile_fd = open(options.profile_file_name_, O_RDONLY);
if (profile_fd < 0) {
- fprintf(stderr, "Can't open %s\n", options_.profile_file_name_);
+ fprintf(stderr, "Can't open %s\n", options.profile_file_name_);
return 1;
}
- profile_info_ = new ProfileCompilationInfo();
- if (!profile_info_->Load(profile_fd)) {
- fprintf(stderr, "Can't read profile info from %s\n", options_.profile_file_name_);
+ profile_info = new ProfileCompilationInfo();
+ if (!profile_info->Load(profile_fd)) {
+ fprintf(stderr, "Can't read profile info from %s\n", options.profile_file_name_);
return 1;
}
}
+ // Create DexLayout instance.
+ DexLayout dex_layout(options, profile_info, out_file);
+
// Process all files supplied on command line.
int result = 0;
while (optind < argc) {
- result |= ProcessFile(argv[optind++]);
+ result |= dex_layout.ProcessFile(argv[optind++]);
} // while
return result != 0;
}
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index c7f36be..665baa6 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -22,11 +22,57 @@
#include <unistd.h>
#include "base/stringprintf.h"
+#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
#include "utils.h"
namespace art {
+static const char kDexFileLayoutInputDex[] =
+ "ZGV4CjAzNQD1KW3+B8NAB0f2A/ZVIBJ0aHrGIqcpVTAUAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAH"
+ "AAAAcAAAAAQAAACMAAAAAQAAAJwAAAAAAAAAAAAAAAMAAACoAAAAAgAAAMAAAAAUAQAAAAEAADAB"
+ "AAA4AQAAQAEAAEgBAABNAQAAUgEAAGYBAAADAAAABAAAAAUAAAAGAAAABgAAAAMAAAAAAAAAAAAA"
+ "AAAAAAABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAEAAAAAAAAAdQEAAAAAAAABAAAA"
+ "AAAAAAIAAAAAAAAAAgAAAAAAAAB/AQAAAAAAAAEAAQABAAAAaQEAAAQAAABwEAIAAAAOAAEAAQAB"
+ "AAAAbwEAAAQAAABwEAIAAAAOAAY8aW5pdD4ABkEuamF2YQAGQi5qYXZhAANMQTsAA0xCOwASTGph"
+ "dmEvbGFuZy9PYmplY3Q7AAFWAAQABw48AAQABw48AAAAAQAAgIAEgAIAAAEAAYCABJgCAAAACwAA"
+ "AAAAAAABAAAAAAAAAAEAAAAHAAAAcAAAAAIAAAAEAAAAjAAAAAMAAAABAAAAnAAAAAUAAAADAAAA"
+ "qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC"
+ "AAAAdQEAAAAQAAABAAAAjAEAAA==";
+
+static const char kDexFileLayoutInputProfile[] =
+ "cHJvADAwMgABAAsAAAABAPUpbf5jbGFzc2VzLmRleAEA";
+
+static const char kDexFileLayoutExpectedOutputDex[] =
+ "ZGV4CjAzNQD1KW3+B8NAB0f2A/ZVIBJ0aHrGIqcpVTAUAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAH"
+ "AAAAcAAAAAQAAACMAAAAAQAAAJwAAAAAAAAAAAAAAAMAAACoAAAAAgAAAMAAAAAUAQAAAAEAADAB"
+ "AAA4AQAAQAEAAEgBAABNAQAAUgEAAGYBAAADAAAABAAAAAUAAAAGAAAABgAAAAMAAAAAAAAAAAAA"
+ "AAAAAAABAAAAAAAAAAIAAAAAAAAAAQAAAAAAAAACAAAAAAAAAAIAAAAAAAAAdQEAAAAAAAAAAAAA"
+ "AAAAAAIAAAAAAAAAAQAAAAAAAAB/AQAAAAAAAAEAAQABAAAAbwEAAAQAAABwEAIAAAAOAAEAAQAB"
+ "AAAAaQEAAAQAAABwEAIAAAAOAAY8aW5pdD4ABkEuamF2YQAGQi5qYXZhAANMQTsAA0xCOwASTGph"
+ "dmEvbGFuZy9PYmplY3Q7AAFWAAQABw48AAQABw48AAAAAQABgIAEgAIAAAEAAICABJgCAAAACwAA"
+ "AAAAAAABAAAAAAAAAAEAAAAHAAAAcAAAAAIAAAAEAAAAjAAAAAMAAAABAAAAnAAAAAUAAAADAAAA"
+ "qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC"
+ "AAAAdQEAAAAQAAABAAAAjAEAAA==";
+
+static void WriteFileBase64(const char* base64, const char* location) {
+ // Decode base64.
+ CHECK(base64 != nullptr);
+ size_t length;
+ std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
+ CHECK(bytes.get() != nullptr);
+
+ // Write to provided file.
+ std::unique_ptr<File> file(OS::CreateEmptyFile(location));
+ CHECK(file.get() != nullptr);
+ if (!file->WriteFully(bytes.get(), length)) {
+ PLOG(FATAL) << "Failed to write base64 as file";
+ }
+ if (file->FlushCloseOrErase() != 0) {
+ PLOG(FATAL) << "Could not flush and close test file.";
+ }
+}
+
class DexLayoutTest : public CommonRuntimeTest {
protected:
virtual void SetUp() {
@@ -51,7 +97,6 @@
{ dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file };
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file };
-
if (!::art::Exec(dexdump_exec_argv, error_msg)) {
return false;
}
@@ -78,13 +123,11 @@
for (const std::string &dex_file : GetLibCoreDexFileNames()) {
std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-d", "-f", "-h", "-l", "plain", "-w", tmp_dir, "-o", tmp_name, dex_file };
-
+ { dexlayout, "-w", tmp_dir, "-o", tmp_name, dex_file };
if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
return false;
}
-
- size_t dex_file_last_slash = dex_file.rfind('/');
+ size_t dex_file_last_slash = dex_file.rfind("/");
std::string dex_file_name = dex_file.substr(dex_file_last_slash + 1);
std::vector<std::string> unzip_exec_argv =
{ "/usr/bin/unzip", dex_file, "classes.dex", "-d", tmp_dir};
@@ -105,7 +148,44 @@
return false;
}
}
+ return true;
+ }
+ // Runs DexFileOutput test.
+ bool DexFileLayoutExec(std::string* error_msg) {
+ ScratchFile tmp_file;
+ std::string tmp_name = tmp_file.GetFilename();
+ size_t tmp_last_slash = tmp_name.rfind("/");
+ std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
+
+ // Write inputs and expected outputs.
+ std::string dex_file = tmp_dir + "classes.dex";
+ WriteFileBase64(kDexFileLayoutInputDex, dex_file.c_str());
+ std::string profile_file = tmp_dir + "primary.prof";
+ WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
+ std::string expected_output = tmp_dir + "expected.dex";
+ WriteFileBase64(kDexFileLayoutExpectedOutputDex, expected_output.c_str());
+ std::string output_dex = tmp_dir + "classes.dex.new";
+
+ std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
+ EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
+
+ std::vector<std::string> dexlayout_exec_argv =
+ { dexlayout, "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
+ if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+ return false;
+ }
+ std::vector<std::string> diff_exec_argv =
+ { "/usr/bin/diff", expected_output, output_dex };
+ if (!::art::Exec(diff_exec_argv, error_msg)) {
+ return false;
+ }
+
+ std::vector<std::string> rm_exec_argv =
+ { "/bin/rm", dex_file, profile_file, expected_output, output_dex };
+ if (!::art::Exec(rm_exec_argv, error_msg)) {
+ return false;
+ }
return true;
}
};
@@ -125,4 +205,11 @@
ASSERT_TRUE(DexFileOutputExec(&error_msg)) << error_msg;
}
+TEST_F(DexLayoutTest, DexFileLayout) {
+ // Disable test on target.
+ TEST_DISABLED_FOR_TARGET();
+ std::string error_msg;
+ ASSERT_TRUE(DexFileLayoutExec(&error_msg)) << error_msg;
+}
+
} // namespace art
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 5d92298..e8ef69f 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -48,7 +48,7 @@
Mutex* Locks::modify_ldt_lock_ = nullptr;
MutatorMutex* Locks::mutator_lock_ = nullptr;
Mutex* Locks::profiler_lock_ = nullptr;
-Mutex* Locks::verifier_deps_lock_ = nullptr;
+ReaderWriterMutex* Locks::verifier_deps_lock_ = nullptr;
ReaderWriterMutex* Locks::oat_file_manager_lock_ = nullptr;
Mutex* Locks::host_dlopen_handles_lock_ = nullptr;
Mutex* Locks::reference_processor_lock_ = nullptr;
@@ -672,7 +672,7 @@
ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self));
++num_pending_readers_;
if (futex(state_.Address(), FUTEX_WAIT, cur_state, nullptr, nullptr, 0) != 0) {
- if (errno != EAGAIN) {
+ if (errno != EAGAIN && errno != EINTR) {
PLOG(FATAL) << "futex wait failed for " << name_;
}
}
@@ -796,7 +796,7 @@
reinterpret_cast<const timespec*>(std::numeric_limits<int32_t>::max()),
guard_.state_.Address(), cur_sequence) != -1;
if (!done) {
- if (errno != EAGAIN) {
+ if (errno != EAGAIN && errno != EINTR) {
PLOG(FATAL) << "futex cmp requeue failed for " << name_;
}
}
@@ -1039,7 +1039,7 @@
UPDATE_CURRENT_LOCK_LEVEL(kVerifierDepsLock);
DCHECK(verifier_deps_lock_ == nullptr);
- verifier_deps_lock_ = new Mutex("verifier deps lock", current_lock_level);
+ verifier_deps_lock_ = new ReaderWriterMutex("verifier deps lock", current_lock_level);
UPDATE_CURRENT_LOCK_LEVEL(kHostDlOpenHandlesLock);
DCHECK(host_dlopen_handles_lock_ == nullptr);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 74b786c..7e73e0d 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -658,8 +658,8 @@
// Guards opened oat files in OatFileManager.
static ReaderWriterMutex* oat_file_manager_lock_ ACQUIRED_AFTER(modify_ldt_lock_);
- // Guards verifier dependency collection in VerifierDeps.
- static Mutex* verifier_deps_lock_ ACQUIRED_AFTER(oat_file_manager_lock_);
+ // Guards extra string entries for VerifierDeps.
+ static ReaderWriterMutex* verifier_deps_lock_ ACQUIRED_AFTER(oat_file_manager_lock_);
// Guards dlopen_handles_ in DlOpenOatFile.
static Mutex* host_dlopen_handles_lock_ ACQUIRED_AFTER(verifier_deps_lock_);
diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h
index a53dcea..d5f375a 100644
--- a/runtime/base/stl_util.h
+++ b/runtime/base/stl_util.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_BASE_STL_UTIL_H_
#include <algorithm>
+#include <set>
#include <sstream>
#include "base/logging.h"
@@ -187,6 +188,12 @@
using type = T;
};
+// Merge `other` entries into `to_update`.
+template <typename T>
+static inline void MergeSets(std::set<T>& to_update, const std::set<T>& other) {
+ to_update.insert(other.begin(), other.end());
+}
+
} // namespace art
#endif // ART_RUNTIME_BASE_STL_UTIL_H_
diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc
index dc197c1..6e3e1d8 100644
--- a/runtime/compiler_filter.cc
+++ b/runtime/compiler_filter.cc
@@ -33,6 +33,7 @@
case CompilerFilter::kTime:
case CompilerFilter::kSpeedProfile:
case CompilerFilter::kSpeed:
+ case CompilerFilter::kLayoutProfile:
case CompilerFilter::kEverythingProfile:
case CompilerFilter::kEverything: return true;
}
@@ -52,6 +53,7 @@
case CompilerFilter::kTime:
case CompilerFilter::kSpeedProfile:
case CompilerFilter::kSpeed:
+ case CompilerFilter::kLayoutProfile:
case CompilerFilter::kEverythingProfile:
case CompilerFilter::kEverything: return true;
}
@@ -71,6 +73,7 @@
case CompilerFilter::kTime:
case CompilerFilter::kSpeedProfile:
case CompilerFilter::kSpeed:
+ case CompilerFilter::kLayoutProfile:
case CompilerFilter::kEverythingProfile:
case CompilerFilter::kEverything: return true;
}
@@ -97,6 +100,7 @@
case CompilerFilter::kVerifyProfile:
case CompilerFilter::kSpaceProfile:
case CompilerFilter::kSpeedProfile:
+ case CompilerFilter::kLayoutProfile:
case CompilerFilter::kEverythingProfile: return true;
}
UNREACHABLE();
@@ -121,6 +125,7 @@
return CompilerFilter::kSpace;
case CompilerFilter::kSpeedProfile:
+ case CompilerFilter::kLayoutProfile:
return CompilerFilter::kSpeed;
case CompilerFilter::kEverythingProfile:
@@ -146,6 +151,7 @@
case CompilerFilter::kTime: return "time";
case CompilerFilter::kSpeedProfile: return "speed-profile";
case CompilerFilter::kSpeed: return "speed";
+ case CompilerFilter::kLayoutProfile: return "layout-profile";
case CompilerFilter::kEverythingProfile: return "everything-profile";
case CompilerFilter::kEverything: return "everything";
}
@@ -173,6 +179,8 @@
*filter = kSpeed;
} else if (strcmp(option, "speed-profile") == 0) {
*filter = kSpeedProfile;
+ } else if (strcmp(option, "layout-profile") == 0) {
+ *filter = kLayoutProfile;
} else if (strcmp(option, "everything") == 0) {
*filter = kEverything;
} else if (strcmp(option, "everything-profile") == 0) {
diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h
index 37631cc..781d43a 100644
--- a/runtime/compiler_filter.h
+++ b/runtime/compiler_filter.h
@@ -39,6 +39,7 @@
kSpace, // Maximize space savings.
kBalanced, // Good performance return on compilation investment.
kSpeedProfile, // Maximize runtime performance based on profile.
+ kLayoutProfile, // Temporary filter for dexlayout. Will be merged with kSpeedProfile.
kSpeed, // Maximize runtime performance.
kEverythingProfile, // Compile everything capable of being compiled based on profile.
kEverything, // Compile everything capable of being compiled.
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 68e9f73..ed50711 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include <zlib.h>
+#include <limits>
#include <memory>
#include "base/stringprintf.h"
@@ -31,6 +32,16 @@
namespace art {
+static constexpr uint32_t kTypeIdLimit = std::numeric_limits<uint16_t>::max();
+
+static bool IsValidOrNoTypeId(uint16_t low, uint16_t high) {
+ return (high == 0) || ((high == 0xffffU) && (low == 0xffffU));
+}
+
+static bool IsValidTypeId(uint16_t low ATTRIBUTE_UNUSED, uint16_t high) {
+ return (high == 0);
+}
+
static uint32_t MapTypeToBitMask(uint32_t map_type) {
switch (map_type) {
case DexFile::kDexTypeHeaderItem: return 1 << 0;
@@ -579,7 +590,7 @@
(reinterpret_cast<const DexFile::MethodId*>(begin_ + header_->method_ids_off_) + idx)->
class_idx_;
if (class_type_index != my_class_index) {
- ErrorStringPrintf("Method's class index unexpected, %" PRIu16 "vs %" PRIu16,
+ ErrorStringPrintf("Method's class index unexpected, %" PRIu16 " vs %" PRIu16,
my_class_index.index_,
class_type_index.index_);
return false;
@@ -1790,6 +1801,12 @@
return false;
}
+ // Check that return type is representable as a uint16_t;
+ if (UNLIKELY(!IsValidOrNoTypeId(item->return_type_idx_.index_, item->pad_))) {
+ ErrorStringPrintf("proto with return type idx outside uint16_t range '%x:%x'",
+ item->pad_, item->return_type_idx_.index_);
+ return false;
+ }
// Check the return type and advance the shorty.
LOAD_STRING_BY_TYPE(return_type, item->return_type_idx_, "inter_proto_id_item return_type_idx")
if (!CheckShortyDescriptorMatch(*shorty, return_type, true)) {
@@ -1952,6 +1969,18 @@
bool DexFileVerifier::CheckInterClassDefItem() {
const DexFile::ClassDef* item = reinterpret_cast<const DexFile::ClassDef*>(ptr_);
+ // Check that class_idx_ is representable as a uint16_t;
+ if (UNLIKELY(!IsValidTypeId(item->class_idx_.index_, item->pad1_))) {
+ ErrorStringPrintf("class with type idx outside uint16_t range '%x:%x'", item->pad1_,
+ item->class_idx_.index_);
+ return false;
+ }
+ // Check that superclass_idx_ is representable as a uint16_t;
+ if (UNLIKELY(!IsValidOrNoTypeId(item->superclass_idx_.index_, item->pad2_))) {
+ ErrorStringPrintf("class with superclass type idx outside uint16_t range '%x:%x'", item->pad2_,
+ item->superclass_idx_.index_);
+ return false;
+ }
// Check for duplicate class def.
if (defined_classes_.find(item->class_idx_) != defined_classes_.end()) {
ErrorStringPrintf("Redefinition of class with type idx: '%d'", item->class_idx_.index_);
@@ -2320,6 +2349,14 @@
break;
}
case DexFile::kDexTypeClassDefItem: {
+ // There shouldn't be more class definitions than type ids allow.
+ // This check should be redundant, since there are checks that the
+ // class_idx_ is within range and that there is only one definition
+ // for a given type id.
+ if (i > kTypeIdLimit) {
+ ErrorStringPrintf("Too many class definition items");
+ return false;
+ }
if (!CheckInterClassDefItem()) {
return false;
}
@@ -2338,6 +2375,14 @@
break;
}
case DexFile::kDexTypeClassDataItem: {
+ // There shouldn't be more class data than type ids allow.
+ // This check should be redundant, since there are checks that the
+ // class_idx_ is within range and that there is only one definition
+ // for a given type id.
+ if (i > kTypeIdLimit) {
+ ErrorStringPrintf("Too many class data items");
+ return false;
+ }
if (!CheckInterClassDataItem()) {
return false;
}
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index b0463d7..1283660 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -94,8 +94,8 @@
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, opeer, jpeer, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, jpeer, stack_begin, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_begin, stack_size, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_size, stack_trace_sample, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_trace_sample, wait_next, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_size, deps_or_stack_trace_sample, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, deps_or_stack_trace_sample, wait_next, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, wait_next, monitor_enter_object, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, monitor_enter_object, top_handle_scope, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, top_handle_scope, class_loader_override, sizeof(void*));
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 719faed..f0ed237 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -269,10 +269,16 @@
return reinterpret_cast<const uint32_t*>(stack_map)[-1];
}
+static void FillRootTableLength(uint8_t* roots_data, uint32_t length) {
+ // Store the length of the table at the end. This will allow fetching it from a `stack_map`
+ // pointer.
+ reinterpret_cast<uint32_t*>(roots_data)[length] = length;
+}
+
static void FillRootTable(uint8_t* roots_data, Handle<mirror::ObjectArray<mirror::Object>> roots)
REQUIRES_SHARED(Locks::mutator_lock_) {
GcRoot<mirror::Object>* gc_roots = reinterpret_cast<GcRoot<mirror::Object>*>(roots_data);
- uint32_t length = roots->GetLength();
+ const uint32_t length = roots->GetLength();
// Put all roots in `roots_data`.
for (uint32_t i = 0; i < length; ++i) {
ObjPtr<mirror::Object> object = roots->Get(i);
@@ -285,9 +291,7 @@
}
gc_roots[i] = GcRoot<mirror::Object>(object);
}
- // Store the length of the table at the end. This will allow fetching it from a `stack_map`
- // pointer.
- reinterpret_cast<uint32_t*>(gc_roots + length)[0] = length;
+ FillRootTableLength(roots_data, length);
}
static uint8_t* GetRootTable(const void* code_ptr, uint32_t* number_of_roots = nullptr) {
@@ -396,6 +400,7 @@
// Ensure the header ends up at expected instruction alignment.
size_t header_size = RoundUp(sizeof(OatQuickMethodHeader), alignment);
size_t total_size = header_size + code_size;
+ const uint32_t num_roots = roots->GetLength();
OatQuickMethodHeader* method_header = nullptr;
uint8_t* code_ptr = nullptr;
@@ -408,6 +413,9 @@
ScopedCodeCacheWrite scc(code_map_.get());
memory = AllocateCode(total_size);
if (memory == nullptr) {
+ // Fill root table length so that ClearData works correctly in case of failure. Otherwise
+ // the length will be 0 and cause incorrect DCHECK failure.
+ FillRootTableLength(roots_data, num_roots);
return nullptr;
}
code_ptr = memory + header_size;
@@ -482,9 +490,16 @@
return used_memory_for_data_;
}
-void JitCodeCache::ClearData(Thread* self, void* data) {
+static const uint8_t* FromStackMapToRoots(const uint8_t* stack_map_data) {
+ return stack_map_data - ComputeRootTableSize(GetNumberOfRoots(stack_map_data));
+}
+
+void JitCodeCache::ClearData(Thread* self,
+ uint8_t* stack_map_data,
+ uint8_t* roots_data) {
+ DCHECK_EQ(FromStackMapToRoots(stack_map_data), roots_data);
MutexLock mu(self, lock_);
- FreeData(reinterpret_cast<uint8_t*>(data));
+ FreeData(reinterpret_cast<uint8_t*>(roots_data));
}
void JitCodeCache::ReserveData(Thread* self,
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index a97ef68..40112fe 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -122,7 +122,7 @@
REQUIRES(!lock_);
// Clear data from the data portion of the code cache.
- void ClearData(Thread* self, void* data)
+ void ClearData(Thread* self, uint8_t* stack_map_data, uint8_t* roots_data)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!lock_);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index b99df26..65c8681 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1900,7 +1900,7 @@
}
delete tlsPtr_.instrumentation_stack;
delete tlsPtr_.name;
- delete tlsPtr_.stack_trace_sample;
+ delete tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample;
free(tlsPtr_.nested_signal_state);
Runtime::Current()->GetHeap()->AssertThreadLocalBuffersAreRevoked(this);
diff --git a/runtime/thread.h b/runtime/thread.h
index b2983cc..3f13db1 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -70,7 +70,8 @@
} // namespace mirror
namespace verifier {
-class MethodVerifier;
+ class MethodVerifier;
+ class VerifierDeps;
} // namespace verifier
class ArtMethod;
@@ -947,11 +948,25 @@
}
std::vector<ArtMethod*>* GetStackTraceSample() const {
- return tlsPtr_.stack_trace_sample;
+ return tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample;
}
void SetStackTraceSample(std::vector<ArtMethod*>* sample) {
- tlsPtr_.stack_trace_sample = sample;
+ DCHECK(sample == nullptr || tlsPtr_.deps_or_stack_trace_sample.verifier_deps == nullptr);
+ tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample = sample;
+ }
+
+ verifier::VerifierDeps* GetVerifierDeps() const {
+ return tlsPtr_.deps_or_stack_trace_sample.verifier_deps;
+ }
+
+ // It is the responsability of the caller to make sure the verifier_deps
+ // entry in the thread is cleared before destruction of the actual VerifierDeps
+ // object, or the thread.
+ void SetVerifierDeps(verifier::VerifierDeps* verifier_deps) {
+ DCHECK(verifier_deps == nullptr ||
+ tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample == nullptr);
+ tlsPtr_.deps_or_stack_trace_sample.verifier_deps = verifier_deps;
}
uint64_t GetTraceClockBase() const {
@@ -1378,7 +1393,7 @@
tls_ptr_sized_values() : card_table(nullptr), exception(nullptr), stack_end(nullptr),
managed_stack(), suspend_trigger(nullptr), jni_env(nullptr), tmp_jni_env(nullptr),
self(nullptr), opeer(nullptr), jpeer(nullptr), stack_begin(nullptr), stack_size(0),
- stack_trace_sample(nullptr), wait_next(nullptr), monitor_enter_object(nullptr),
+ deps_or_stack_trace_sample(), wait_next(nullptr), monitor_enter_object(nullptr),
top_handle_scope(nullptr), class_loader_override(nullptr), long_jump_context(nullptr),
instrumentation_stack(nullptr), debug_invoke_req(nullptr), single_step_control(nullptr),
stacked_shadow_frame_record(nullptr), deoptimization_context_stack(nullptr),
@@ -1432,8 +1447,18 @@
// Size of the stack.
size_t stack_size;
- // Pointer to previous stack trace captured by sampling profiler.
- std::vector<ArtMethod*>* stack_trace_sample;
+ // Sampling profiler and AOT verification cannot happen on the same run, so we share
+ // the same entry for the stack trace and the verifier deps.
+ union DepsOrStackTraceSample {
+ DepsOrStackTraceSample() {
+ verifier_deps = nullptr;
+ stack_trace_sample = nullptr;
+ }
+ // Pointer to previous stack trace captured by sampling profiler.
+ std::vector<ArtMethod*>* stack_trace_sample;
+ // When doing AOT verification, per-thread VerifierDeps.
+ verifier::VerifierDeps* verifier_deps;
+ } deps_or_stack_trace_sample;
// The next thread in the wait set this thread is part of or null if not waiting.
Thread* wait_next;
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index 65fd999..d9d2ea3 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -85,6 +85,7 @@
ThreadPoolWorker* worker = reinterpret_cast<ThreadPoolWorker*>(arg);
Runtime* runtime = Runtime::Current();
CHECK(runtime->AttachCurrentThread(worker->name_.c_str(), true, nullptr, false));
+ worker->thread_ = Thread::Current();
// Do work until its time to shut down.
worker->Run();
runtime->DetachCurrentThread();
diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h
index 2ff33a6..eaadfe0 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -62,6 +62,8 @@
// Set the "nice" priorty for this worker.
void SetPthreadPriority(int priority);
+ Thread* GetThread() const { return thread_; }
+
protected:
ThreadPoolWorker(ThreadPool* thread_pool, const std::string& name, size_t stack_size);
static void* Callback(void* arg) REQUIRES(!Locks::mutator_lock_);
@@ -71,6 +73,7 @@
const std::string name_;
std::unique_ptr<MemMap> stack_;
pthread_t pthread_;
+ Thread* thread_;
private:
friend class ThreadPool;
@@ -84,6 +87,10 @@
return threads_.size();
}
+ const std::vector<ThreadPoolWorker*>& GetWorkers() const {
+ return threads_;
+ }
+
// Broadcast to the workers and tell them to empty out the work queue.
void StartWorkers(Thread* self) REQUIRES(!task_queue_lock_);
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index a65e82b..fefe5a3 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -18,6 +18,7 @@
#include <cstring>
+#include "base/stl_util.h"
#include "compiler_callbacks.h"
#include "leb128.h"
#include "mirror/class-inl.h"
@@ -28,7 +29,6 @@
namespace verifier {
VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files) {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (const DexFile* dex_file : dex_files) {
DCHECK(GetDexFileDeps(*dex_file) == nullptr);
std::unique_ptr<DexFileDeps> deps(new DexFileDeps());
@@ -36,6 +36,28 @@
}
}
+void VerifierDeps::MergeWith(const VerifierDeps& other,
+ const std::vector<const DexFile*>& dex_files) {
+ DCHECK(dex_deps_.size() == other.dex_deps_.size());
+ for (const DexFile* dex_file : dex_files) {
+ DexFileDeps* my_deps = GetDexFileDeps(*dex_file);
+ const DexFileDeps& other_deps = *other.GetDexFileDeps(*dex_file);
+ // We currently collect extra strings only on the main `VerifierDeps`,
+ // which should be the one passed as `this` in this method.
+ DCHECK(other_deps.strings_.empty());
+ MergeSets(my_deps->assignable_types_, other_deps.assignable_types_);
+ MergeSets(my_deps->unassignable_types_, other_deps.unassignable_types_);
+ MergeSets(my_deps->classes_, other_deps.classes_);
+ MergeSets(my_deps->fields_, other_deps.fields_);
+ MergeSets(my_deps->direct_methods_, other_deps.direct_methods_);
+ MergeSets(my_deps->virtual_methods_, other_deps.virtual_methods_);
+ MergeSets(my_deps->interface_methods_, other_deps.interface_methods_);
+ for (dex::TypeIndex entry : other_deps.unverified_classes_) {
+ my_deps->unverified_classes_.push_back(entry);
+ }
+ }
+}
+
VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) {
auto it = dex_deps_.find(&dex_file);
return (it == dex_deps_.end()) ? nullptr : it->second.get();
@@ -134,6 +156,38 @@
return GetClassDescriptorStringId(dex_file, field->GetDeclaringClass());
}
+static inline VerifierDeps* GetMainVerifierDeps() {
+ // The main VerifierDeps is the one set in the compiler callbacks, which at the
+ // end of verification will have all the per-thread VerifierDeps merged into it.
+ CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
+ if (callbacks == nullptr) {
+ return nullptr;
+ }
+ return callbacks->GetVerifierDeps();
+}
+
+static inline VerifierDeps* GetThreadLocalVerifierDeps() {
+ // During AOT, each thread has its own VerifierDeps, to avoid lock contention. At the end
+ // of full verification, these VerifierDeps will be merged into the main one.
+ if (!Runtime::Current()->IsAotCompiler()) {
+ return nullptr;
+ }
+ return Thread::Current()->GetVerifierDeps();
+}
+
+static bool FindExistingStringId(const std::vector<std::string>& strings,
+ const std::string& str,
+ uint32_t* found_id) {
+ uint32_t num_extra_ids = strings.size();
+ for (size_t i = 0; i < num_extra_ids; ++i) {
+ if (strings[i] == str) {
+ *found_id = i;
+ return true;
+ }
+ }
+ return false;
+}
+
uint32_t VerifierDeps::GetIdFromString(const DexFile& dex_file, const std::string& str) {
const DexFile::StringId* string_id = dex_file.FindStringId(str.c_str());
if (string_id != nullptr) {
@@ -144,25 +198,32 @@
// String is not in the DEX file. Assign a new ID to it which is higher than
// the number of strings in the DEX file.
- DexFileDeps* deps = GetDexFileDeps(dex_file);
+ // We use the main `VerifierDeps` for adding new strings to simplify
+ // synchronization/merging of these entries between threads.
+ VerifierDeps* singleton = GetMainVerifierDeps();
+ DexFileDeps* deps = singleton->GetDexFileDeps(dex_file);
DCHECK(deps != nullptr);
uint32_t num_ids_in_dex = dex_file.NumStringIds();
- uint32_t num_extra_ids = deps->strings_.size();
+ uint32_t found_id;
- for (size_t i = 0; i < num_extra_ids; ++i) {
- if (deps->strings_[i] == str) {
- return num_ids_in_dex + i;
+ {
+ ReaderMutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ if (FindExistingStringId(deps->strings_, str, &found_id)) {
+ return num_ids_in_dex + found_id;
}
}
-
- deps->strings_.push_back(str);
-
- uint32_t new_id = num_ids_in_dex + num_extra_ids;
- CHECK_GE(new_id, num_ids_in_dex); // check for overflows
- DCHECK_EQ(str, GetStringFromId(dex_file, new_id));
-
- return new_id;
+ {
+ WriterMutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ if (FindExistingStringId(deps->strings_, str, &found_id)) {
+ return num_ids_in_dex + found_id;
+ }
+ deps->strings_.push_back(str);
+ uint32_t new_id = num_ids_in_dex + deps->strings_.size() - 1;
+ CHECK_GE(new_id, num_ids_in_dex); // check for overflows
+ DCHECK_EQ(str, singleton->GetStringFromId(dex_file, new_id));
+ return new_id;
+ }
}
std::string VerifierDeps::GetStringFromId(const DexFile& dex_file, uint32_t string_id) const {
@@ -216,7 +277,6 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
dex_deps->classes_.emplace(ClassResolution(type_idx, GetAccessFlags(klass)));
}
@@ -235,7 +295,6 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
dex_deps->fields_.emplace(FieldResolution(field_idx,
GetAccessFlags(field),
GetFieldDeclaringClassStringId(dex_file,
@@ -259,7 +318,6 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
MethodResolution method_tuple(method_idx,
GetAccessFlags(method),
GetMethodDeclaringClassStringId(dex_file, method_idx, method));
@@ -328,8 +386,6 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
// Get string IDs for both descriptors and store in the appropriate set.
uint32_t destination_id = GetClassDescriptorStringId(dex_file, destination);
uint32_t source_id = GetClassDescriptorStringId(dex_file, source);
@@ -341,14 +397,6 @@
}
}
-static inline VerifierDeps* GetVerifierDepsSingleton() {
- CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
- if (callbacks == nullptr) {
- return nullptr;
- }
- return callbacks->GetVerifierDeps();
-}
-
void VerifierDeps::MaybeRecordVerificationStatus(const DexFile& dex_file,
dex::TypeIndex type_idx,
MethodVerifier::FailureKind failure_kind) {
@@ -357,10 +405,9 @@
return;
}
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- DexFileDeps* dex_deps = singleton->GetDexFileDeps(dex_file);
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ DexFileDeps* dex_deps = thread_deps->GetDexFileDeps(dex_file);
dex_deps->unverified_classes_.push_back(type_idx);
}
}
@@ -368,18 +415,18 @@
void VerifierDeps::MaybeRecordClassResolution(const DexFile& dex_file,
dex::TypeIndex type_idx,
mirror::Class* klass) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddClassResolution(dex_file, type_idx, klass);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddClassResolution(dex_file, type_idx, klass);
}
}
void VerifierDeps::MaybeRecordFieldResolution(const DexFile& dex_file,
uint32_t field_idx,
ArtField* field) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddFieldResolution(dex_file, field_idx, field);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddFieldResolution(dex_file, field_idx, field);
}
}
@@ -387,9 +434,9 @@
uint32_t method_idx,
MethodResolutionKind resolution_kind,
ArtMethod* method) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddMethodResolution(dex_file, method_idx, resolution_kind, method);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddMethodResolution(dex_file, method_idx, resolution_kind, method);
}
}
@@ -398,9 +445,9 @@
mirror::Class* source,
bool is_strict,
bool is_assignable) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddAssignability(dex_file, destination, source, is_strict, is_assignable);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddAssignability(dex_file, destination, source, is_strict, is_assignable);
}
}
@@ -533,7 +580,6 @@
void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files,
std::vector<uint8_t>* buffer) const {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (const DexFile* dex_file : dex_files) {
const DexFileDeps& deps = *GetDexFileDeps(*dex_file);
EncodeStringVector(buffer, deps.strings_);
@@ -575,8 +621,6 @@
}
bool VerifierDeps::Equals(const VerifierDeps& rhs) const {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
if (dex_deps_.size() != rhs.dex_deps_.size()) {
return false;
}
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index e35af41..a12071b 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -42,18 +42,19 @@
// which are being compiled. Classes defined in DEX files outside of this set
// (or synthesized classes without associated DEX files) are considered being
// in the classpath.
-// During code-flow verification, the MethodVerifier informs the VerifierDeps
-// singleton about the outcome of every resolution and assignability test, and
-// the singleton records them if their outcome may change with changes in the
-// classpath.
+// During code-flow verification, the MethodVerifier informs VerifierDeps
+// about the outcome of every resolution and assignability test, and
+// the VerifierDeps object records them if their outcome may change with
+// changes in the classpath.
class VerifierDeps {
public:
- explicit VerifierDeps(const std::vector<const DexFile*>& dex_files)
- REQUIRES(!Locks::verifier_deps_lock_);
+ explicit VerifierDeps(const std::vector<const DexFile*>& dex_files);
- VerifierDeps(const std::vector<const DexFile*>& dex_files,
- ArrayRef<const uint8_t> data)
- REQUIRES(!Locks::verifier_deps_lock_);
+ VerifierDeps(const std::vector<const DexFile*>& dex_files, ArrayRef<const uint8_t> data);
+
+ // Merge `other` into this `VerifierDeps`'. `other` and `this` must be for the
+ // same set of dex files.
+ void MergeWith(const VerifierDeps& other, const std::vector<const DexFile*>& dex_files);
// Record the verification status of the class at `type_idx`.
static void MaybeRecordVerificationStatus(const DexFile& dex_file,
@@ -101,23 +102,15 @@
// Serialize the recorded dependencies and store the data into `buffer`.
// `dex_files` provides the order of the dex files in which the dependencies
// should be emitted.
- void Encode(const std::vector<const DexFile*>& dex_files, std::vector<uint8_t>* buffer) const
- REQUIRES(!Locks::verifier_deps_lock_);
+ void Encode(const std::vector<const DexFile*>& dex_files, std::vector<uint8_t>* buffer) const;
- // NO_THREAD_SAFETY_ANALYSIS as Dump iterates over dex_deps_, which is guarded by
- // verifier_deps_lock_, but we expect Dump to be called once the deps collection is done.
- void Dump(VariableIndentationOutputStream* vios) const
- NO_THREAD_SAFETY_ANALYSIS;
+ void Dump(VariableIndentationOutputStream* vios) const;
// 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 ValidateDependencies(Handle<mirror::ClassLoader> class_loader, Thread* self) const
- NO_THREAD_SAFETY_ANALYSIS;
+ REQUIRES_SHARED(Locks::mutator_lock_);
- // NO_THREAD_SAFETY_ANALSYS, as this is queried when the VerifierDeps are
- // fully created.
- const std::vector<dex::TypeIndex>& GetUnverifiedClasses(const DexFile& dex_file) const
- NO_THREAD_SAFETY_ANALYSIS {
+ const std::vector<dex::TypeIndex>& GetUnverifiedClasses(const DexFile& dex_file) const {
return GetDexFileDeps(dex_file)->unverified_classes_;
}
@@ -200,13 +193,9 @@
// Finds the DexFileDep instance associated with `dex_file`, or nullptr if
// `dex_file` is not reported as being compiled.
- // We disable thread safety analysis. The method only reads the key set of
- // `dex_deps_` which stays constant after initialization.
- DexFileDeps* GetDexFileDeps(const DexFile& dex_file)
- NO_THREAD_SAFETY_ANALYSIS;
+ DexFileDeps* GetDexFileDeps(const DexFile& dex_file);
- const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const
- NO_THREAD_SAFETY_ANALYSIS;
+ const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const;
// Returns true if `klass` is null or not defined in any of dex files which
// were reported as being compiled.
@@ -218,11 +207,10 @@
// of the corresponding DexFileDeps structure (either provided or inferred from
// `dex_file`).
uint32_t GetIdFromString(const DexFile& dex_file, const std::string& str)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES(!Locks::verifier_deps_lock_);
// Returns the string represented by `id`.
- std::string GetStringFromId(const DexFile& dex_file, uint32_t string_id) const
- REQUIRES(Locks::verifier_deps_lock_);
+ std::string GetStringFromId(const DexFile& dex_file, uint32_t string_id) const;
// Returns the bytecode access flags of `element` (bottom 16 bits), or
// `kUnresolvedMarker` if `element` is null.
@@ -235,18 +223,16 @@
uint32_t GetMethodDeclaringClassStringId(const DexFile& dex_file,
uint32_t dex_method_idx,
ArtMethod* method)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
uint32_t GetFieldDeclaringClassStringId(const DexFile& dex_file,
uint32_t dex_field_idx,
ArtField* field)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a string ID of the descriptor of the class.
uint32_t GetClassDescriptorStringId(const DexFile& dex_file, ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES(!Locks::verifier_deps_lock_);
void AddClassResolution(const DexFile& dex_file,
dex::TypeIndex type_idx,
@@ -272,11 +258,9 @@
mirror::Class* source,
bool is_strict,
bool is_assignable)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
- bool Equals(const VerifierDeps& rhs) const
- REQUIRES(!Locks::verifier_deps_lock_);
+ bool Equals(const VerifierDeps& rhs) const;
// Verify `dex_file` according to the `deps`, that is going over each
// `DexFileDeps` field, and checking that the recorded information still
@@ -285,16 +269,14 @@
const DexFile& dex_file,
const DexFileDeps& deps,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
bool VerifyAssignability(Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const std::set<TypeAssignability>& assignables,
bool expected_assignability,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Verify that the set of resolved classes at the point of creation
// of this `VerifierDeps` is still the same.
@@ -302,8 +284,7 @@
const DexFile& dex_file,
const std::set<ClassResolution>& classes,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Verify that the set of resolved fields at the point of creation
// of this `VerifierDeps` is still the same, and each field resolves to the
@@ -313,7 +294,7 @@
const std::set<FieldResolution>& classes,
Thread* self) const
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES(!Locks::verifier_deps_lock_);
// Verify that the set of resolved methods at the point of creation
// of this `VerifierDeps` is still the same, and each method resolves to the
@@ -323,12 +304,10 @@
const std::set<MethodResolution>& methods,
MethodResolutionKind kind,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Map from DexFiles into dependencies collected from verification of their methods.
- std::map<const DexFile*, std::unique_ptr<DexFileDeps>> dex_deps_
- GUARDED_BY(Locks::verifier_deps_lock_);
+ std::map<const DexFile*, std::unique_ptr<DexFileDeps>> dex_deps_;
friend class VerifierDepsTest;
ART_FRIEND_TEST(VerifierDepsTest, StringToId);