summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dex2oat/dex2oat_test.cc16
-rw-r--r--dexlayout/compact_dex_writer.cc2
-rw-r--r--dexlayout/compact_dex_writer.h9
-rw-r--r--dexlayout/dex_ir.cc196
-rw-r--r--dexlayout/dex_ir.h236
-rw-r--r--dexlayout/dex_ir_builder.cc7
-rw-r--r--dexlayout/dex_ir_builder.h4
-rw-r--r--dexlayout/dex_writer.cc647
-rw-r--r--dexlayout/dex_writer.h121
-rw-r--r--dexlayout/dexdiag.cc3
-rw-r--r--dexlayout/dexlayout.cc389
-rw-r--r--dexlayout/dexlayout.h28
-rw-r--r--runtime/dex_file_layout.cc10
-rw-r--r--runtime/dex_file_layout.h40
-rw-r--r--runtime/dex_file_verifier.cc4
15 files changed, 1019 insertions, 693 deletions
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index bd8583bd41..ad287b0745 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1332,10 +1332,10 @@ TEST_F(Dex2oatTest, LayoutSections) {
code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeUnused)];
// All the sections should be non-empty.
- EXPECT_GT(section_hot_code.size_, 0u);
- EXPECT_GT(section_sometimes_used.size_, 0u);
- EXPECT_GT(section_startup_only.size_, 0u);
- EXPECT_GT(section_unused.size_, 0u);
+ EXPECT_GT(section_hot_code.Size(), 0u);
+ EXPECT_GT(section_sometimes_used.Size(), 0u);
+ EXPECT_GT(section_startup_only.Size(), 0u);
+ EXPECT_GT(section_unused.Size(), 0u);
// Open the dex file since we need to peek at the code items to verify the layout matches what
// we expect.
@@ -1364,18 +1364,18 @@ TEST_F(Dex2oatTest, LayoutSections) {
const bool is_post_startup = ContainsElement(post_methods, method_idx);
if (is_hot) {
// Hot is highest precedence, check that the hot methods are in the hot section.
- EXPECT_LT(code_item_offset - section_hot_code.offset_, section_hot_code.size_);
+ EXPECT_TRUE(section_hot_code.Contains(code_item_offset));
++hot_count;
} else if (is_post_startup) {
// Post startup is sometimes used section.
- EXPECT_LT(code_item_offset - section_sometimes_used.offset_, section_sometimes_used.size_);
+ EXPECT_TRUE(section_sometimes_used.Contains(code_item_offset));
++post_startup_count;
} else if (is_startup) {
// Startup at this point means not hot or post startup, these must be startup only then.
- EXPECT_LT(code_item_offset - section_startup_only.offset_, section_startup_only.size_);
+ EXPECT_TRUE(section_startup_only.Contains(code_item_offset));
++startup_count;
} else {
- if (code_item_offset - section_unused.offset_ < section_unused.size_) {
+ if (section_unused.Contains(code_item_offset)) {
// If no flags are set, the method should be unused ...
++unused_count;
} else {
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index b089c1d4b3..f2d46199a2 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -47,7 +47,7 @@ void CompactDexWriter::WriteHeader() {
header.class_defs_off_ = collections.ClassDefsOffset();
header.data_size_ = header_->DataSize();
header.data_off_ = header_->DataOffset();
- Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u);
+ UNUSED(Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u));
}
} // namespace art
diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h
index 1c77202c9a..e28efab5c1 100644
--- a/dexlayout/compact_dex_writer.h
+++ b/dexlayout/compact_dex_writer.h
@@ -25,9 +25,12 @@ namespace art {
class CompactDexWriter : public DexWriter {
public:
- CompactDexWriter(dex_ir::Header* header, MemMap* mem_map, CompactDexLevel compact_dex_level)
- : DexWriter(header, mem_map),
- compact_dex_level_(compact_dex_level) { }
+ CompactDexWriter(dex_ir::Header* header,
+ MemMap* mem_map,
+ DexLayout* dex_layout,
+ CompactDexLevel compact_dex_level)
+ : DexWriter(header, mem_map, dex_layout, /*compute_offsets*/ true),
+ compact_dex_level_(compact_dex_level) {}
protected:
void WriteHeader() OVERRIDE;
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 3edb0a44f2..a8ba950c28 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -186,22 +186,28 @@ static bool GetIdsFromByteCode(Collections& collections,
return has_id;
}
-EncodedValue* Collections::ReadEncodedValue(const uint8_t** data) {
+EncodedValue* Collections::ReadEncodedValue(const DexFile& dex_file, const uint8_t** data) {
const uint8_t encoded_value = *(*data)++;
const uint8_t type = encoded_value & 0x1f;
EncodedValue* item = new EncodedValue(type);
- ReadEncodedValue(data, type, encoded_value >> 5, item);
+ ReadEncodedValue(dex_file, data, type, encoded_value >> 5, item);
return item;
}
-EncodedValue* Collections::ReadEncodedValue(const uint8_t** data, uint8_t type, uint8_t length) {
+EncodedValue* Collections::ReadEncodedValue(const DexFile& dex_file,
+ const uint8_t** data,
+ uint8_t type,
+ uint8_t length) {
EncodedValue* item = new EncodedValue(type);
- ReadEncodedValue(data, type, length, item);
+ ReadEncodedValue(dex_file, data, type, length, item);
return item;
}
-void Collections::ReadEncodedValue(
- const uint8_t** data, uint8_t type, uint8_t length, EncodedValue* item) {
+void Collections::ReadEncodedValue(const DexFile& dex_file,
+ const uint8_t** data,
+ uint8_t type,
+ uint8_t length,
+ EncodedValue* item) {
switch (type) {
case DexFile::kDexAnnotationByte:
item->SetByte(static_cast<int8_t>(ReadVarWidth(data, length, false)));
@@ -271,12 +277,17 @@ void Collections::ReadEncodedValue(
}
case DexFile::kDexAnnotationArray: {
EncodedValueVector* values = new EncodedValueVector();
+ const uint32_t offset = *data - dex_file.Begin();
const uint32_t size = DecodeUnsignedLeb128(data);
// Decode all elements.
for (uint32_t i = 0; i < size; i++) {
- values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(data)));
+ values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, data)));
}
- item->SetEncodedArray(new EncodedArrayItem(values));
+ EncodedArrayItem* array_item = new EncodedArrayItem(values);
+ if (eagerly_assign_offsets_) {
+ array_item->SetOffset(offset);
+ }
+ item->SetEncodedArray(array_item);
break;
}
case DexFile::kDexAnnotationAnnotation: {
@@ -287,7 +298,7 @@ void Collections::ReadEncodedValue(
for (uint32_t i = 0; i < size; i++) {
const uint32_t name_index = DecodeUnsignedLeb128(data);
elements->push_back(std::unique_ptr<AnnotationElement>(
- new AnnotationElement(GetStringId(name_index), ReadEncodedValue(data))));
+ new AnnotationElement(GetStringId(name_index), ReadEncodedValue(dex_file, data))));
}
item->SetEncodedAnnotation(new EncodedAnnotation(GetTypeId(type_idx), elements));
break;
@@ -305,16 +316,16 @@ void Collections::ReadEncodedValue(
void Collections::CreateStringId(const DexFile& dex_file, uint32_t i) {
const DexFile::StringId& disk_string_id = dex_file.GetStringId(dex::StringIndex(i));
StringData* string_data = new StringData(dex_file.GetStringData(disk_string_id));
- string_datas_.AddItem(string_data, disk_string_id.string_data_off_);
+ AddItem(string_datas_map_, string_datas_, string_data, disk_string_id.string_data_off_);
StringId* string_id = new StringId(string_data);
- string_ids_.AddIndexedItem(string_id, StringIdsOffset() + i * StringId::ItemSize(), i);
+ AddIndexedItem(string_ids_, string_id, StringIdsOffset() + i * StringId::ItemSize(), i);
}
void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) {
const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i));
TypeId* type_id = new TypeId(GetStringId(disk_type_id.descriptor_idx_.index_));
- type_ids_.AddIndexedItem(type_id, TypeIdsOffset() + i * TypeId::ItemSize(), i);
+ AddIndexedItem(type_ids_, type_id, TypeIdsOffset() + i * TypeId::ItemSize(), i);
}
void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) {
@@ -325,7 +336,7 @@ void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) {
ProtoId* proto_id = new ProtoId(GetStringId(disk_proto_id.shorty_idx_.index_),
GetTypeId(disk_proto_id.return_type_idx_.index_),
parameter_type_list);
- proto_ids_.AddIndexedItem(proto_id, ProtoIdsOffset() + i * ProtoId::ItemSize(), i);
+ AddIndexedItem(proto_ids_, proto_id, ProtoIdsOffset() + i * ProtoId::ItemSize(), i);
}
void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) {
@@ -333,7 +344,7 @@ void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) {
FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_.index_),
GetTypeId(disk_field_id.type_idx_.index_),
GetStringId(disk_field_id.name_idx_.index_));
- field_ids_.AddIndexedItem(field_id, FieldIdsOffset() + i * FieldId::ItemSize(), i);
+ AddIndexedItem(field_ids_, field_id, FieldIdsOffset() + i * FieldId::ItemSize(), i);
}
void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
@@ -341,7 +352,7 @@ void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_.index_),
GetProtoId(disk_method_id.proto_idx_),
GetStringId(disk_method_id.name_idx_.index_));
- method_ids_.AddIndexedItem(method_id, MethodIdsOffset() + i * MethodId::ItemSize(), i);
+ AddIndexedItem(method_ids_, method_id, MethodIdsOffset() + i * MethodId::ItemSize(), i);
}
void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) {
@@ -365,48 +376,48 @@ void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) {
// Static field initializers.
const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def);
EncodedArrayItem* static_values =
- CreateEncodedArrayItem(static_data, disk_class_def.static_values_off_);
+ CreateEncodedArrayItem(dex_file, static_data, disk_class_def.static_values_off_);
ClassData* class_data = CreateClassData(
dex_file, dex_file.GetClassData(disk_class_def), disk_class_def.class_data_off_);
ClassDef* class_def = new ClassDef(class_type, access_flags, superclass, interfaces_type_list,
source_file, annotations, static_values, class_data);
- class_defs_.AddIndexedItem(class_def, ClassDefsOffset() + i * ClassDef::ItemSize(), i);
+ AddIndexedItem(class_defs_, class_def, ClassDefsOffset() + i * ClassDef::ItemSize(), i);
}
TypeList* Collections::CreateTypeList(const DexFile::TypeList* dex_type_list, uint32_t offset) {
if (dex_type_list == nullptr) {
return nullptr;
}
- 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();
- for (uint32_t index = 0; index < size; ++index) {
- type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_.index_));
+ TypeList* type_list = type_lists_map_.GetExistingObject(offset);
+ if (type_list == nullptr) {
+ TypeIdVector* type_vector = new TypeIdVector();
+ uint32_t size = dex_type_list->Size();
+ for (uint32_t index = 0; index < size; ++index) {
+ type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_.index_));
+ }
+ type_list = new TypeList(type_vector);
+ AddItem(type_lists_map_, type_lists_, type_list, offset);
}
- TypeList* new_type_list = new TypeList(type_vector);
- type_lists_.AddItem(new_type_list, offset);
- return new_type_list;
+ return type_list;
}
-EncodedArrayItem* Collections::CreateEncodedArrayItem(const uint8_t* static_data, uint32_t offset) {
+EncodedArrayItem* Collections::CreateEncodedArrayItem(const DexFile& dex_file,
+ const uint8_t* static_data,
+ uint32_t offset) {
if (static_data == nullptr) {
return nullptr;
}
- 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();
- for (uint32_t i = 0; i < size; ++i) {
- values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(&static_data)));
+ EncodedArrayItem* encoded_array_item = encoded_array_items_map_.GetExistingObject(offset);
+ if (encoded_array_item == nullptr) {
+ uint32_t size = DecodeUnsignedLeb128(&static_data);
+ EncodedValueVector* values = new EncodedValueVector();
+ for (uint32_t i = 0; i < size; ++i) {
+ values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, &static_data)));
+ }
+ // TODO: Calculate the size of the encoded array.
+ encoded_array_item = new EncodedArrayItem(values);
+ AddItem(encoded_array_items_map_, encoded_array_items_, encoded_array_item, offset);
}
- // TODO: Calculate the size of the encoded array.
- EncodedArrayItem* encoded_array_item = new EncodedArrayItem(values);
- encoded_array_items_.AddItem(encoded_array_item, offset);
return encoded_array_item;
}
@@ -427,19 +438,16 @@ AnnotationItem* Collections::CreateAnnotationItem(const DexFile& dex_file,
const DexFile::AnnotationItem* annotation) {
const uint8_t* const start_data = reinterpret_cast<const uint8_t*>(annotation);
const uint32_t offset = start_data - dex_file.Begin();
- auto found_annotation_item = AnnotationItems().find(offset);
- if (found_annotation_item != AnnotationItems().end()) {
- return found_annotation_item->second.get();
+ AnnotationItem* annotation_item = annotation_items_map_.GetExistingObject(offset);
+ if (annotation_item == nullptr) {
+ uint8_t visibility = annotation->visibility_;
+ const uint8_t* annotation_data = annotation->annotation_;
+ std::unique_ptr<EncodedValue> encoded_value(
+ ReadEncodedValue(dex_file, &annotation_data, DexFile::kDexAnnotationAnnotation, 0));
+ annotation_item = new AnnotationItem(visibility, encoded_value->ReleaseEncodedAnnotation());
+ annotation_item->SetSize(annotation_data - start_data);
+ AddItem(annotation_items_map_, annotation_items_, annotation_item, offset);
}
- uint8_t visibility = annotation->visibility_;
- const uint8_t* annotation_data = annotation->annotation_;
- std::unique_ptr<EncodedValue> encoded_value(
- ReadEncodedValue(&annotation_data, DexFile::kDexAnnotationAnnotation, 0));
- AnnotationItem* annotation_item =
- new AnnotationItem(visibility, encoded_value->ReleaseEncodedAnnotation());
- annotation_item->SetOffset(offset);
- annotation_item->SetSize(annotation_data - start_data);
- annotation_items_.AddItem(annotation_item, annotation_item->GetOffset());
return annotation_item;
}
@@ -449,30 +457,30 @@ AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file,
if (disk_annotations_item == nullptr || (disk_annotations_item->size_ == 0 && offset == 0)) {
return nullptr;
}
- 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) {
- const DexFile::AnnotationItem* annotation =
- dex_file.GetAnnotationItem(disk_annotations_item, i);
- if (annotation == nullptr) {
- continue;
+ AnnotationSetItem* annotation_set_item = annotation_set_items_map_.GetExistingObject(offset);
+ if (annotation_set_item == nullptr) {
+ std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
+ for (uint32_t i = 0; i < disk_annotations_item->size_; ++i) {
+ const DexFile::AnnotationItem* annotation =
+ dex_file.GetAnnotationItem(disk_annotations_item, i);
+ if (annotation == nullptr) {
+ continue;
+ }
+ AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
+ items->push_back(annotation_item);
}
- AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation);
- items->push_back(annotation_item);
+ annotation_set_item = new AnnotationSetItem(items);
+ AddItem(annotation_set_items_map_, annotation_set_items_, annotation_set_item, offset);
}
- AnnotationSetItem* annotation_set_item = new AnnotationSetItem(items);
- annotation_set_items_.AddItem(annotation_set_item, offset);
return annotation_set_item;
}
AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
- auto found_anno_dir_item = AnnotationsDirectoryItems().find(offset);
- if (found_anno_dir_item != AnnotationsDirectoryItems().end()) {
- return found_anno_dir_item->second.get();
+ AnnotationsDirectoryItem* annotations_directory_item =
+ annotations_directory_items_map_.GetExistingObject(offset);
+ if (annotations_directory_item != nullptr) {
+ return annotations_directory_item;
}
const DexFile::AnnotationSetItem* class_set_item =
dex_file.GetClassAnnotationSet(disk_annotations_item);
@@ -527,20 +535,19 @@ AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexF
}
}
// TODO: Calculate the size of the annotations directory.
- AnnotationsDirectoryItem* annotations_directory_item = new AnnotationsDirectoryItem(
+annotations_directory_item = new AnnotationsDirectoryItem(
class_annotation, field_annotations, method_annotations, parameter_annotations);
- annotations_directory_items_.AddItem(annotations_directory_item, offset);
+ AddItem(annotations_directory_items_map_,
+ annotations_directory_items_,
+ annotations_directory_item,
+ offset);
return annotations_directory_item;
}
ParameterAnnotation* Collections::GenerateParameterAnnotation(
const DexFile& dex_file, MethodId* method_id,
const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
- AnnotationSetRefList* set_ref_list = nullptr;
- auto found_set_ref_list = AnnotationSetRefLists().find(offset);
- if (found_set_ref_list != AnnotationSetRefLists().end()) {
- set_ref_list = found_set_ref_list->second.get();
- }
+ AnnotationSetRefList* set_ref_list = annotation_set_ref_lists_map_.GetExistingObject(offset);
if (set_ref_list == nullptr) {
std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
@@ -550,7 +557,7 @@ ParameterAnnotation* Collections::GenerateParameterAnnotation(
annotations->push_back(CreateAnnotationSetItem(dex_file, annotation_set_item, set_offset));
}
set_ref_list = new AnnotationSetRefList(annotations);
- annotation_set_ref_lists_.AddItem(set_ref_list, offset);
+ AddItem(annotation_set_ref_lists_map_, annotation_set_ref_lists_, set_ref_list, offset);
}
return new ParameterAnnotation(method_id, set_ref_list);
}
@@ -566,13 +573,13 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(&disk_code_item);
DebugInfoItem* debug_info = nullptr;
if (debug_info_stream != nullptr) {
- debug_info = debug_info_items_.GetExistingObject(disk_code_item.debug_info_off_);
+ debug_info = debug_info_items_map_.GetExistingObject(disk_code_item.debug_info_off_);
if (debug_info == nullptr) {
uint32_t debug_info_size = GetDebugInfoStreamSize(debug_info_stream);
uint8_t* debug_info_buffer = new uint8_t[debug_info_size];
memcpy(debug_info_buffer, debug_info_stream, debug_info_size);
debug_info = new DebugInfoItem(debug_info_size, debug_info_buffer);
- debug_info_items_.AddItem(debug_info, disk_code_item.debug_info_off_);
+ AddItem(debug_info_items_map_, debug_info_items_, debug_info, disk_code_item.debug_info_off_);
}
}
@@ -662,7 +669,7 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
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);
+ AddItem(code_items_map_, code_items_, 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
// instructions here.
@@ -690,7 +697,7 @@ MethodItem* Collections::GenerateMethodItem(const DexFile& dex_file, ClassDataIt
MethodId* method_id = GetMethodId(cdii.GetMemberIndex());
uint32_t access_flags = cdii.GetRawMemberAccessFlags();
const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
- CodeItem* code_item = code_items_.GetExistingObject(cdii.GetMethodCodeItemOffset());
+ CodeItem* code_item = code_items_map_.GetExistingObject(cdii.GetMethodCodeItemOffset());
DebugInfoItem* debug_info = nullptr;
if (disk_code_item != nullptr) {
if (code_item == nullptr) {
@@ -705,7 +712,7 @@ ClassData* Collections::CreateClassData(
const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset) {
// Read the fields and methods defined by the class, resolving the circular reference from those
// to classes by setting class at the same time.
- ClassData* class_data = class_datas_.GetExistingObject(offset);
+ ClassData* class_data = class_datas_map_.GetExistingObject(offset);
if (class_data == nullptr && encoded_data != nullptr) {
ClassDataItemIterator cdii(dex_file, encoded_data);
// Static fields.
@@ -735,7 +742,7 @@ ClassData* Collections::CreateClassData(
}
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);
+ AddItem(class_datas_map_, class_datas_, class_data, offset);
}
return class_data;
}
@@ -771,10 +778,10 @@ void Collections::CreateCallSiteId(const DexFile& dex_file, uint32_t i) {
const DexFile::CallSiteIdItem& disk_call_site_id = dex_file.GetCallSiteId(i);
const uint8_t* disk_call_item_ptr = dex_file.Begin() + disk_call_site_id.data_off_;
EncodedArrayItem* call_site_item =
- CreateEncodedArrayItem(disk_call_item_ptr, disk_call_site_id.data_off_);
+ CreateEncodedArrayItem(dex_file, disk_call_item_ptr, disk_call_site_id.data_off_);
CallSiteId* call_site_id = new CallSiteId(call_site_item);
- call_site_ids_.AddIndexedItem(call_site_id, CallSiteIdsOffset() + i * CallSiteId::ItemSize(), i);
+ AddIndexedItem(call_site_ids_, call_site_id, CallSiteIdsOffset() + i * CallSiteId::ItemSize(), i);
}
void Collections::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) {
@@ -796,8 +803,23 @@ void Collections::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) {
field_or_method_id = GetFieldId(index);
}
MethodHandleItem* method_handle = new MethodHandleItem(type, field_or_method_id);
- method_handle_items_.AddIndexedItem(
- method_handle, MethodHandleItemsOffset() + i * MethodHandleItem::ItemSize(), i);
+ AddIndexedItem(method_handle_items_,
+ method_handle,
+ MethodHandleItemsOffset() + i * MethodHandleItem::ItemSize(),
+ i);
+}
+
+void Collections::SortVectorsByMapOrder() {
+ string_datas_map_.SortVectorByMapOrder(string_datas_);
+ type_lists_map_.SortVectorByMapOrder(type_lists_);
+ encoded_array_items_map_.SortVectorByMapOrder(encoded_array_items_);
+ annotation_items_map_.SortVectorByMapOrder(annotation_items_);
+ annotation_set_items_map_.SortVectorByMapOrder(annotation_set_items_);
+ annotation_set_ref_lists_map_.SortVectorByMapOrder(annotation_set_ref_lists_);
+ annotations_directory_items_map_.SortVectorByMapOrder(annotations_directory_items_);
+ debug_info_items_map_.SortVectorByMapOrder(debug_info_items_);
+ code_items_map_.SortVectorByMapOrder(code_items_);
+ class_datas_map_.SortVectorByMapOrder(class_datas_);
}
static uint32_t HeaderOffset(const dex_ir::Collections& collections ATTRIBUTE_UNUSED) {
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 179d3b96e0..61a4eae9b1 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -112,33 +112,55 @@ template<class T> class CollectionBase {
public:
CollectionBase() = default;
- uint32_t GetOffset() const { return offset_; }
- void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
+ uint32_t GetOffset() const {
+ return offset_;
+ }
+ void SetOffset(uint32_t new_offset) {
+ offset_ = new_offset;
+ }
private:
- uint32_t offset_ = 0;
+ // Start out unassigned.
+ uint32_t offset_ = 0u;
DISALLOW_COPY_AND_ASSIGN(CollectionBase);
};
template<class T> class CollectionVector : public CollectionBase<T> {
public:
+ using Vector = std::vector<std::unique_ptr<T>>;
CollectionVector() = default;
- void AddIndexedItem(T* object, uint32_t offset, uint32_t index) {
- object->SetOffset(offset);
- object->SetIndex(index);
+ uint32_t Size() const { return collection_.size(); }
+ Vector& Collection() { return collection_; }
+
+ protected:
+ Vector collection_;
+
+ void AddItem(T* object) {
collection_.push_back(std::unique_ptr<T>(object));
}
- uint32_t Size() const { return collection_.size(); }
- std::vector<std::unique_ptr<T>>& Collection() { return collection_; }
private:
- std::vector<std::unique_ptr<T>> collection_;
-
+ friend class Collections;
DISALLOW_COPY_AND_ASSIGN(CollectionVector);
};
+template<class T> class IndexedCollectionVector : public CollectionVector<T> {
+ public:
+ using Vector = std::vector<std::unique_ptr<T>>;
+ IndexedCollectionVector() = default;
+
+ private:
+ void AddIndexedItem(T* object, uint32_t index) {
+ object->SetIndex(index);
+ CollectionVector<T>::collection_.push_back(std::unique_ptr<T>(object));
+ }
+
+ friend class Collections;
+ DISALLOW_COPY_AND_ASSIGN(IndexedCollectionVector);
+};
+
template<class T> class CollectionMap : public CollectionBase<T> {
public:
CollectionMap() = default;
@@ -146,21 +168,35 @@ template<class T> class CollectionMap : public CollectionBase<T> {
// Returns the existing item if it is already inserted, null otherwise.
T* GetExistingObject(uint32_t offset) {
auto it = collection_.find(offset);
- return it != collection_.end() ? it->second.get() : nullptr;
+ return it != collection_.end() ? it->second : nullptr;
}
- void AddItem(T* object, uint32_t offset) {
- object->SetOffset(offset);
- auto it = collection_.emplace(offset, std::unique_ptr<T>(object));
- CHECK(it.second) << "CollectionMap already has an object with offset " << offset << " "
- << " and address " << it.first->second.get();
- }
uint32_t Size() const { return collection_.size(); }
- std::map<uint32_t, std::unique_ptr<T>>& Collection() { return collection_; }
+ std::map<uint32_t, T*>& Collection() { return collection_; }
+
+ // Sort the vector by copying pointers over.
+ void SortVectorByMapOrder(CollectionVector<T>& vector) {
+ auto it = collection_.begin();
+ CHECK_EQ(vector.Size(), Size());
+ for (size_t i = 0; i < Size(); ++i) {
+ // There are times when the array will temporarily contain the same pointer twice, doing the
+ // release here sure there is no double free errors.
+ vector.Collection()[i].release();
+ vector.Collection()[i].reset(it->second);
+ ++it;
+ }
+ }
private:
- std::map<uint32_t, std::unique_ptr<T>> collection_;
+ std::map<uint32_t, T*> collection_;
+ void AddItem(T* object, uint32_t offset) {
+ auto it = collection_.emplace(offset, object);
+ CHECK(it.second) << "CollectionMap already has an object with offset " << offset << " "
+ << " and address " << it.first->second;
+ }
+
+ friend class Collections;
DISALLOW_COPY_AND_ASSIGN(CollectionMap);
};
@@ -168,32 +204,31 @@ class Collections {
public:
Collections() = default;
- std::vector<std::unique_ptr<StringId>>& StringIds() { return string_ids_.Collection(); }
- std::vector<std::unique_ptr<TypeId>>& TypeIds() { return type_ids_.Collection(); }
- std::vector<std::unique_ptr<ProtoId>>& ProtoIds() { return proto_ids_.Collection(); }
- 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<CallSiteId>>& CallSiteIds() { return call_site_ids_.Collection(); }
- std::vector<std::unique_ptr<MethodHandleItem>>& MethodHandleItems()
+ CollectionVector<StringId>::Vector& StringIds() { return string_ids_.Collection(); }
+ CollectionVector<TypeId>::Vector& TypeIds() { return type_ids_.Collection(); }
+ CollectionVector<ProtoId>::Vector& ProtoIds() { return proto_ids_.Collection(); }
+ CollectionVector<FieldId>::Vector& FieldIds() { return field_ids_.Collection(); }
+ CollectionVector<MethodId>::Vector& MethodIds() { return method_ids_.Collection(); }
+ CollectionVector<ClassDef>::Vector& ClassDefs() { return class_defs_.Collection(); }
+ CollectionVector<CallSiteId>::Vector& CallSiteIds() { return call_site_ids_.Collection(); }
+ CollectionVector<MethodHandleItem>::Vector& MethodHandleItems()
{ return method_handle_items_.Collection(); }
- 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()
+ CollectionVector<StringData>::Vector& StringDatas() { return string_datas_.Collection(); }
+ CollectionVector<TypeList>::Vector& TypeLists() { return type_lists_.Collection(); }
+ CollectionVector<EncodedArrayItem>::Vector& EncodedArrayItems()
{ return encoded_array_items_.Collection(); }
- std::map<uint32_t, std::unique_ptr<AnnotationItem>>& AnnotationItems()
+ CollectionVector<AnnotationItem>::Vector& AnnotationItems()
{ return annotation_items_.Collection(); }
- std::map<uint32_t, std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems()
+ CollectionVector<AnnotationSetItem>::Vector& AnnotationSetItems()
{ return annotation_set_items_.Collection(); }
- std::map<uint32_t, std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists()
+ CollectionVector<AnnotationSetRefList>::Vector& AnnotationSetRefLists()
{ return annotation_set_ref_lists_.Collection(); }
- std::map<uint32_t, std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems()
+ CollectionVector<AnnotationsDirectoryItem>::Vector& AnnotationsDirectoryItems()
{ return annotations_directory_items_.Collection(); }
- std::map<uint32_t, std::unique_ptr<DebugInfoItem>>& DebugInfoItems()
+ CollectionVector<DebugInfoItem>::Vector& DebugInfoItems()
{ return debug_info_items_.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(); }
+ CollectionVector<CodeItem>::Vector& CodeItems() { return code_items_.Collection(); }
+ CollectionVector<ClassData>::Vector& ClassDatas() { return class_datas_.Collection(); }
void CreateStringId(const DexFile& dex_file, uint32_t i);
void CreateTypeId(const DexFile& dex_file, uint32_t i);
@@ -207,7 +242,9 @@ class Collections {
void CreateCallSitesAndMethodHandles(const DexFile& dex_file);
TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset);
- EncodedArrayItem* CreateEncodedArrayItem(const uint8_t* static_data, uint32_t offset);
+ EncodedArrayItem* CreateEncodedArrayItem(const DexFile& dex_file,
+ const uint8_t* static_data,
+ uint32_t offset);
AnnotationItem* CreateAnnotationItem(const DexFile& dex_file,
const DexFile::AnnotationItem* annotation);
AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file,
@@ -326,37 +363,99 @@ class Collections {
uint32_t CodeItemsSize() const { return code_items_.Size(); }
uint32_t ClassDatasSize() const { return class_datas_.Size(); }
+ // Sort the vectors buy map order (same order that was used in the input file).
+ void SortVectorsByMapOrder();
+
+ template <typename Type>
+ void AddItem(CollectionMap<Type>& map,
+ CollectionVector<Type>& vector,
+ Type* item,
+ uint32_t offset) {
+ DCHECK(!map.GetExistingObject(offset));
+ DCHECK(!item->OffsetAssigned());
+ if (eagerly_assign_offsets_) {
+ item->SetOffset(offset);
+ }
+ map.AddItem(item, offset);
+ vector.AddItem(item);
+ }
+
+ template <typename Type>
+ void AddIndexedItem(IndexedCollectionVector<Type>& vector,
+ Type* item,
+ uint32_t offset,
+ uint32_t index) {
+ DCHECK(!item->OffsetAssigned());
+ if (eagerly_assign_offsets_) {
+ item->SetOffset(offset);
+ }
+ vector.AddIndexedItem(item, index);
+ }
+
+ void SetEagerlyAssignOffsets(bool eagerly_assign_offsets) {
+ eagerly_assign_offsets_ = eagerly_assign_offsets;
+ }
+
private:
- EncodedValue* ReadEncodedValue(const uint8_t** data);
- EncodedValue* ReadEncodedValue(const uint8_t** data, uint8_t type, uint8_t length);
- void ReadEncodedValue(const uint8_t** data, uint8_t type, uint8_t length, EncodedValue* item);
+ EncodedValue* ReadEncodedValue(const DexFile& dex_file, const uint8_t** data);
+ EncodedValue* ReadEncodedValue(const DexFile& dex_file,
+ const uint8_t** data,
+ uint8_t type,
+ uint8_t length);
+ void ReadEncodedValue(const DexFile& dex_file,
+ const uint8_t** data,
+ uint8_t type,
+ uint8_t length,
+ EncodedValue* item);
ParameterAnnotation* GenerateParameterAnnotation(const DexFile& dex_file, MethodId* method_id,
const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset);
MethodItem* GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii);
- CollectionVector<StringId> string_ids_;
- CollectionVector<TypeId> type_ids_;
- CollectionVector<ProtoId> proto_ids_;
- CollectionVector<FieldId> field_ids_;
- CollectionVector<MethodId> method_ids_;
- CollectionVector<ClassDef> class_defs_;
- CollectionVector<CallSiteId> call_site_ids_;
- CollectionVector<MethodHandleItem> method_handle_items_;
-
- 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_;
+ // Collection vectors own the IR data.
+ IndexedCollectionVector<StringId> string_ids_;
+ IndexedCollectionVector<TypeId> type_ids_;
+ IndexedCollectionVector<ProtoId> proto_ids_;
+ IndexedCollectionVector<FieldId> field_ids_;
+ IndexedCollectionVector<MethodId> method_ids_;
+ IndexedCollectionVector<CallSiteId> call_site_ids_;
+ IndexedCollectionVector<MethodHandleItem> method_handle_items_;
+ IndexedCollectionVector<StringData> string_datas_;
+ IndexedCollectionVector<TypeList> type_lists_;
+ IndexedCollectionVector<EncodedArrayItem> encoded_array_items_;
+ IndexedCollectionVector<AnnotationItem> annotation_items_;
+ IndexedCollectionVector<AnnotationSetItem> annotation_set_items_;
+ IndexedCollectionVector<AnnotationSetRefList> annotation_set_ref_lists_;
+ IndexedCollectionVector<AnnotationsDirectoryItem> annotations_directory_items_;
+ IndexedCollectionVector<ClassDef> class_defs_;
+ // The order of the vectors controls the layout of the output file by index order, to change the
+ // layout just sort the vector. Note that you may only change the order of the non indexed vectors
+ // below. Indexed vectors are accessed by indices in other places, changing the sorting order will
+ // invalidate the existing indices and is not currently supported.
+ CollectionVector<DebugInfoItem> debug_info_items_;
+ CollectionVector<CodeItem> code_items_;
+ CollectionVector<ClassData> class_datas_;
+
+ // Note that the maps do not have ownership, the vectors do.
+ // TODO: These maps should only be required for building the IR and should be put in a separate
+ // IR builder class.
+ CollectionMap<StringData> string_datas_map_;
+ CollectionMap<TypeList> type_lists_map_;
+ CollectionMap<EncodedArrayItem> encoded_array_items_map_;
+ CollectionMap<AnnotationItem> annotation_items_map_;
+ CollectionMap<AnnotationSetItem> annotation_set_items_map_;
+ CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_map_;
+ CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_map_;
+ CollectionMap<DebugInfoItem> debug_info_items_map_;
+ CollectionMap<CodeItem> code_items_map_;
+ CollectionMap<ClassData> class_datas_map_;
uint32_t map_list_offset_ = 0;
+ // If we eagerly assign offsets during IR building or later after layout. Must be false if
+ // changing the layout is enabled.
+ bool eagerly_assign_offsets_;
+
DISALLOW_COPY_AND_ASSIGN(Collections);
};
@@ -365,15 +464,26 @@ class Item {
Item() { }
virtual ~Item() { }
- uint32_t GetOffset() const { return offset_; }
+ // Return the assigned offset.
+ uint32_t GetOffset() const {
+ CHECK(OffsetAssigned());
+ return offset_;
+ }
uint32_t GetSize() const { return size_; }
void SetOffset(uint32_t offset) { offset_ = offset; }
void SetSize(uint32_t size) { size_ = size; }
+ bool OffsetAssigned() const {
+ return offset_ != kOffsetUnassigned;
+ }
protected:
Item(uint32_t offset, uint32_t size) : offset_(offset), size_(size) { }
- uint32_t offset_ = 0;
+ // 0 is the dex file header and shouldn't be a valid offset for any part of the dex file.
+ static constexpr uint32_t kOffsetUnassigned = 0u;
+
+ // Start out unassigned.
+ uint32_t offset_ = kOffsetUnassigned;
uint32_t size_ = 0;
};
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index bd3e1fa718..924dfe076a 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -26,7 +26,7 @@ namespace dex_ir {
static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* collections);
-Header* DexIrBuilder(const DexFile& dex_file) {
+Header* DexIrBuilder(const DexFile& dex_file, bool eagerly_assign_offsets) {
const DexFile::Header& disk_header = dex_file.GetHeader();
Header* header = new Header(disk_header.magic_,
disk_header.checksum_,
@@ -39,6 +39,7 @@ Header* DexIrBuilder(const DexFile& dex_file) {
disk_header.data_size_,
disk_header.data_off_);
Collections& collections = header->GetCollections();
+ collections.SetEagerlyAssignOffsets(eagerly_assign_offsets);
// Walk the rest of the header fields.
// StringId table.
collections.SetStringIdsOffset(disk_header.string_ids_off_);
@@ -74,9 +75,11 @@ Header* DexIrBuilder(const DexFile& dex_file) {
collections.SetMapListOffset(disk_header.map_off_);
// CallSiteIds and MethodHandleItems.
collections.CreateCallSitesAndMethodHandles(dex_file);
-
CheckAndSetRemainingOffsets(dex_file, &collections);
+ // Sort the vectors by the map order (same order as the file).
+ collections.SortVectorsByMapOrder();
+
return header;
}
diff --git a/dexlayout/dex_ir_builder.h b/dexlayout/dex_ir_builder.h
index c53157b5fc..4d4b4e8699 100644
--- a/dexlayout/dex_ir_builder.h
+++ b/dexlayout/dex_ir_builder.h
@@ -24,7 +24,9 @@
namespace art {
namespace dex_ir {
-dex_ir::Header* DexIrBuilder(const DexFile& dex_file);
+// 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);
} // namespace dex_ir
} // namespace art
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 4895ab6957..c85bca0d92 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -18,17 +18,37 @@
#include <stdint.h>
-#include <queue>
#include <vector>
#include "cdex/compact_dex_file.h"
#include "compact_dex_writer.h"
+#include "dex_file_layout.h"
#include "dex_file_types.h"
+#include "dexlayout.h"
#include "standard_dex_file.h"
#include "utf.h"
namespace art {
+static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
+static constexpr uint32_t kDexSectionWordAlignment = 4;
+
+static constexpr uint32_t SectionAlignment(DexFile::MapItemType type) {
+ switch (type) {
+ case DexFile::kDexTypeClassDataItem:
+ case DexFile::kDexTypeStringDataItem:
+ case DexFile::kDexTypeDebugInfoItem:
+ case DexFile::kDexTypeAnnotationItem:
+ case DexFile::kDexTypeEncodedArrayItem:
+ return alignof(uint8_t);
+
+ default:
+ // All other sections are kDexAlignedSection.
+ return kDexSectionWordAlignment;
+ }
+}
+
+
size_t EncodeIntValue(int32_t value, uint8_t* buffer) {
size_t length = 0;
if (value >= 0) {
@@ -245,130 +265,213 @@ size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t
return offset - original_offset;
}
-void DexWriter::WriteStrings() {
- uint32_t string_data_off[1];
+// TODO: Refactor this to remove duplicated boiler plate. One way to do this is adding
+// function that takes a CollectionVector<T> and uses overloading.
+uint32_t DexWriter::WriteStringIds(uint32_t offset, bool reserve_only) {
+ const uint32_t start = offset;
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());
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeStringIdItem));
+ if (reserve_only) {
+ offset += string_id->GetSize();
+ } else {
+ uint32_t string_data_off = string_id->DataItem()->GetOffset();
+ offset += Write(&string_data_off, string_id->GetSize(), offset);
+ }
}
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetStringIdsOffset(start);
+ }
+ return offset - start;
+}
- 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();
+uint32_t DexWriter::WriteStringDatas(uint32_t offset) {
+ const uint32_t start = offset;
+ for (std::unique_ptr<dex_ir::StringData>& string_data : header_->GetCollections().StringDatas()) {
+ ProcessOffset(&offset, string_data.get());
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeStringDataItem));
offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset);
- Write(string_data->Data(), strlen(string_data->Data()), offset);
+ // Skip null terminator (already zeroed out, no need to write).
+ offset += Write(string_data->Data(), strlen(string_data->Data()), offset) + 1u;
+ }
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetStringDatasOffset(start);
}
+ return offset - start;
}
-void DexWriter::WriteTypes() {
+uint32_t DexWriter::WriteTypeIds(uint32_t offset) {
uint32_t descriptor_idx[1];
+ const uint32_t start = offset;
for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeTypeIdItem));
+ ProcessOffset(&offset, type_id.get());
descriptor_idx[0] = type_id->GetStringId()->GetIndex();
- Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset());
+ offset += Write(descriptor_idx, type_id->GetSize(), offset);
}
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetTypeIdsOffset(start);
+ }
+ return offset - start;
}
-void DexWriter::WriteTypeLists() {
+uint32_t DexWriter::WriteTypeLists(uint32_t offset) {
uint32_t size[1];
uint16_t list[1];
- for (auto& type_list_pair : header_->GetCollections().TypeLists()) {
- std::unique_ptr<dex_ir::TypeList>& type_list = type_list_pair.second;
+ const uint32_t start = offset;
+ for (std::unique_ptr<dex_ir::TypeList>& type_list : header_->GetCollections().TypeLists()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeTypeList));
size[0] = type_list->GetTypeList()->size();
- uint32_t offset = type_list->GetOffset();
+ ProcessOffset(&offset, type_list.get());
offset += Write(size, sizeof(uint32_t), offset);
for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
list[0] = type_id->GetIndex();
offset += Write(list, sizeof(uint16_t), offset);
}
}
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetTypeListsOffset(start);
+ }
+ return offset - start;
}
-void DexWriter::WriteProtos() {
+uint32_t DexWriter::WriteProtoIds(uint32_t offset, bool reserve_only) {
uint32_t buffer[3];
+ const uint32_t start = offset;
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();
- Write(buffer, proto_id->GetSize(), proto_id->GetOffset());
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeProtoIdItem));
+ ProcessOffset(&offset, proto_id.get());
+ if (reserve_only) {
+ offset += proto_id->GetSize();
+ } else {
+ buffer[0] = proto_id->Shorty()->GetIndex();
+ buffer[1] = proto_id->ReturnType()->GetIndex();
+ buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset();
+ offset += Write(buffer, proto_id->GetSize(), offset);
+ }
}
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetProtoIdsOffset(start);
+ }
+ return offset - start;
}
-void DexWriter::WriteFields() {
+uint32_t DexWriter::WriteFieldIds(uint32_t offset) {
uint16_t buffer[4];
+ const uint32_t start = offset;
for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeFieldIdItem));
+ ProcessOffset(&offset, field_id.get());
buffer[0] = field_id->Class()->GetIndex();
buffer[1] = field_id->Type()->GetIndex();
buffer[2] = field_id->Name()->GetIndex();
buffer[3] = field_id->Name()->GetIndex() >> 16;
- Write(buffer, field_id->GetSize(), field_id->GetOffset());
+ offset += Write(buffer, field_id->GetSize(), offset);
+ }
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetFieldIdsOffset(start);
}
+ return offset - start;
}
-void DexWriter::WriteMethods() {
+uint32_t DexWriter::WriteMethodIds(uint32_t offset) {
uint16_t buffer[4];
+ const uint32_t start = offset;
for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMethodIdItem));
+ ProcessOffset(&offset, method_id.get());
buffer[0] = method_id->Class()->GetIndex();
buffer[1] = method_id->Proto()->GetIndex();
buffer[2] = method_id->Name()->GetIndex();
buffer[3] = method_id->Name()->GetIndex() >> 16;
- Write(buffer, method_id->GetSize(), method_id->GetOffset());
+ offset += Write(buffer, method_id->GetSize(), offset);
+ }
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetMethodIdsOffset(start);
}
+ return offset - start;
}
-void DexWriter::WriteEncodedArrays() {
- 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());
+uint32_t DexWriter::WriteEncodedArrays(uint32_t offset) {
+ const uint32_t start = offset;
+ for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array :
+ header_->GetCollections().EncodedArrayItems()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeEncodedArrayItem));
+ ProcessOffset(&offset, encoded_array.get());
+ offset += WriteEncodedArray(encoded_array->GetEncodedValues(), offset);
}
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetEncodedArrayItemsOffset(start);
+ }
+ return offset - start;
}
-void DexWriter::WriteAnnotations() {
+uint32_t DexWriter::WriteAnnotations(uint32_t offset) {
uint8_t visibility[1];
- for (auto& annotation_pair : header_->GetCollections().AnnotationItems()) {
- std::unique_ptr<dex_ir::AnnotationItem>& annotation = annotation_pair.second;
+ const uint32_t start = offset;
+ for (std::unique_ptr<dex_ir::AnnotationItem>& annotation :
+ header_->GetCollections().AnnotationItems()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationItem));
visibility[0] = annotation->GetVisibility();
- size_t offset = annotation->GetOffset();
+ ProcessOffset(&offset, annotation.get());
offset += Write(visibility, sizeof(uint8_t), offset);
- WriteEncodedAnnotation(annotation->GetAnnotation(), offset);
+ offset += WriteEncodedAnnotation(annotation->GetAnnotation(), offset);
+ }
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetAnnotationItemsOffset(start);
}
+ return offset - start;
}
-void DexWriter::WriteAnnotationSets() {
+uint32_t DexWriter::WriteAnnotationSets(uint32_t offset) {
uint32_t size[1];
uint32_t annotation_off[1];
- for (auto& annotation_set_pair : header_->GetCollections().AnnotationSetItems()) {
- std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set = annotation_set_pair.second;
+ const uint32_t start = offset;
+ for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set :
+ header_->GetCollections().AnnotationSetItems()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationSetItem));
size[0] = annotation_set->GetItems()->size();
- size_t offset = annotation_set->GetOffset();
+ ProcessOffset(&offset, annotation_set.get());
offset += Write(size, sizeof(uint32_t), offset);
for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) {
annotation_off[0] = annotation->GetOffset();
offset += Write(annotation_off, sizeof(uint32_t), offset);
}
}
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetAnnotationSetItemsOffset(start);
+ }
+ return offset - start;
}
-void DexWriter::WriteAnnotationSetRefs() {
+uint32_t DexWriter::WriteAnnotationSetRefs(uint32_t offset) {
uint32_t size[1];
uint32_t annotations_off[1];
- for (auto& anno_set_ref_pair : header_->GetCollections().AnnotationSetRefLists()) {
- std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref = anno_set_ref_pair.second;
+ const uint32_t start = offset;
+ for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref :
+ header_->GetCollections().AnnotationSetRefLists()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationSetRefList));
size[0] = annotation_set_ref->GetItems()->size();
- size_t offset = annotation_set_ref->GetOffset();
+ ProcessOffset(&offset, annotation_set_ref.get());
offset += Write(size, sizeof(uint32_t), offset);
for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) {
annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset();
offset += Write(annotations_off, sizeof(uint32_t), offset);
}
}
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetAnnotationSetRefListsOffset(start);
+ }
+ return offset - start;
}
-void DexWriter::WriteAnnotationsDirectories() {
+uint32_t DexWriter::WriteAnnotationsDirectories(uint32_t offset) {
uint32_t directory_buffer[4];
uint32_t annotation_buffer[2];
- for (auto& annotations_directory_pair : header_->GetCollections().AnnotationsDirectoryItems()) {
- std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory =
- annotations_directory_pair.second;
+ const uint32_t start = offset;
+ for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory :
+ header_->GetCollections().AnnotationsDirectoryItems()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem));
+ ProcessOffset(&offset, annotations_directory.get());
directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
annotations_directory->GetClassAnnotation()->GetOffset();
directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 :
@@ -377,7 +480,6 @@ void DexWriter::WriteAnnotationsDirectories() {
annotations_directory->GetMethodAnnotations()->size();
directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 :
annotations_directory->GetParameterAnnotations()->size();
- uint32_t offset = annotations_directory->GetOffset();
offset += Write(directory_buffer, 4 * sizeof(uint32_t), offset);
if (annotations_directory->GetFieldAnnotations() != nullptr) {
for (std::unique_ptr<dex_ir::FieldAnnotation>& field :
@@ -404,27 +506,55 @@ void DexWriter::WriteAnnotationsDirectories() {
}
}
}
-}
-
-void DexWriter::WriteDebugInfoItems() {
- 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 (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();
- uint16_buffer[3] = code_item->TriesSize();
- uint32_buffer[0] = code_item->DebugInfo() == nullptr ? 0 : code_item->DebugInfo()->GetOffset();
- uint32_buffer[1] = code_item->InsnsSize();
- size_t offset = code_item->GetOffset();
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetAnnotationsDirectoryItemsOffset(start);
+ }
+ return offset - start;
+}
+
+uint32_t DexWriter::WriteDebugInfoItems(uint32_t offset) {
+ const uint32_t start = offset;
+ for (std::unique_ptr<dex_ir::DebugInfoItem>& debug_info :
+ header_->GetCollections().DebugInfoItems()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeDebugInfoItem));
+ ProcessOffset(&offset, debug_info.get());
+ offset += Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), offset);
+ }
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetDebugInfoItemsOffset(start);
+ }
+ return offset - start;
+}
+
+uint32_t DexWriter::WriteCodeItems(uint32_t offset, bool reserve_only) {
+ DexLayoutSection* code_section = nullptr;
+ if (!reserve_only && dex_layout_ != nullptr) {
+ code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>(
+ DexLayoutSections::SectionType::kSectionTypeCode)];
+ }
+ uint16_t uint16_buffer[4] = {};
+ uint32_t uint32_buffer[2] = {};
+ uint32_t start = offset;
+ for (auto& code_item : header_->GetCollections().CodeItems()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCodeItem));
+ ProcessOffset(&offset, code_item.get());
+ if (!reserve_only) {
+ uint16_buffer[0] = code_item->RegistersSize();
+ uint16_buffer[1] = code_item->InsSize();
+ uint16_buffer[2] = code_item->OutsSize();
+ uint16_buffer[3] = code_item->TriesSize();
+ uint32_buffer[0] = code_item->DebugInfo() == nullptr ? 0 :
+ code_item->DebugInfo()->GetOffset();
+ uint32_buffer[1] = code_item->InsnsSize();
+ // Only add the section hotness info once.
+ if (code_section != nullptr) {
+ auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get());
+ if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) {
+ code_section->parts_[static_cast<size_t>(it->second)].CombineSection(
+ code_item->GetOffset(), code_item->GetOffset() + code_item->GetSize());
+ }
+ }
+ }
offset += Write(uint16_buffer, 4 * sizeof(uint16_t), offset);
offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset);
offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
@@ -443,7 +573,7 @@ void DexWriter::WriteCodeItems() {
offset += Write(insn_count_and_handler_off, 2 * sizeof(uint16_t), offset);
}
// Leave offset pointing to the end of the try items.
- WriteUleb128(code_item->Handlers()->size(), offset);
+ UNUSED(WriteUleb128(code_item->Handlers()->size(), offset));
for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
size_t list_offset = offset + handlers->GetListOffset();
uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
@@ -457,32 +587,52 @@ void DexWriter::WriteCodeItems() {
}
}
}
+ // TODO: Clean this up to properly calculate the size instead of assuming it doesn't change.
+ offset = code_item->GetOffset() + code_item->GetSize();
}
+
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetCodeItemsOffset(start);
+ }
+ return offset - start;
}
-void DexWriter::WriteClasses() {
+uint32_t DexWriter::WriteClassDefs(uint32_t offset, bool reserve_only) {
+ const uint32_t start = offset;
uint32_t class_def_buffer[8];
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 ? dex::kDexNoIndex :
- class_def->Superclass()->GetIndex();
- class_def_buffer[3] = class_def->InterfacesOffset();
- class_def_buffer[4] = class_def->SourceFile() == nullptr ? dex::kDexNoIndex :
- class_def->SourceFile()->GetIndex();
- class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 :
- class_def->Annotations()->GetOffset();
- class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 :
- class_def->GetClassData()->GetOffset();
- class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 :
- class_def->StaticValues()->GetOffset();
- size_t offset = class_def->GetOffset();
- Write(class_def_buffer, class_def->GetSize(), offset);
- }
-
- 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 = RoundUp(offset, SectionAlignment(DexFile::kDexTypeClassDefItem));
+ if (reserve_only) {
+ offset += class_def->GetSize();
+ } else {
+ class_def_buffer[0] = class_def->ClassType()->GetIndex();
+ class_def_buffer[1] = class_def->GetAccessFlags();
+ class_def_buffer[2] = class_def->Superclass() == nullptr ? dex::kDexNoIndex :
+ class_def->Superclass()->GetIndex();
+ class_def_buffer[3] = class_def->InterfacesOffset();
+ class_def_buffer[4] = class_def->SourceFile() == nullptr ? dex::kDexNoIndex :
+ class_def->SourceFile()->GetIndex();
+ class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 :
+ class_def->Annotations()->GetOffset();
+ class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 :
+ class_def->GetClassData()->GetOffset();
+ class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 :
+ class_def->StaticValues()->GetOffset();
+ offset += Write(class_def_buffer, class_def->GetSize(), offset);
+ }
+ }
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetClassDefsOffset(start);
+ }
+ return offset - start;
+}
+
+uint32_t DexWriter::WriteClassDatas(uint32_t offset) {
+ const uint32_t start = offset;
+ for (const std::unique_ptr<dex_ir::ClassData>& class_data :
+ header_->GetCollections().ClassDatas()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeClassDataItem));
+ ProcessOffset(&offset, class_data.get());
offset += WriteUleb128(class_data->StaticFields()->size(), offset);
offset += WriteUleb128(class_data->InstanceFields()->size(), offset);
offset += WriteUleb128(class_data->DirectMethods()->size(), offset);
@@ -492,139 +642,134 @@ void DexWriter::WriteClasses() {
offset += WriteEncodedMethods(class_data->DirectMethods(), offset);
offset += WriteEncodedMethods(class_data->VirtualMethods(), offset);
}
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetClassDatasOffset(start);
+ }
+ return offset - start;
}
-void DexWriter::WriteCallSites() {
+uint32_t DexWriter::WriteCallSiteIds(uint32_t offset, bool reserve_only) {
+ const uint32_t start = offset;
uint32_t call_site_off[1];
for (std::unique_ptr<dex_ir::CallSiteId>& call_site_id :
header_->GetCollections().CallSiteIds()) {
- call_site_off[0] = call_site_id->CallSiteItem()->GetOffset();
- Write(call_site_off, call_site_id->GetSize(), call_site_id->GetOffset());
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCallSiteIdItem));
+ if (reserve_only) {
+ offset += call_site_id->GetSize();
+ } else {
+ call_site_off[0] = call_site_id->CallSiteItem()->GetOffset();
+ offset += Write(call_site_off, call_site_id->GetSize(), offset);
+ }
}
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetCallSiteIdsOffset(start);
+ }
+ return offset - start;
}
-void DexWriter::WriteMethodHandles() {
+uint32_t DexWriter::WriteMethodHandles(uint32_t offset) {
+ const uint32_t start = offset;
uint16_t method_handle_buff[4];
for (std::unique_ptr<dex_ir::MethodHandleItem>& method_handle :
header_->GetCollections().MethodHandleItems()) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMethodHandleItem));
method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType());
method_handle_buff[1] = 0; // unused.
method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex();
method_handle_buff[3] = 0; // unused.
- Write(method_handle_buff, method_handle->GetSize(), method_handle->GetOffset());
+ offset += Write(method_handle_buff, method_handle->GetSize(), offset);
}
-}
-
-struct MapItemContainer {
- MapItemContainer(uint32_t type, uint32_t size, uint32_t offset)
- : type_(type), size_(size), offset_(offset) { }
-
- bool operator<(const MapItemContainer& other) const {
- return offset_ > other.offset_;
- }
-
- uint32_t type_;
- uint32_t size_;
- uint32_t offset_;
-};
-
-void DexWriter::WriteMapItem() {
- dex_ir::Collections& collection = header_->GetCollections();
- std::priority_queue<MapItemContainer> queue;
-
- // Header and index section.
- queue.push(MapItemContainer(DexFile::kDexTypeHeaderItem, 1, 0));
- if (collection.StringIdsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeStringIdItem, collection.StringIdsSize(),
- collection.StringIdsOffset()));
- }
- if (collection.TypeIdsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeTypeIdItem, collection.TypeIdsSize(),
- collection.TypeIdsOffset()));
- }
- if (collection.ProtoIdsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeProtoIdItem, collection.ProtoIdsSize(),
- collection.ProtoIdsOffset()));
- }
- if (collection.FieldIdsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeFieldIdItem, collection.FieldIdsSize(),
- collection.FieldIdsOffset()));
- }
- if (collection.MethodIdsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeMethodIdItem, collection.MethodIdsSize(),
- collection.MethodIdsOffset()));
- }
- if (collection.ClassDefsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeClassDefItem, collection.ClassDefsSize(),
- collection.ClassDefsOffset()));
- }
- if (collection.CallSiteIdsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeCallSiteIdItem, collection.CallSiteIdsSize(),
- collection.CallSiteIdsOffset()));
- }
- if (collection.MethodHandleItemsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeMethodHandleItem,
- collection.MethodHandleItemsSize(), collection.MethodHandleItemsOffset()));
- }
-
- // Data section.
- queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
- if (collection.TypeListsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(),
- collection.TypeListsOffset()));
- }
- if (collection.AnnotationSetRefListsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetRefList,
- collection.AnnotationSetRefListsSize(), collection.AnnotationSetRefListsOffset()));
- }
- if (collection.AnnotationSetItemsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetItem,
- collection.AnnotationSetItemsSize(), collection.AnnotationSetItemsOffset()));
- }
- if (collection.ClassDatasSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeClassDataItem, collection.ClassDatasSize(),
- collection.ClassDatasOffset()));
- }
- if (collection.CodeItemsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeCodeItem, collection.CodeItemsSize(),
- collection.CodeItemsOffset()));
- }
- if (collection.StringDatasSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeStringDataItem, collection.StringDatasSize(),
- collection.StringDatasOffset()));
- }
- if (collection.DebugInfoItemsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeDebugInfoItem, collection.DebugInfoItemsSize(),
- collection.DebugInfoItemsOffset()));
- }
- if (collection.AnnotationItemsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeAnnotationItem, collection.AnnotationItemsSize(),
- collection.AnnotationItemsOffset()));
- }
- if (collection.EncodedArrayItemsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeEncodedArrayItem,
- collection.EncodedArrayItemsSize(), collection.EncodedArrayItemsOffset()));
- }
- if (collection.AnnotationsDirectoryItemsSize() != 0) {
- queue.push(MapItemContainer(DexFile::kDexTypeAnnotationsDirectoryItem,
- collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset()));
+ if (compute_offsets_ && start != offset) {
+ header_->GetCollections().SetMethodHandleItemsOffset(start);
}
+ return offset - start;
+}
- uint32_t offset = collection.MapListOffset();
+uint32_t DexWriter::WriteMapItems(uint32_t offset, MapItemQueue* queue) {
+ // All the sections should already have been added.
uint16_t uint16_buffer[2];
uint32_t uint32_buffer[2];
uint16_buffer[1] = 0;
- uint32_buffer[0] = queue.size();
+ uint32_buffer[0] = queue->size();
+ const uint32_t start = offset;
offset += Write(uint32_buffer, sizeof(uint32_t), offset);
- while (!queue.empty()) {
- const MapItemContainer& map_item = queue.top();
+ while (!queue->empty()) {
+ const MapItem& map_item = queue->top();
uint16_buffer[0] = map_item.type_;
uint32_buffer[0] = map_item.size_;
uint32_buffer[1] = map_item.offset_;
offset += Write(uint16_buffer, 2 * sizeof(uint16_t), offset);
offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset);
- queue.pop();
+ queue->pop();
}
+ return offset - start;
+}
+
+uint32_t DexWriter::GenerateAndWriteMapItems(uint32_t offset) {
+ dex_ir::Collections& collection = header_->GetCollections();
+ MapItemQueue queue;
+
+ // Header and index section.
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHeaderItem, 1, 0));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringIdItem,
+ collection.StringIdsSize(),
+ collection.StringIdsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeIdItem,
+ collection.TypeIdsSize(),
+ collection.TypeIdsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeProtoIdItem,
+ collection.ProtoIdsSize(),
+ collection.ProtoIdsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeFieldIdItem,
+ collection.FieldIdsSize(),
+ collection.FieldIdsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodIdItem,
+ collection.MethodIdsSize(),
+ collection.MethodIdsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDefItem,
+ collection.ClassDefsSize(),
+ collection.ClassDefsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCallSiteIdItem,
+ collection.CallSiteIdsSize(),
+ collection.CallSiteIdsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodHandleItem,
+ collection.MethodHandleItemsSize(),
+ collection.MethodHandleItemsOffset()));
+ // Data section.
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeList,
+ collection.TypeListsSize(),
+ collection.TypeListsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetRefList,
+ collection.AnnotationSetRefListsSize(),
+ collection.AnnotationSetRefListsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetItem,
+ collection.AnnotationSetItemsSize(),
+ collection.AnnotationSetItemsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDataItem,
+ collection.ClassDatasSize(),
+ collection.ClassDatasOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCodeItem,
+ collection.CodeItemsSize(),
+ collection.CodeItemsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringDataItem,
+ collection.StringDatasSize(),
+ collection.StringDatasOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeDebugInfoItem,
+ collection.DebugInfoItemsSize(),
+ collection.DebugInfoItemsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationItem,
+ collection.AnnotationItemsSize(),
+ collection.AnnotationItemsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeEncodedArrayItem,
+ collection.EncodedArrayItemsSize(),
+ collection.EncodedArrayItemsOffset()));
+ queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationsDirectoryItem,
+ collection.AnnotationsDirectoryItemsSize(),
+ collection.AnnotationsDirectoryItemsOffset()));
+
+ // Write the map items.
+ return WriteMapItems(offset, &queue);
}
void DexWriter::WriteHeader() {
@@ -657,38 +802,110 @@ void DexWriter::WriteHeader() {
header.data_off_ = header_->DataOffset();
static_assert(sizeof(header) == 0x70, "Size doesn't match dex spec");
- Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u);
+ UNUSED(Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u));
}
void DexWriter::WriteMemMap() {
- WriteStrings();
- WriteTypes();
- WriteTypeLists();
- WriteProtos();
- WriteFields();
- WriteMethods();
- WriteEncodedArrays();
- WriteAnnotations();
- WriteAnnotationSets();
- WriteAnnotationSetRefs();
- WriteAnnotationsDirectories();
- WriteDebugInfoItems();
- WriteCodeItems();
- WriteClasses();
- WriteCallSites();
- WriteMethodHandles();
- WriteMapItem();
+ // Starting offset is right after the header.
+ uint32_t offset = sizeof(StandardDexFile::Header);
+
+ dex_ir::Collections& collection = header_->GetCollections();
+
+ // Based on: https://source.android.com/devices/tech/dalvik/dex-format
+ // Since the offsets may not be calculated already, the writing must be done in the correct order.
+ const uint32_t string_ids_offset = offset;
+ offset += WriteStringIds(offset, /*reserve_only*/ true);
+ offset += WriteTypeIds(offset);
+ const uint32_t proto_ids_offset = offset;
+ offset += WriteProtoIds(offset, /*reserve_only*/ true);
+ offset += WriteFieldIds(offset);
+ offset += WriteMethodIds(offset);
+ const uint32_t class_defs_offset = offset;
+ offset += WriteClassDefs(offset, /*reserve_only*/ true);
+ const uint32_t call_site_ids_offset = offset;
+ offset += WriteCallSiteIds(offset, /*reserve_only*/ true);
+ offset += WriteMethodHandles(offset);
+
+ uint32_t data_offset_ = 0u;
+ if (compute_offsets_) {
+ // Data section.
+ offset = RoundUp(offset, kDataSectionAlignment);
+ data_offset_ = offset;
+ }
+
+ // Write code item first to minimize the space required for encoded methods.
+ // Reserve code item space since we need the debug offsets to actually write them.
+ const uint32_t code_items_offset = offset;
+ offset += WriteCodeItems(offset, /*reserve_only*/ true);
+ // Write debug info section.
+ offset += WriteDebugInfoItems(offset);
+ // Actually write code items since debug info offsets are calculated now.
+ WriteCodeItems(code_items_offset, /*reserve_only*/ false);
+
+ offset += WriteEncodedArrays(offset);
+ offset += WriteAnnotations(offset);
+ offset += WriteAnnotationSets(offset);
+ offset += WriteAnnotationSetRefs(offset);
+ offset += WriteAnnotationsDirectories(offset);
+ offset += WriteTypeLists(offset);
+ offset += WriteClassDatas(offset);
+ offset += WriteStringDatas(offset);
+
+ // Write delayed id sections that depend on data sections.
+ WriteStringIds(string_ids_offset, /*reserve_only*/ false);
+ WriteProtoIds(proto_ids_offset, /*reserve_only*/ false);
+ WriteClassDefs(class_defs_offset, /*reserve_only*/ false);
+ WriteCallSiteIds(call_site_ids_offset, /*reserve_only*/ false);
+
+ // Write the map list.
+ if (compute_offsets_) {
+ offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMapList));
+ collection.SetMapListOffset(offset);
+ } else {
+ offset = collection.MapListOffset();
+ }
+ offset += GenerateAndWriteMapItems(offset);
+ offset = RoundUp(offset, kDataSectionAlignment);
+
+ // Map items are included in the data section.
+ if (compute_offsets_) {
+ header_->SetDataSize(offset - data_offset_);
+ if (header_->DataSize() != 0) {
+ // Offset must be zero when the size is zero.
+ header_->SetDataOffset(data_offset_);
+ } else {
+ header_->SetDataOffset(0u);
+ }
+ }
+
+ // TODO: Write link data?
+
+ // Write header last.
+ if (compute_offsets_) {
+ header_->SetFileSize(offset);
+ }
WriteHeader();
}
-void DexWriter::Output(dex_ir::Header* header, MemMap* mem_map, CompactDexLevel compact_dex_level) {
+void DexWriter::Output(dex_ir::Header* header,
+ MemMap* mem_map,
+ DexLayout* dex_layout,
+ bool compute_offsets,
+ CompactDexLevel compact_dex_level) {
+ CHECK(dex_layout != nullptr);
std::unique_ptr<DexWriter> writer;
if (compact_dex_level != CompactDexLevel::kCompactDexLevelNone) {
- writer.reset(new CompactDexWriter(header, mem_map, compact_dex_level));
+ writer.reset(new CompactDexWriter(header, mem_map, dex_layout, compact_dex_level));
} else {
- writer.reset(new DexWriter(header, mem_map));
+ writer.reset(new DexWriter(header, mem_map, dex_layout, compute_offsets));
}
writer->WriteMemMap();
}
+void MapItemQueue::AddIfNotEmpty(const MapItem& item) {
+ if (item.size_ != 0) {
+ push(item);
+ }
+}
+
} // namespace art
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index 85d3e7ebf3..c47898e533 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -19,56 +19,119 @@
#ifndef ART_DEXLAYOUT_DEX_WRITER_H_
#define ART_DEXLAYOUT_DEX_WRITER_H_
+#include <functional>
+
#include "base/unix_file/fd_file.h"
#include "cdex/compact_dex_level.h"
#include "dex_ir.h"
#include "mem_map.h"
#include "os.h"
+#include <queue>
+
namespace art {
+class DexLayout;
+class DexLayoutHotnessInfo;
+
+struct MapItem {
+ // Not using DexFile::MapItemType since compact dex and standard dex file may have different
+ // sections.
+ MapItem() = default;
+ MapItem(uint32_t type, uint32_t size, uint32_t offset)
+ : type_(type), size_(size), offset_(offset) { }
+
+ // Sort by decreasing order since the priority_queue puts largest elements first.
+ bool operator>(const MapItem& other) const {
+ return offset_ > other.offset_;
+ }
+
+ uint32_t type_ = 0u;
+ uint32_t size_ = 0u;
+ uint32_t offset_ = 0u;
+};
+
+class MapItemQueue : public
+ std::priority_queue<MapItem, std::vector<MapItem>, std::greater<MapItem>> {
+ public:
+ void AddIfNotEmpty(const MapItem& item);
+};
+
class DexWriter {
public:
- DexWriter(dex_ir::Header* header, MemMap* mem_map) : header_(header), mem_map_(mem_map) {}
+ DexWriter(dex_ir::Header* header,
+ MemMap* mem_map,
+ DexLayout* dex_layout,
+ bool compute_offsets)
+ : header_(header),
+ mem_map_(mem_map),
+ dex_layout_(dex_layout),
+ compute_offsets_(compute_offsets) {}
- static void Output(dex_ir::Header* header, MemMap* mem_map, CompactDexLevel compact_dex_level);
+ static void Output(dex_ir::Header* header,
+ MemMap* mem_map,
+ DexLayout* dex_layout,
+ bool compute_offsets,
+ CompactDexLevel compact_dex_level);
virtual ~DexWriter() {}
protected:
void WriteMemMap();
- size_t Write(const void* buffer, size_t length, size_t offset);
- size_t WriteSleb128(uint32_t value, size_t offset);
- size_t WriteUleb128(uint32_t value, size_t offset);
- size_t WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset);
- size_t WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset);
- size_t WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset);
- size_t WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset);
- size_t WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset);
- size_t WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset);
-
- void WriteStrings();
- void WriteTypes();
- void WriteTypeLists();
- void WriteProtos();
- void WriteFields();
- void WriteMethods();
- void WriteEncodedArrays();
- void WriteAnnotations();
- void WriteAnnotationSets();
- void WriteAnnotationSetRefs();
- void WriteAnnotationsDirectories();
- void WriteDebugInfoItems();
- void WriteCodeItems();
- void WriteClasses();
- void WriteCallSites();
- void WriteMethodHandles();
- void WriteMapItem();
+ size_t Write(const void* buffer, size_t length, size_t offset) WARN_UNUSED;
+ size_t WriteSleb128(uint32_t value, size_t offset) WARN_UNUSED;
+ size_t WriteUleb128(uint32_t value, size_t offset) WARN_UNUSED;
+ size_t WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) WARN_UNUSED;
+ size_t WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) WARN_UNUSED;
+ size_t WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) WARN_UNUSED;
+ size_t WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) WARN_UNUSED;
+ size_t WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) WARN_UNUSED;
+ size_t WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) WARN_UNUSED;
+
+ // Header and id section
virtual void WriteHeader();
+ // reserve_only means don't write, only reserve space. This is required since the string data
+ // offsets must be assigned.
+ uint32_t WriteStringIds(uint32_t offset, bool reserve_only);
+ uint32_t WriteTypeIds(uint32_t offset);
+ uint32_t WriteProtoIds(uint32_t offset, bool reserve_only);
+ uint32_t WriteFieldIds(uint32_t offset);
+ uint32_t WriteMethodIds(uint32_t offset);
+ uint32_t WriteClassDefs(uint32_t offset, bool reserve_only);
+ uint32_t WriteCallSiteIds(uint32_t offset, bool reserve_only);
+
+ uint32_t WriteEncodedArrays(uint32_t offset);
+ uint32_t WriteAnnotations(uint32_t offset);
+ uint32_t WriteAnnotationSets(uint32_t offset);
+ uint32_t WriteAnnotationSetRefs(uint32_t offset);
+ uint32_t WriteAnnotationsDirectories(uint32_t offset);
+
+ // Data section.
+ uint32_t WriteDebugInfoItems(uint32_t offset);
+ uint32_t WriteCodeItems(uint32_t offset, bool reserve_only);
+ uint32_t WriteTypeLists(uint32_t offset);
+ uint32_t WriteStringDatas(uint32_t offset);
+ uint32_t WriteClassDatas(uint32_t offset);
+ uint32_t WriteMethodHandles(uint32_t offset);
+ uint32_t WriteMapItems(uint32_t offset, MapItemQueue* queue);
+ uint32_t GenerateAndWriteMapItems(uint32_t offset);
+
+ // Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the
+ // existing offset and use that for writing.
+ void ProcessOffset(uint32_t* const offset, dex_ir::Item* item) {
+ if (compute_offsets_) {
+ item->SetOffset(*offset);
+ } else {
+ // Not computing offsets, just use the one in the item.
+ *offset = item->GetOffset();
+ }
+ }
dex_ir::Header* const header_;
MemMap* const mem_map_;
+ DexLayout* const dex_layout_;
+ bool compute_offsets_;
private:
DISALLOW_COPY_AND_ASSIGN(DexWriter);
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index c14cd5f807..e83f98ee6b 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -289,7 +289,8 @@ 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;
{
- std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
+ std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file,
+ /*eagerly_assign_offsets*/ true));
sections = dex_ir::GetSortedDexFileSections(header.get(),
dex_ir::SortDirection::kSortDescending);
}
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index dd2e809a92..d904a52f0c 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -56,9 +56,6 @@ using android::base::StringPrintf;
// necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550).
static constexpr bool kChangeClassDefOrder = false;
-static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
-static constexpr uint32_t kDexCodeItemAlignment = 4;
-
/*
* Flags for use with createAccessFlagStr().
*/
@@ -1564,7 +1561,7 @@ void DexLayout::DumpDexFile() {
}
}
-std::vector<dex_ir::ClassData*> DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
+void 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());
@@ -1578,31 +1575,41 @@ std::vector<dex_ir::ClassData*> DexLayout::LayoutClassDefsAndClassData(const Dex
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();
std::unordered_set<dex_ir::ClassData*> visited_class_data;
- std::vector<dex_ir::ClassData*> new_class_data_order;
- for (uint32_t i = 0; i < new_class_def_order.size(); ++i) {
- dex_ir::ClassDef* class_def = new_class_def_order[i];
- if (kChangeClassDefOrder) {
- // This produces dex files that violate the spec since the super class class_def is supposed
- // to occur before any subclasses.
- class_def->SetIndex(i);
- class_def->SetOffset(class_defs_offset);
- class_defs_offset += dex_ir::ClassDef::ItemSize();
- }
+ size_t class_data_index = 0;
+ dex_ir::CollectionVector<dex_ir::ClassData>::Vector& class_datas =
+ header_->GetCollections().ClassDatas();
+ for (dex_ir::ClassDef* class_def : new_class_def_order) {
dex_ir::ClassData* class_data = class_def->GetClassData();
if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) {
- class_data->SetOffset(class_data_offset);
- class_data_offset += class_data->GetSize();
visited_class_data.insert(class_data);
- new_class_data_order.push_back(class_data);
+ // Overwrite the existing vector with the new ordering, note that the sets of objects are
+ // equivalent, but the order changes. This is why this is not a memory leak.
+ // TODO: Consider cleaning this up with a shared_ptr.
+ class_datas[class_data_index].release();
+ class_datas[class_data_index].reset(class_data);
+ ++class_data_index;
+ }
+ }
+ CHECK_EQ(class_data_index, class_datas.size());
+
+ if (kChangeClassDefOrder) {
+ // This currently produces dex files that violate the spec since the super class class_def is
+ // supposed to occur before any subclasses.
+ dex_ir::CollectionVector<dex_ir::ClassDef>::Vector& class_defs =
+ header_->GetCollections().ClassDefs();
+ CHECK_EQ(new_class_def_order.size(), class_defs.size());
+ for (size_t i = 0; i < class_defs.size(); ++i) {
+ // Overwrite the existing vector with the new ordering, note that the sets of objects are
+ // equivalent, but the order changes. This is why this is not a memory leak.
+ // TODO: Consider cleaning this up with a shared_ptr.
+ class_defs[i].release();
+ class_defs[i].reset(new_class_def_order[i]);
}
}
- return new_class_data_order;
}
-int32_t DexLayout::LayoutStringData(const DexFile* dex_file) {
+void DexLayout::LayoutStringData(const DexFile* dex_file) {
const size_t num_strings = header_->GetCollections().StringIds().size();
std::vector<bool> is_shorty(num_strings, false);
std::vector<bool> from_hot_method(num_strings, false);
@@ -1672,23 +1679,9 @@ int32_t DexLayout::LayoutStringData(const DexFile* dex_file) {
}
// Sort string data by specified order.
std::vector<dex_ir::StringId*> string_ids;
- size_t min_offset = std::numeric_limits<size_t>::max();
- size_t max_offset = 0;
- size_t hot_bytes = 0;
for (auto& string_id : header_->GetCollections().StringIds()) {
string_ids.push_back(string_id.get());
- const size_t cur_offset = string_id->DataItem()->GetOffset();
- CHECK_NE(cur_offset, 0u);
- min_offset = std::min(min_offset, cur_offset);
- dex_ir::StringData* data = string_id->DataItem();
- const size_t element_size = data->GetSize() + 1; // Add one extra for null.
- size_t end_offset = cur_offset + element_size;
- if (is_shorty[string_id->GetIndex()] || from_hot_method[string_id->GetIndex()]) {
- hot_bytes += element_size;
- }
- max_offset = std::max(max_offset, end_offset);
- }
- VLOG(compiler) << "Hot string data bytes " << hot_bytes << "/" << max_offset - min_offset;
+ }
std::sort(string_ids.begin(),
string_ids.end(),
[&is_shorty, &from_hot_method](const dex_ir::StringId* a,
@@ -1704,59 +1697,41 @@ int32_t DexLayout::LayoutStringData(const DexFile* dex_file) {
if (a_is_shorty != b_is_shorty) {
return a_is_shorty < b_is_shorty;
}
- // Preserve order.
- return a->DataItem()->GetOffset() < b->DataItem()->GetOffset();
+ // Order by index by default.
+ return a->GetIndex() < b->GetIndex();
});
- // Now we know what order we want the string data, reorder the offsets.
- size_t offset = min_offset;
+ dex_ir::CollectionVector<dex_ir::StringData>::Vector& string_datas =
+ header_->GetCollections().StringDatas();
+ // Now we know what order we want the string data, reorder them.
+ size_t data_index = 0;
for (dex_ir::StringId* string_id : string_ids) {
- dex_ir::StringData* data = string_id->DataItem();
- data->SetOffset(offset);
- offset += data->GetSize() + 1; // Add one extra for null.
+ string_datas[data_index].release();
+ string_datas[data_index].reset(string_id->DataItem());
+ ++data_index;
}
- if (offset > max_offset) {
- return offset - max_offset;
- // If we expanded the string data section, we need to update the offsets or else we will
- // corrupt the next section when writing out.
+ if (kIsDebugBuild) {
+ std::unordered_set<dex_ir::StringData*> visited;
+ for (const std::unique_ptr<dex_ir::StringData>& data : string_datas) {
+ visited.insert(data.get());
+ }
+ for (auto& string_id : header_->GetCollections().StringIds()) {
+ CHECK(visited.find(string_id->DataItem()) != visited.end());
+ }
}
- return 0;
+ CHECK_EQ(data_index, string_datas.size());
}
// Orders code items according to specified class data ordering.
-// NOTE: If the section following the code items is byte aligned, the last code item is left in
-// place to preserve alignment. Layout needs an overhaul to handle movement of other sections.
-int32_t DexLayout::LayoutCodeItems(const DexFile* dex_file,
- std::vector<dex_ir::ClassData*> new_class_data_order) {
- // Do not move code items if class data section precedes code item section.
- // ULEB encoding is variable length, causing problems determining the offset of the code items.
- // TODO: We should swap the order of these sections in the future to avoid this issue.
- uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
- uint32_t code_item_offset = header_->GetCollections().CodeItemsOffset();
- if (class_data_offset < code_item_offset) {
- return 0;
- }
-
- // Find the last code item so we can leave it in place if the next section is not 4 byte aligned.
- dex_ir::CodeItem* last_code_item = nullptr;
- std::unordered_set<dex_ir::CodeItem*> visited_code_items;
- bool is_code_item_aligned = IsNextSectionCodeItemAligned(code_item_offset);
- if (!is_code_item_aligned) {
- for (auto& code_item_pair : header_->GetCollections().CodeItems()) {
- std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second;
- if (last_code_item == nullptr
- || last_code_item->GetOffset() < code_item->GetOffset()) {
- last_code_item = code_item.get();
- }
- }
- }
-
+void DexLayout::LayoutCodeItems(const DexFile* dex_file) {
static constexpr InvokeType invoke_types[] = {
kDirect,
kVirtual
};
- const size_t num_layout_types = static_cast<size_t>(LayoutType::kLayoutTypeCount);
- std::unordered_set<dex_ir::CodeItem*> code_items[num_layout_types];
+ std::unordered_map<dex_ir::CodeItem*, LayoutType>& code_item_layout =
+ layout_hotness_info_.code_item_layout_;
+
+ // Assign hotness flags to all code items.
for (InvokeType invoke_type : invoke_types) {
for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
const bool is_profile_class =
@@ -1772,7 +1747,7 @@ int32_t DexLayout::LayoutCodeItems(const DexFile* dex_file,
: class_data->VirtualMethods())) {
const dex_ir::MethodId *method_id = method->GetMethodId();
dex_ir::CodeItem *code_item = method->GetCodeItem();
- if (code_item == last_code_item || code_item == nullptr) {
+ if (code_item == nullptr) {
continue;
}
// Separate executed methods (clinits and profiled methods) from unexecuted methods.
@@ -1794,194 +1769,61 @@ int32_t DexLayout::LayoutCodeItems(const DexFile* dex_file,
} else if (hotness.IsInProfile()) {
state = LayoutType::kLayoutTypeSometimesUsed;
}
- code_items[static_cast<size_t>(state)].insert(code_item);
- }
- }
- }
-
- // Removing duplicate CodeItems may expose other issues with downstream
- // optimizations such as quickening. But we need to ensure at least the weak
- // forms of it currently in use do not break layout optimizations.
- std::map<dex_ir::CodeItem*, uint32_t> original_code_item_offset;
- // Total_diff includes diffs generated by clinits, executed, and non-executed methods.
- int32_t total_diff = 0;
- // The relative placement has no effect on correctness; it is used to ensure
- // the layout is deterministic
- for (size_t index = 0; index < num_layout_types; ++index) {
- const std::unordered_set<dex_ir::CodeItem*>& code_items_set = code_items[index];
- // diff is reset for each class of code items.
- int32_t diff = 0;
- const uint32_t start_offset = code_item_offset;
- for (dex_ir::ClassData* data : new_class_data_order) {
- data->SetOffset(data->GetOffset() + diff);
- for (InvokeType invoke_type : invoke_types) {
- for (auto &method : *(invoke_type == InvokeType::kDirect
- ? data->DirectMethods()
- : data->VirtualMethods())) {
- dex_ir::CodeItem* code_item = method->GetCodeItem();
- if (code_item != nullptr &&
- code_items_set.find(code_item) != code_items_set.end()) {
- // Compute where the CodeItem was originally laid out.
- uint32_t original_offset = code_item->GetOffset();
- auto it = original_code_item_offset.find(code_item);
- if (it != original_code_item_offset.end()) {
- original_offset = it->second;
- } else {
- original_code_item_offset[code_item] = code_item->GetOffset();
- // Assign the new offset and move the pointer to allocate space.
- code_item->SetOffset(code_item_offset);
- code_item_offset +=
- RoundUp(code_item->GetSize(), kDexCodeItemAlignment);
- }
- // Update the size of the encoded methods to reflect that the offset difference
- // may have changed the ULEB128 length.
- diff +=
- UnsignedLeb128Size(code_item->GetOffset()) - UnsignedLeb128Size(original_offset);
- }
+ auto it = code_item_layout.emplace(code_item, state);
+ if (!it.second) {
+ LayoutType& layout_type = it.first->second;
+ // Already exists, merge the hotness.
+ layout_type = MergeLayoutType(layout_type, state);
}
}
}
- DexLayoutSection& code_section = dex_sections_.sections_[static_cast<size_t>(
- DexLayoutSections::SectionType::kSectionTypeCode)];
- code_section.parts_[index].offset_ = start_offset;
- code_section.parts_[index].size_ = code_item_offset - start_offset;
- for (size_t i = 0; i < num_layout_types; ++i) {
- VLOG(dex) << "Code item layout bucket " << i << " count=" << code_items[i].size()
- << " bytes=" << code_section.parts_[i].size_;
- }
- total_diff += diff;
}
- // Adjust diff to be 4-byte aligned.
- return RoundUp(total_diff, kDexCodeItemAlignment);
-}
-bool DexLayout::IsNextSectionCodeItemAligned(uint32_t offset) {
- dex_ir::Collections& collections = header_->GetCollections();
- std::set<uint32_t> section_offsets;
- section_offsets.insert(collections.MapListOffset());
- section_offsets.insert(collections.TypeListsOffset());
- section_offsets.insert(collections.AnnotationSetRefListsOffset());
- section_offsets.insert(collections.AnnotationSetItemsOffset());
- section_offsets.insert(collections.ClassDatasOffset());
- section_offsets.insert(collections.CodeItemsOffset());
- section_offsets.insert(collections.StringDatasOffset());
- section_offsets.insert(collections.DebugInfoItemsOffset());
- section_offsets.insert(collections.AnnotationItemsOffset());
- section_offsets.insert(collections.EncodedArrayItemsOffset());
- section_offsets.insert(collections.AnnotationsDirectoryItemsOffset());
-
- auto found = section_offsets.find(offset);
- if (found != section_offsets.end()) {
- found++;
- if (found != section_offsets.end()) {
- return *found % kDexCodeItemAlignment == 0;
+ dex_ir::CollectionVector<dex_ir::CodeItem>::Vector& code_items =
+ header_->GetCollections().CodeItems();
+ if (VLOG_IS_ON(dex)) {
+ size_t layout_count[static_cast<size_t>(LayoutType::kLayoutTypeCount)] = {};
+ for (const std::unique_ptr<dex_ir::CodeItem>& code_item : code_items) {
+ auto it = code_item_layout.find(code_item.get());
+ DCHECK(it != code_item_layout.end());
+ ++layout_count[static_cast<size_t>(it->second)];
+ }
+ for (size_t i = 0; i < static_cast<size_t>(LayoutType::kLayoutTypeCount); ++i) {
+ LOG(INFO) << "Code items in category " << i << " count=" << layout_count[i];
}
- }
- return false;
-}
-
-// 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);
- }
+ // Sort the code items vector by new layout. The writing process will take care of calculating
+ // all the offsets. Stable sort to preserve any existing locality that might be there.
+ std::stable_sort(code_items.begin(),
+ code_items.end(),
+ [&](const std::unique_ptr<dex_ir::CodeItem>& a,
+ const std::unique_ptr<dex_ir::CodeItem>& b) {
+ auto it_a = code_item_layout.find(a.get());
+ auto it_b = code_item_layout.find(b.get());
+ DCHECK(it_a != code_item_layout.end());
+ DCHECK(it_b != code_item_layout.end());
+ const LayoutType layout_type_a = it_a->second;
+ const LayoutType layout_type_b = it_b->second;
+ return layout_type_a < layout_type_b;
+ });
}
void DexLayout::LayoutOutputFile(const DexFile* dex_file) {
- const int32_t string_diff = LayoutStringData(dex_file);
- // If we expanded the string data section, we need to update the offsets or else we will
- // corrupt the next section when writing out.
- FixupSections(header_->GetCollections().StringDatasOffset(), string_diff);
- // Update file size.
- header_->SetFileSize(header_->FileSize() + string_diff);
-
- std::vector<dex_ir::ClassData*> new_class_data_order = LayoutClassDefsAndClassData(dex_file);
- const int32_t code_item_diff = LayoutCodeItems(dex_file, new_class_data_order);
- // Move sections after ClassData by diff bytes.
- FixupSections(header_->GetCollections().ClassDatasOffset(), code_item_diff);
-
- // Update file and data size.
- // The data size must be aligned to kDataSectionAlignment.
- const int32_t total_diff = code_item_diff + string_diff;
- header_->SetDataSize(RoundUp(header_->DataSize() + total_diff, kDataSectionAlignment));
- header_->SetFileSize(header_->FileSize() + total_diff);
+ LayoutStringData(dex_file);
+ LayoutClassDefsAndClassData(dex_file);
+ LayoutCodeItems(dex_file);
}
-void DexLayout::OutputDexFile(const DexFile* dex_file) {
+void DexLayout::OutputDexFile(const DexFile* dex_file, bool compute_offsets) {
const std::string& dex_file_location = dex_file->GetLocation();
std::string error_msg;
std::unique_ptr<File> new_file;
+ // Since we allow dex growth, we need to size the map larger than the original input to be safe.
+ // Reserve an extra 10% to add some buffer room. Note that this is probably more than
+ // necessary.
+ constexpr size_t kReserveFraction = 10;
+ const size_t max_size = header_->FileSize() + header_->FileSize() / kReserveFraction;
if (!options_.output_to_memmap_) {
std::string output_location(options_.output_dex_directory_);
size_t last_slash = dex_file_location.rfind('/');
@@ -1998,15 +1840,15 @@ void DexLayout::OutputDexFile(const DexFile* dex_file) {
LOG(ERROR) << "Could not create dex writer output file: " << output_location;
return;
}
- if (ftruncate(new_file->Fd(), header_->FileSize()) != 0) {
+ if (ftruncate(new_file->Fd(), max_size) != 0) {
LOG(ERROR) << "Could not grow dex writer output file: " << output_location;;
new_file->Erase();
return;
}
- mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED,
+ mem_map_.reset(MemMap::MapFile(max_size, 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(),
+ mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, max_size,
PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
}
if (mem_map_ == nullptr) {
@@ -2016,8 +1858,14 @@ void DexLayout::OutputDexFile(const DexFile* dex_file) {
}
return;
}
- DexWriter::Output(header_, mem_map_.get(), options_.compact_dex_level_);
+ DexWriter::Output(header_, mem_map_.get(), this, compute_offsets, options_.compact_dex_level_);
if (new_file != nullptr) {
+ // Since we make the memmap larger than needed, shrink the file back down to not leave extra
+ // padding.
+ int res = new_file->SetLength(header_->FileSize());
+ if (res != 0) {
+ LOG(ERROR) << "Truncating file resulted in " << res;
+ }
UNUSED(new_file->FlushCloseOrErase());
}
}
@@ -2028,7 +1876,15 @@ void DexLayout::OutputDexFile(const DexFile* dex_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));
+ const bool output = options_.output_dex_directory_ != nullptr || options_.output_to_memmap_;
+ // Try to avoid eagerly assigning offsets to find bugs since GetOffset will abort if the offset
+ // is unassigned.
+ bool eagerly_assign_offsets = false;
+ if (options_.visualize_pattern_ || options_.show_section_statistics_ || options_.dump_) {
+ // 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));
SetHeader(header.get());
if (options_.verbose_) {
@@ -2052,13 +1908,17 @@ void DexLayout::ProcessDexFile(const char* file_name,
}
// In case we are outputting to a file, keep it open so we can verify.
- if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) {
- if (info_ != nullptr) {
+ if (output) {
+ // Layout information about what strings and code items are hot. Used by the writing process
+ // to generate the sections that are stored in the oat file.
+ bool do_layout = info_ != nullptr;
+ if (do_layout) {
LayoutOutputFile(dex_file);
}
- OutputDexFile(dex_file);
+ OutputDexFile(dex_file, do_layout);
// Clear header before verifying to reduce peak RAM usage.
+ const size_t file_size = header_->FileSize();
header.reset();
// Verify the output dex file's structure, only enabled by default for debug builds.
@@ -2066,7 +1926,7 @@ void DexLayout::ProcessDexFile(const char* file_name,
std::string error_msg;
std::string location = "memory mapped file for " + std::string(file_name);
std::unique_ptr<const DexFile> output_dex_file(DexFileLoader::Open(mem_map_->Begin(),
- mem_map_->Size(),
+ file_size,
location,
/* checksum */ 0,
/*oat_dex_file*/ nullptr,
@@ -2076,11 +1936,16 @@ void DexLayout::ProcessDexFile(const char* file_name,
CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
// Do IR-level comparison between input and output. This check ignores potential differences
- // due to layout, so offsets are not checked. Instead, it checks the data contents of each item.
+ // due to layout, so offsets are not checked. Instead, it checks the data contents of each
+ // item.
//
// 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));
- std::unique_ptr<dex_ir::Header> orig_header(dex_ir::DexIrBuilder(*dex_file));
+ std::unique_ptr<dex_ir::Header> output_header(
+ dex_ir::DexIrBuilder(*output_dex_file,
+ /*eagerly_assign_offsets*/ true));
+ std::unique_ptr<dex_ir::Header> orig_header(
+ dex_ir::DexIrBuilder(*dex_file,
+ /*eagerly_assign_offsets*/ true));
CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), &error_msg)) << error_msg;
}
}
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index 2e897739cc..8a277b7afe 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -25,6 +25,7 @@
#include <stdint.h>
#include <stdio.h>
+#include <unordered_map>
#include "cdex/compact_dex_level.h"
#include "dex_file_layout.h"
@@ -69,6 +70,13 @@ class Options {
const char* profile_file_name_ = nullptr;
};
+// Hotness info
+class DexLayoutHotnessInfo {
+ public:
+ // Store layout information so that the offset calculation can specify the section sizes.
+ std::unordered_map<dex_ir::CodeItem*, LayoutType> code_item_layout_;
+};
+
class DexLayout {
public:
DexLayout(Options& options,
@@ -86,10 +94,14 @@ class DexLayout {
MemMap* GetAndReleaseMemMap() { return mem_map_.release(); }
- const DexLayoutSections& GetSections() const {
+ DexLayoutSections& GetSections() {
return dex_sections_;
}
+ const DexLayoutHotnessInfo& LayoutHotnessInfo() const {
+ return layout_hotness_info_;
+ }
+
private:
void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item);
void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
@@ -120,18 +132,14 @@ class DexLayout {
void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init);
void DumpDexFile();
- std::vector<dex_ir::ClassData*> LayoutClassDefsAndClassData(const DexFile* dex_file);
- int32_t LayoutCodeItems(const DexFile* dex_file,
- std::vector<dex_ir::ClassData*> new_class_data_order);
- int32_t LayoutStringData(const DexFile* dex_file);
- bool IsNextSectionCodeItemAligned(uint32_t offset);
- 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);
+ void LayoutClassDefsAndClassData(const DexFile* dex_file);
+ void LayoutCodeItems(const DexFile* dex_file);
+ void LayoutStringData(const DexFile* dex_file);
// 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 DexFile* dex_file);
+ void OutputDexFile(const DexFile* dex_file, bool compute_offsets);
void DumpCFG(const DexFile* dex_file, int idx);
void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code);
@@ -142,6 +150,8 @@ class DexLayout {
dex_ir::Header* header_;
std::unique_ptr<MemMap> mem_map_;
DexLayoutSections dex_sections_;
+ // Layout hotness information is only calculated when dexlayout is enabled.
+ DexLayoutHotnessInfo layout_hotness_info_;
DISALLOW_COPY_AND_ASSIGN(DexLayout);
};
diff --git a/runtime/dex_file_layout.cc b/runtime/dex_file_layout.cc
index c3fae15b14..1973440d55 100644
--- a/runtime/dex_file_layout.cc
+++ b/runtime/dex_file_layout.cc
@@ -26,10 +26,10 @@ namespace art {
void DexLayoutSection::Subsection::Madvise(const DexFile* dex_file, int advice) const {
DCHECK(dex_file != nullptr);
- DCHECK_LE(size_, dex_file->Size());
- DCHECK_LE(offset_ + size_, dex_file->Size());
- MadviseLargestPageAlignedRegion(dex_file->Begin() + offset_,
- dex_file->Begin() + offset_ + size_,
+ DCHECK_LT(start_offset_, dex_file->Size());
+ DCHECK_LE(end_offset_, dex_file->Size());
+ MadviseLargestPageAlignedRegion(dex_file->Begin() + start_offset_,
+ dex_file->Begin() + end_offset_,
advice);
}
@@ -69,7 +69,7 @@ std::ostream& operator<<(std::ostream& os, const DexLayoutSection& section) {
for (size_t i = 0; i < static_cast<size_t>(LayoutType::kLayoutTypeCount); ++i) {
const DexLayoutSection::Subsection& part = section.parts_[i];
os << static_cast<LayoutType>(i) << "("
- << part.offset_ << "-" << part.offset_ + part.size_ << ") ";
+ << part.start_offset_ << "-" << part.end_offset_ << ") ";
}
return os;
}
diff --git a/runtime/dex_file_layout.h b/runtime/dex_file_layout.h
index 40cc91232e..4c960c3ff5 100644
--- a/runtime/dex_file_layout.h
+++ b/runtime/dex_file_layout.h
@@ -17,22 +17,25 @@
#ifndef ART_RUNTIME_DEX_FILE_LAYOUT_H_
#define ART_RUNTIME_DEX_FILE_LAYOUT_H_
+#include <algorithm>
#include <cstdint>
#include <iosfwd>
+#include "base/logging.h"
+
namespace art {
class DexFile;
enum class LayoutType : uint8_t {
+ // Layout of things that are hot (commonly accessed), these should be pinned or madvised will
+ // need.
+ kLayoutTypeHot,
// Layout of things that are randomly used. These should be advised to random access.
// Without layout, this is the default mode when loading a dex file.
kLayoutTypeSometimesUsed,
// Layout of things that are only used during startup, these can be madvised after launch.
kLayoutTypeStartupOnly,
- // Layout of things that are hot (commonly accessed), these should be pinned or madvised will
- // need.
- kLayoutTypeHot,
// Layout of things that are needed probably only once (class initializers). These can be
// madvised during trim events.
kLayoutTypeUsedOnce,
@@ -44,6 +47,11 @@ enum class LayoutType : uint8_t {
};
std::ostream& operator<<(std::ostream& os, const LayoutType& collector_type);
+// Return the "best" layout option if the same item has multiple different layouts.
+static inline LayoutType MergeLayoutType(LayoutType a, LayoutType b) {
+ return std::min(a, b);
+}
+
enum class MadviseState : uint8_t {
// Madvise based on a file that was just loaded.
kMadviseStateAtLoad,
@@ -55,15 +63,35 @@ enum class MadviseState : uint8_t {
std::ostream& operator<<(std::ostream& os, const MadviseState& collector_type);
// A dex layout section such as code items or strings. Each section is composed of subsections
-// that are layed out ajacently to each other such as (hot, unused, startup, etc...).
+// that are laid out adjacently to each other such as (hot, unused, startup, etc...).
class DexLayoutSection {
public:
// A subsection is a a continuous range of dex file that is all part of the same layout hint.
class Subsection {
public:
// Use uint32_t to handle 32/64 bit cross compilation.
- uint32_t offset_ = 0u;
- uint32_t size_ = 0u;
+ uint32_t start_offset_ = 0u;
+ uint32_t end_offset_ = 0u;
+
+ bool Contains(uint32_t offset) const {
+ return start_offset_ <= offset && offset < end_offset_;
+ }
+
+ bool Size() const {
+ DCHECK_LE(start_offset_, end_offset_);
+ return end_offset_ - start_offset_;
+ }
+
+ void CombineSection(uint32_t start_offset, uint32_t end_offset) {
+ DCHECK_LT(start_offset, end_offset);
+ if (start_offset_ == end_offset_) {
+ start_offset_ = start_offset;
+ end_offset_ = end_offset;
+ } else {
+ start_offset_ = std::min(start_offset_, start_offset);
+ end_offset_ = std::max(end_offset_, end_offset);
+ }
+ }
void Madvise(const DexFile* dex_file, int advice) const;
};
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 025952f7a9..edf5650df1 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -471,7 +471,9 @@ bool DexFileVerifier::CheckMap() {
if (IsDataSectionType(item_type)) {
uint32_t icount = item->size_;
if (UNLIKELY(icount > data_items_left)) {
- ErrorStringPrintf("Too many items in data section: %ud", data_item_count + icount);
+ ErrorStringPrintf("Too many items in data section: %ud item_type %zx",
+ data_item_count + icount,
+ static_cast<size_t>(item_type));
return false;
}
data_items_left -= icount;