summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dexlayout/Android.bp1
-rw-r--r--dexlayout/dex_ir_builder.cc29
-rw-r--r--dexlayout/dex_ir_builder.h7
-rw-r--r--dexlayout/dexdiag.cc5
-rw-r--r--dexlayout/dexlayout.cc10
-rw-r--r--dexlayout/dexlayout.h1
-rw-r--r--dexlayout/dexlayout_test.cc55
-rw-r--r--openjdkjvmti/fixed_up_dex_file.cc79
-rw-r--r--openjdkjvmti/fixed_up_dex_file.h3
-rw-r--r--openjdkjvmti/ti_class.cc3
-rw-r--r--openjdkjvmti/ti_class_definition.cc4
11 files changed, 138 insertions, 59 deletions
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 23ad5fd17e..63650bf121 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -85,6 +85,7 @@ art_cc_binary {
art_cc_test {
name: "art_dexlayout_tests",
defaults: ["art_gtest_defaults"],
+ shared_libs: ["libart-dexlayout"],
srcs: ["dexlayout_test.cc"],
}
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 3ec163cea1..4f9bcdd742 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -20,13 +20,18 @@
#include <vector>
#include "dex_ir_builder.h"
+#include "dexlayout.h"
namespace art {
namespace dex_ir {
-static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* collections);
+static void CheckAndSetRemainingOffsets(const DexFile& dex_file,
+ Collections* collections,
+ const Options& options);
-Header* DexIrBuilder(const DexFile& dex_file, bool eagerly_assign_offsets) {
+Header* DexIrBuilder(const DexFile& dex_file,
+ bool eagerly_assign_offsets,
+ const Options& options) {
const DexFile::Header& disk_header = dex_file.GetHeader();
Header* header = new Header(disk_header.magic_,
disk_header.checksum_,
@@ -70,13 +75,22 @@ Header* DexIrBuilder(const DexFile& dex_file, bool eagerly_assign_offsets) {
// ClassDef table.
collections.SetClassDefsOffset(disk_header.class_defs_off_);
for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) {
+ if (!options.class_filter_.empty()) {
+ // If the filter is enabled (not empty), filter out classes that don't have a matching
+ // descriptor.
+ const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
+ const char* descriptor = dex_file.GetClassDescriptor(class_def);
+ if (options.class_filter_.find(descriptor) == options.class_filter_.end()) {
+ continue;
+ }
+ }
collections.CreateClassDef(dex_file, i);
}
// MapItem.
collections.SetMapListOffset(disk_header.map_off_);
// CallSiteIds and MethodHandleItems.
collections.CreateCallSitesAndMethodHandles(dex_file);
- CheckAndSetRemainingOffsets(dex_file, &collections);
+ CheckAndSetRemainingOffsets(dex_file, &collections, options);
// Sort the vectors by the map order (same order as the file).
collections.SortVectorsByMapOrder();
@@ -89,7 +103,9 @@ Header* DexIrBuilder(const DexFile& dex_file, bool eagerly_assign_offsets) {
return header;
}
-static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* collections) {
+static void CheckAndSetRemainingOffsets(const DexFile& dex_file,
+ Collections* collections,
+ const Options& options) {
const DexFile::Header& disk_header = dex_file.GetHeader();
// Read MapItems and validate/set remaining offsets.
const DexFile::MapList* map = dex_file.GetMapList();
@@ -122,7 +138,10 @@ static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* co
CHECK_EQ(item->offset_, collections->MethodIdsOffset());
break;
case DexFile::kDexTypeClassDefItem:
- CHECK_EQ(item->size_, collections->ClassDefsSize());
+ if (options.class_filter_.empty()) {
+ // The filter may have removed some classes, this will get fixed up during writing.
+ CHECK_EQ(item->size_, collections->ClassDefsSize());
+ }
CHECK_EQ(item->offset_, collections->ClassDefsOffset());
break;
case DexFile::kDexTypeCallSiteIdItem:
diff --git a/dexlayout/dex_ir_builder.h b/dexlayout/dex_ir_builder.h
index 4d4b4e8699..43b5290756 100644
--- a/dexlayout/dex_ir_builder.h
+++ b/dexlayout/dex_ir_builder.h
@@ -22,11 +22,16 @@
#include "dex_ir.h"
namespace art {
+
+class Options;
+
namespace dex_ir {
// Eagerly assign offsets assigns offsets based on the original offsets in the input dex file. If
// this not done, dex_ir::Item::GetOffset will abort when reading uninitialized offsets.
-dex_ir::Header* DexIrBuilder(const DexFile& dex_file, bool eagerly_assign_offsets);
+dex_ir::Header* DexIrBuilder(const DexFile& dex_file,
+ bool eagerly_assign_offsets,
+ const Options& options);
} // namespace dex_ir
} // namespace art
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index 99b1f38f73..c0d6f02c00 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -29,6 +29,7 @@
#include "base/logging.h" // For InitLogging.
#include "base/stringpiece.h"
+#include "dexlayout.h"
#include "dex/dex_file.h"
#include "dex_ir.h"
#include "dex_ir_builder.h"
@@ -290,8 +291,10 @@ static void ProcessOneDexMapping(uint64_t* pagemap,
// Build a list of the dex file section types, sorted from highest offset to lowest.
std::vector<dex_ir::DexFileSection> sections;
{
+ Options options;
std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file,
- /*eagerly_assign_offsets*/ true));
+ /*eagerly_assign_offsets*/ true,
+ options));
sections = dex_ir::GetSortedDexFileSections(header.get(),
dex_ir::SortDirection::kSortDescending);
}
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 1b32f7b0d9..c51e50b577 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1873,7 +1873,9 @@ void DexLayout::ProcessDexFile(const char* file_name,
// These options required the offsets for dumping purposes.
eagerly_assign_offsets = true;
}
- std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file, eagerly_assign_offsets));
+ std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file,
+ eagerly_assign_offsets,
+ GetOptions()));
SetHeader(header.get());
if (options_.verbose_) {
@@ -1948,10 +1950,12 @@ void DexLayout::ProcessDexFile(const char* file_name,
// Regenerate output IR to catch any bugs that might happen during writing.
std::unique_ptr<dex_ir::Header> output_header(
dex_ir::DexIrBuilder(*output_dex_file,
- /*eagerly_assign_offsets*/ true));
+ /*eagerly_assign_offsets*/ true,
+ GetOptions()));
std::unique_ptr<dex_ir::Header> orig_header(
dex_ir::DexIrBuilder(*dex_file,
- /*eagerly_assign_offsets*/ true));
+ /*eagerly_assign_offsets*/ true,
+ GetOptions()));
CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), &error_msg)) << error_msg;
}
}
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index 00d24dbda4..e66710fa55 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -72,6 +72,7 @@ class Options {
const char* output_dex_directory_ = nullptr;
const char* output_file_name_ = nullptr;
const char* profile_file_name_ = nullptr;
+ std::set<std::string> class_filter_;
};
// Hotness info
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 3a7f9eeda6..e93ade1412 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -27,6 +27,7 @@
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
+#include "dexlayout.h"
#include "exec_utils.h"
#include "jit/profile_compilation_info.h"
#include "utils.h"
@@ -778,4 +779,58 @@ TEST_F(DexLayoutTest, LinkData) {
ASSERT_TRUE(::art::Exec(rm_exec_argv, &error_msg));
}
+TEST_F(DexLayoutTest, ClassFilter) {
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ std::string error_msg;
+ const ArtDexFileLoader dex_file_loader;
+ const std::string input_jar = GetTestDexFileName("ManyMethods");
+ CHECK(dex_file_loader.Open(input_jar.c_str(),
+ input_jar.c_str(),
+ /*verify*/ true,
+ /*verify_checksum*/ true,
+ &error_msg,
+ &dex_files)) << error_msg;
+ ASSERT_EQ(dex_files.size(), 1u);
+ for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ EXPECT_GT(dex_file->NumClassDefs(), 1u);
+ for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+ LOG(INFO) << dex_file->GetClassDescriptor(class_def);
+ }
+ Options options;
+ // Filter out all the classes other than the one below based on class descriptor.
+ options.class_filter_.insert("LManyMethods$Strings;");
+ DexLayout dexlayout(options,
+ /*info*/ nullptr,
+ /*out_file*/ nullptr,
+ /*header*/ nullptr);
+ std::unique_ptr<DexContainer> out;
+ dexlayout.ProcessDexFile(dex_file->GetLocation().c_str(),
+ dex_file.get(),
+ /*dex_file_index*/ 0,
+ &out);
+ std::unique_ptr<const DexFile> output_dex_file(
+ dex_file_loader.OpenWithDataSection(
+ out->GetMainSection()->Begin(),
+ out->GetMainSection()->Size(),
+ out->GetDataSection()->Begin(),
+ out->GetDataSection()->Size(),
+ dex_file->GetLocation().c_str(),
+ /* checksum */ 0,
+ /*oat_dex_file*/ nullptr,
+ /* verify */ true,
+ /*verify_checksum*/ false,
+ &error_msg));
+ ASSERT_TRUE(output_dex_file != nullptr);
+
+ ASSERT_EQ(output_dex_file->NumClassDefs(), 1u);
+ for (uint32_t i = 0; i < output_dex_file->NumClassDefs(); ++i) {
+ // Check that every class is in the filter.
+ const DexFile::ClassDef& class_def = output_dex_file->GetClassDef(i);
+ ASSERT_TRUE(options.class_filter_.find(output_dex_file->GetClassDescriptor(class_def)) !=
+ options.class_filter_.end());
+ }
+ }
+}
+
} // namespace art
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index cc56a7b714..6c66f12bb1 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -67,72 +67,59 @@ static void DoDexUnquicken(const art::DexFile& new_dex_file, const art::DexFile&
vdex->UnquickenDexFile(new_dex_file, original_dex_file, /* decompile_return_instruction */true);
}
-std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original) {
+std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original,
+ const char* descriptor) {
// Copy the data into mutable memory.
std::vector<unsigned char> data;
- if (original.IsCompactDexFile()) {
- // Compact dex has a separate data section that is relative from the original dex.
- // We need to copy the shared data section so that dequickening doesn't change anything.
- data.resize(original.Size() + original.DataSize());
- memcpy(data.data(), original.Begin(), original.Size());
- memcpy(data.data() + original.Size(), original.DataBegin(), original.DataSize());
- // Go patch up the header to point to the copied data section.
- art::CompactDexFile::Header* const header =
- const_cast<art::CompactDexFile::Header*>(art::CompactDexFile::Header::At(data.data()));
- header->data_off_ = original.Size();
- header->data_size_ = original.DataSize();
- } else {
- data.resize(original.Size());
- memcpy(data.data(), original.Begin(), original.Size());
- }
+ std::unique_ptr<const art::DexFile> new_dex_file;
std::string error;
const art::ArtDexFileLoader dex_file_loader;
- std::unique_ptr<const art::DexFile> new_dex_file(dex_file_loader.Open(
- data.data(),
- data.size(),
- /*location*/"Unquickening_dexfile.dex",
- /*location_checksum*/0,
- /*oat_dex_file*/nullptr,
- /*verify*/false,
- /*verify_checksum*/false,
- &error));
- if (new_dex_file.get() == nullptr) {
- LOG(ERROR) << "Unable to open dex file from memory for unquickening! error: " << error;
- return nullptr;
- }
-
- DoDexUnquicken(*new_dex_file, original);
if (original.IsCompactDexFile()) {
- // Since we are supposed to return a standard dex, convert back using dexlayout.
+ // Since we are supposed to return a standard dex, convert back using dexlayout. It's OK to do
+ // this before unquickening.
art::Options options;
options.compact_dex_level_ = art::CompactDexLevel::kCompactDexLevelNone;
- options.update_checksum_ = true;
+ // Add a filter to only include the class that has the matching descriptor.
+ static constexpr bool kFilterByDescriptor = true;
+ if (kFilterByDescriptor) {
+ options.class_filter_.insert(descriptor);
+ }
art::DexLayout dex_layout(options,
/*info*/ nullptr,
/*out_file*/ nullptr,
/*header*/ nullptr);
std::unique_ptr<art::DexContainer> dex_container;
- dex_layout.ProcessDexFile(new_dex_file->GetLocation().c_str(),
- new_dex_file.get(),
+ dex_layout.ProcessDexFile(original.GetLocation().c_str(),
+ &original,
0,
&dex_container);
art::DexContainer::Section* main_section = dex_container->GetMainSection();
CHECK_EQ(dex_container->GetDataSection()->Size(), 0u);
- // Overwrite the dex file stored in data with the new result.
- data.clear();
data.insert(data.end(), main_section->Begin(), main_section->End());
- new_dex_file = dex_file_loader.Open(
- data.data(),
- data.size(),
- /*location*/"Unquickening_dexfile.dex",
- /*location_checksum*/0,
- /*oat_dex_file*/nullptr,
- /*verify*/false,
- /*verify_checksum*/false,
- &error);
+ } else {
+ data.resize(original.Size());
+ memcpy(data.data(), original.Begin(), original.Size());
}
+ // Open the dex file in the buffer.
+ new_dex_file = dex_file_loader.Open(
+ data.data(),
+ data.size(),
+ /*location*/"Unquickening_dexfile.dex",
+ /*location_checksum*/0,
+ /*oat_dex_file*/nullptr,
+ /*verify*/false,
+ /*verify_checksum*/false,
+ &error);
+
+ if (new_dex_file == nullptr) {
+ LOG(ERROR) << "Unable to open dex file from memory for unquickening! error: " << error;
+ return nullptr;
+ }
+
+ DoDexUnquicken(*new_dex_file, original);
+
RecomputeDexChecksum(const_cast<art::DexFile*>(new_dex_file.get()));
std::unique_ptr<FixedUpDexFile> ret(new FixedUpDexFile(std::move(new_dex_file), std::move(data)));
return ret;
diff --git a/openjdkjvmti/fixed_up_dex_file.h b/openjdkjvmti/fixed_up_dex_file.h
index b8f349cf8c..7f05a2930a 100644
--- a/openjdkjvmti/fixed_up_dex_file.h
+++ b/openjdkjvmti/fixed_up_dex_file.h
@@ -49,7 +49,8 @@ namespace openjdkjvmti {
// are running on.
class FixedUpDexFile {
public:
- static std::unique_ptr<FixedUpDexFile> Create(const art::DexFile& original)
+ static std::unique_ptr<FixedUpDexFile> Create(const art::DexFile& original,
+ const char* descriptor)
REQUIRES_SHARED(art::Locks::mutator_lock_);
const art::DexFile& GetDexFile() {
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index b3f5c1886e..1868631020 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -191,7 +191,8 @@ struct ClassCallback : public art::ClassLoadCallback {
art::JNIEnvExt* env = self->GetJniEnv();
ScopedLocalRef<jobject> loader(
env, class_loader.IsNull() ? nullptr : env->AddLocalReference<jobject>(class_loader.Get()));
- std::unique_ptr<FixedUpDexFile> dex_file_copy(FixedUpDexFile::Create(initial_dex_file));
+ std::unique_ptr<FixedUpDexFile> dex_file_copy(FixedUpDexFile::Create(initial_dex_file,
+ descriptor));
// Go back to native.
art::ScopedThreadSuspension sts(self, art::ThreadState::kNative);
diff --git a/openjdkjvmti/ti_class_definition.cc b/openjdkjvmti/ti_class_definition.cc
index 6560570136..c8a3047d9a 100644
--- a/openjdkjvmti/ti_class_definition.cc
+++ b/openjdkjvmti/ti_class_definition.cc
@@ -122,7 +122,9 @@ static jvmtiError GetDexDataForRetransformation(ArtJvmTiEnv* env,
if (dex_file == nullptr) {
dex_file = &klass->GetDexFile();
}
- std::unique_ptr<FixedUpDexFile> fixed_dex_file(FixedUpDexFile::Create(*dex_file));
+ std::string storage;
+ std::unique_ptr<FixedUpDexFile> fixed_dex_file(
+ FixedUpDexFile::Create(*dex_file, klass->GetDescriptor(&storage)));
*dex_data_len = static_cast<jint>(fixed_dex_file->Size());
return CopyDataIntoJvmtiBuffer(env,
fixed_dex_file->Begin(),