diff options
| -rw-r--r-- | dexlayout/dex_ir.cc | 2 | ||||
| -rw-r--r-- | dexlayout/dexlayout.cc | 107 | ||||
| -rw-r--r-- | dexlayout/dexlayout.h | 5 | ||||
| -rw-r--r-- | dexlayout/dexlayout_test.cc | 106 | ||||
| -rw-r--r-- | runtime/gc/heap.cc | 9 | ||||
| -rw-r--r-- | runtime/hprof/hprof.cc | 4 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_field.cc | 1 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_heap.cc | 71 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_phase.cc | 1 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_search.cc | 1 | ||||
| -rw-r--r-- | test/913-heaps/expected.txt | 175 | ||||
| -rw-r--r-- | test/913-heaps/src/Main.java | 11 |
12 files changed, 405 insertions, 88 deletions
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index 609068f41c..131f4b9f63 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -653,7 +653,7 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, if (has_catch_all) { size = -size; } - if (already_added == true) { + if (already_added) { for (int32_t i = 0; i < size; i++) { DecodeUnsignedLeb128(&handlers_data); DecodeUnsignedLeb128(&handlers_data); diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 1add6bfede..22619b9e8d 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -46,6 +46,8 @@ namespace art { using android::base::StringPrintf; +static constexpr uint32_t kDexCodeItemAlignment = 4; + /* * Flags for use with createAccessFlagStr(). */ @@ -1489,7 +1491,7 @@ void DexLayout::DumpDexFile() { } } -std::vector<dex_ir::ClassDef*> DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) { +std::vector<dex_ir::ClassData*> 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()); @@ -1505,46 +1507,93 @@ std::vector<dex_ir::ClassDef*> DexLayout::LayoutClassDefsAndClassData(const DexF } 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]; class_def->SetIndex(i); class_def->SetOffset(class_defs_offset); class_defs_offset += dex_ir::ClassDef::ItemSize(); - if (class_def->GetClassData() != nullptr) { - class_def->GetClassData()->SetOffset(class_data_offset); - class_data_offset += class_def->GetClassData()->GetSize(); + 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); } } - return new_class_def_order; + return new_class_data_order; } -int32_t DexLayout::LayoutCodeItems(std::vector<dex_ir::ClassDef*> new_class_def_order) { - int32_t diff = 0; +// 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(std::vector<dex_ir::ClassData*> new_class_data_order) { + // Find the last code item so we can leave it in place if the next section is not 4 byte aligned. + std::unordered_set<dex_ir::CodeItem*> visited_code_items; uint32_t offset = header_->GetCollections().CodeItemsOffset(); - for (dex_ir::ClassDef* class_def : new_class_def_order) { - dex_ir::ClassData* class_data = class_def->GetClassData(); - if (class_data != nullptr) { - class_data->SetOffset(class_data->GetOffset() + diff); - for (auto& method : *class_data->DirectMethods()) { - dex_ir::CodeItem* code_item = method->GetCodeItem(); - if (code_item != nullptr) { - diff += UnsignedLeb128Size(offset) - UnsignedLeb128Size(code_item->GetOffset()); - code_item->SetOffset(offset); - offset += RoundUp(code_item->GetSize(), 4); - } + bool is_code_item_aligned = IsNextSectionCodeItemAligned(offset); + if (!is_code_item_aligned) { + dex_ir::CodeItem* last_code_item = nullptr; + 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(); } - for (auto& method : *class_data->VirtualMethods()) { - dex_ir::CodeItem* code_item = method->GetCodeItem(); - if (code_item != nullptr) { - diff += UnsignedLeb128Size(offset) - UnsignedLeb128Size(code_item->GetOffset()); - code_item->SetOffset(offset); - offset += RoundUp(code_item->GetSize(), 4); - } + } + // Preserve the last code item by marking it already visited. + visited_code_items.insert(last_code_item); + } + + int32_t diff = 0; + for (dex_ir::ClassData* class_data : new_class_data_order) { + class_data->SetOffset(class_data->GetOffset() + diff); + for (auto& method : *class_data->DirectMethods()) { + dex_ir::CodeItem* code_item = method->GetCodeItem(); + if (code_item != nullptr && visited_code_items.find(code_item) == visited_code_items.end()) { + visited_code_items.insert(code_item); + diff += UnsignedLeb128Size(offset) - UnsignedLeb128Size(code_item->GetOffset()); + code_item->SetOffset(offset); + offset += RoundUp(code_item->GetSize(), kDexCodeItemAlignment); + } + } + for (auto& method : *class_data->VirtualMethods()) { + dex_ir::CodeItem* code_item = method->GetCodeItem(); + if (code_item != nullptr && visited_code_items.find(code_item) == visited_code_items.end()) { + visited_code_items.insert(code_item); + diff += UnsignedLeb128Size(offset) - UnsignedLeb128Size(code_item->GetOffset()); + code_item->SetOffset(offset); + offset += RoundUp(code_item->GetSize(), kDexCodeItemAlignment); } } } + // Adjust diff to be 4-byte aligned. + return RoundUp(diff, kDexCodeItemAlignment); +} - return diff; +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; + } + } + return false; } // Adjust offsets of every item in the specified section by diff bytes. @@ -1626,10 +1675,8 @@ void DexLayout::FixupSections(uint32_t offset, uint32_t diff) { } void DexLayout::LayoutOutputFile(const DexFile* dex_file) { - std::vector<dex_ir::ClassDef*> new_class_def_order = LayoutClassDefsAndClassData(dex_file); - int32_t diff = LayoutCodeItems(new_class_def_order); - // Adjust diff to be 4-byte aligned. - diff = RoundUp(diff, 4); + std::vector<dex_ir::ClassData*> new_class_data_order = LayoutClassDefsAndClassData(dex_file); + int32_t diff = LayoutCodeItems(new_class_data_order); // Move sections after ClassData by diff bytes. FixupSections(header_->GetCollections().ClassDatasOffset(), diff); // Update file size. diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index ac1a4a6efb..391870644a 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -105,8 +105,9 @@ class DexLayout { void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init); void DumpDexFile(); - std::vector<dex_ir::ClassDef*> LayoutClassDefsAndClassData(const DexFile* dex_file); - int32_t LayoutCodeItems(std::vector<dex_ir::ClassDef*> new_class_def_order); + std::vector<dex_ir::ClassData*> LayoutClassDefsAndClassData(const DexFile* dex_file); + int32_t LayoutCodeItems(std::vector<dex_ir::ClassData*> new_class_data_order); + 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); diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc index 9881e283df..9f0593a5cd 100644 --- a/dexlayout/dexlayout_test.cc +++ b/dexlayout/dexlayout_test.cc @@ -55,6 +55,26 @@ static const char kDexFileLayoutExpectedOutputDex[] = "qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC" "AAAAdQEAAAAQAAABAAAAjAEAAA=="; +// Dex file with catch handler unreferenced by try blocks. +// Constructed by building a dex file with try/catch blocks and hex editing. +static const char kUnreferencedCatchHandlerInputDex[] = + "ZGV4CjAzNQD+exd52Y0f9nY5x5GmInXq5nXrO6Kl2RV4AwAAcAAAAHhWNBIAAAAAAAAAANgCAAAS" + "AAAAcAAAAAgAAAC4AAAAAwAAANgAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAA0AgAARAEAANYB" + "AADeAQAA5gEAAO4BAAAAAgAADwIAACYCAAA9AgAAUQIAAGUCAAB5AgAAfwIAAIUCAACIAgAAjAIA" + "AKECAACnAgAArAIAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAwAAAAOAAAADAAAAAYAAAAAAAAA" + "DQAAAAYAAADIAQAADQAAAAYAAADQAQAABQABABAAAAAAAAAAAAAAAAAAAgAPAAAAAQABABEAAAAD" + "AAAAAAAAAAAAAAABAAAAAwAAAAAAAAADAAAAAAAAAMgCAAAAAAAAAQABAAEAAAC1AgAABAAAAHAQ" + "AwAAAA4AAwABAAIAAgC6AgAAIQAAAGIAAAAaAQoAbiACABAAYgAAABoBCwBuIAIAEAAOAA0AYgAA" + "ABoBAQBuIAIAEAAo8A0AYgAAABoBAgBuIAIAEAAo7gAAAAAAAAcAAQAHAAAABwABAAIBAg8BAhgA" + "AQAAAAQAAAABAAAABwAGPGluaXQ+AAZDYXRjaDEABkNhdGNoMgAQSGFuZGxlclRlc3QuamF2YQAN" + "TEhhbmRsZXJUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABVMamF2YS9sYW5nL0V4Y2VwdGlv" + "bjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5" + "c3RlbTsABFRyeTEABFRyeTIAAVYAAlZMABNbTGphdmEvbGFuZy9TdHJpbmc7AARtYWluAANvdXQA" + "B3ByaW50bG4AAQAHDgAEAQAHDn17AncdHoseAAAAAgAAgYAExAIBCdwCAAANAAAAAAAAAAEAAAAA" + "AAAAAQAAABIAAABwAAAAAgAAAAgAAAC4AAAAAwAAAAMAAADYAAAABAAAAAEAAAD8AAAABQAAAAQA" + "AAAEAQAABgAAAAEAAAAkAQAAASAAAAIAAABEAQAAARAAAAIAAADIAQAAAiAAABIAAADWAQAAAyAA" + "AAIAAAC1AgAAACAAAAEAAADIAgAAABAAAAEAAADYAgAA"; + // Dex file with multiple code items that have the same debug_info_off_. Constructed by a modified // dexlayout on XandY. static const char kDexFileDuplicateOffset[] = @@ -100,25 +120,30 @@ static const char kNullSetRefListElementInputDex[] = "ASAAAAIAAACEAQAABiAAAAIAAACwAQAAARAAAAIAAADYAQAAAiAAABIAAADoAQAAAyAAAAIAAADw" "AgAABCAAAAIAAAD8AgAAACAAAAIAAAAIAwAAABAAAAEAAAAgAwAA"; -// Dex file with catch handler unreferenced by try blocks. -// Constructed by building a dex file with try/catch blocks and hex editing. -static const char kUnreferencedCatchHandlerInputDex[] = - "ZGV4CjAzNQD+exd52Y0f9nY5x5GmInXq5nXrO6Kl2RV4AwAAcAAAAHhWNBIAAAAAAAAAANgCAAAS" - "AAAAcAAAAAgAAAC4AAAAAwAAANgAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAA0AgAARAEAANYB" - "AADeAQAA5gEAAO4BAAAAAgAADwIAACYCAAA9AgAAUQIAAGUCAAB5AgAAfwIAAIUCAACIAgAAjAIA" - "AKECAACnAgAArAIAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAwAAAAOAAAADAAAAAYAAAAAAAAA" - "DQAAAAYAAADIAQAADQAAAAYAAADQAQAABQABABAAAAAAAAAAAAAAAAAAAgAPAAAAAQABABEAAAAD" - "AAAAAAAAAAAAAAABAAAAAwAAAAAAAAADAAAAAAAAAMgCAAAAAAAAAQABAAEAAAC1AgAABAAAAHAQ" - "AwAAAA4AAwABAAIAAgC6AgAAIQAAAGIAAAAaAQoAbiACABAAYgAAABoBCwBuIAIAEAAOAA0AYgAA" - "ABoBAQBuIAIAEAAo8A0AYgAAABoBAgBuIAIAEAAo7gAAAAAAAAcAAQAHAAAABwABAAIBAg8BAhgA" - "AQAAAAQAAAABAAAABwAGPGluaXQ+AAZDYXRjaDEABkNhdGNoMgAQSGFuZGxlclRlc3QuamF2YQAN" - "TEhhbmRsZXJUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABVMamF2YS9sYW5nL0V4Y2VwdGlv" - "bjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5" - "c3RlbTsABFRyeTEABFRyeTIAAVYAAlZMABNbTGphdmEvbGFuZy9TdHJpbmc7AARtYWluAANvdXQA" - "B3ByaW50bG4AAQAHDgAEAQAHDn17AncdHoseAAAAAgAAgYAExAIBCdwCAAANAAAAAAAAAAEAAAAA" - "AAAAAQAAABIAAABwAAAAAgAAAAgAAAC4AAAAAwAAAAMAAADYAAAABAAAAAEAAAD8AAAABQAAAAQA" - "AAAEAQAABgAAAAEAAAAkAQAAASAAAAIAAABEAQAAARAAAAIAAADIAQAAAiAAABIAAADWAQAAAyAA" - "AAIAAAC1AgAAACAAAAEAAADIAgAAABAAAAEAAADYAgAA"; +// Dex file with shared empty class data item for multiple class defs. +// Constructing by building a dex file with multiple classes and hex editing. +static const char kMultiClassDataInputDex[] = + "ZGV4CjAzNQALJgF9TtnLq748xVe/+wyxETrT9lTEiW6YAQAAcAAAAHhWNBIAAAAAAAAAADQBAAAI" + "AAAAcAAAAAQAAACQAAAAAAAAAAAAAAACAAAAoAAAAAAAAAAAAAAAAgAAALAAAACoAAAA8AAAAPAA" + "AAD4AAAAAAEAAAMBAAAIAQAADQEAACEBAAAkAQAAAgAAAAMAAAAEAAAABQAAAAEAAAAGAAAAAgAA" + "AAcAAAABAAAAAQYAAAMAAAAAAAAAAAAAAAAAAAAnAQAAAAAAAAIAAAABBgAAAwAAAAAAAAABAAAA" + "AAAAACcBAAAAAAAABkEuamF2YQAGQi5qYXZhAAFJAANMQTsAA0xCOwASTGphdmEvbGFuZy9PYmpl" + "Y3Q7AAFhAAFiAAAAAAABAAAAARkAAAAIAAAAAAAAAAEAAAAAAAAAAQAAAAgAAABwAAAAAgAAAAQA" + "AACQAAAABAAAAAIAAACgAAAABgAAAAIAAACwAAAAAiAAAAgAAADwAAAAACAAAAIAAAAnAQAAABAA" + "AAEAAAA0AQAA"; + +// Dex file with code info followed by non 4-byte aligned section. +// Constructed a dex file with code info followed by string data and hex edited. +static const char kUnalignedCodeInfoInputDex[] = + "ZGV4CjAzNQDXJzXNb4iWn2SLhmLydW/8h1K9moERIw7UAQAAcAAAAHhWNBIAAAAAAAAAAEwBAAAG" + "AAAAcAAAAAMAAACIAAAAAQAAAJQAAAAAAAAAAAAAAAMAAACgAAAAAQAAALgAAAD8AAAA2AAAAAIB" + "AAAKAQAAEgEAABcBAAArAQAALgEAAAIAAAADAAAABAAAAAQAAAACAAAAAAAAAAAAAAAAAAAAAAAA" + "AAUAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAABAAAAAAAAADsBAAAAAAAAAQABAAEAAAAxAQAA" + "BAAAAHAQAgAAAA4AAQABAAAAAAA2AQAAAQAAAA4ABjxpbml0PgAGQS5qYXZhAANMQTsAEkxqYXZh" + "L2xhbmcvT2JqZWN0OwABVgABYQABAAcOAAMABw4AAAABAQCBgATYAQEB8AEAAAALAAAAAAAAAAEA" + "AAAAAAAAAQAAAAYAAABwAAAAAgAAAAMAAACIAAAAAwAAAAEAAACUAAAABQAAAAMAAACgAAAABgAA" + "AAEAAAC4AAAAASAAAAIAAADYAAAAAiAAAAYAAAACAQAAAyAAAAIAAAAxAQAAACAAAAEAAAA7AQAA" + "ABAAAAEAAABMAQAA"; static void WriteBase64ToFile(const char* base64, File* file) { // Decode base64. @@ -314,6 +339,12 @@ TEST_F(DexLayoutTest, DexFileLayout) { ASSERT_TRUE(DexFileLayoutExec(&error_msg)) << error_msg; } +TEST_F(DexLayoutTest, UnreferencedCatchHandler) { + // Disable test on target. + TEST_DISABLED_FOR_TARGET(); + std::string error_msg; + ASSERT_TRUE(UnreferencedCatchHandlerExec(&error_msg)) << error_msg; +} TEST_F(DexLayoutTest, DuplicateOffset) { ScratchFile temp; WriteBase64ToFile(kDexFileDuplicateOffset, temp.GetFile()); @@ -351,11 +382,40 @@ TEST_F(DexLayoutTest, NullSetRefListElement) { } } -TEST_F(DexLayoutTest, UnreferencedCatchHandler) { - // Disable test on target. - TEST_DISABLED_FOR_TARGET(); +TEST_F(DexLayoutTest, MultiClassData) { + ScratchFile temp; + WriteBase64ToFile(kMultiClassDataInputDex, temp.GetFile()); + ScratchFile temp2; + WriteBase64ToFile(kDexFileLayoutInputProfile, temp2.GetFile()); + EXPECT_EQ(temp.GetFile()->Flush(), 0); + std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout"; + EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path"; + std::vector<std::string> dexlayout_exec_argv = + { dexlayout, "-p", temp2.GetFilename(), "-o", "/dev/null", temp.GetFilename() }; std::string error_msg; - ASSERT_TRUE(UnreferencedCatchHandlerExec(&error_msg)) << error_msg; + const bool result = ::art::Exec(dexlayout_exec_argv, &error_msg); + EXPECT_TRUE(result); + if (!result) { + LOG(ERROR) << "Error " << error_msg; + } +} + +TEST_F(DexLayoutTest, UnalignedCodeInfo) { + ScratchFile temp; + WriteBase64ToFile(kUnalignedCodeInfoInputDex, temp.GetFile()); + ScratchFile temp2; + WriteBase64ToFile(kDexFileLayoutInputProfile, temp2.GetFile()); + EXPECT_EQ(temp.GetFile()->Flush(), 0); + std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout"; + EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path"; + std::vector<std::string> dexlayout_exec_argv = + { dexlayout, "-p", temp2.GetFilename(), "-o", "/dev/null", temp.GetFilename() }; + std::string error_msg; + const bool result = ::art::Exec(dexlayout_exec_argv, &error_msg); + EXPECT_TRUE(result); + if (!result) { + LOG(ERROR) << "Error " << error_msg; + } } } // namespace art diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 53be30eafc..37963e49e7 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -3961,7 +3961,14 @@ void Heap::AddModUnionTable(accounting::ModUnionTable* mod_union_table) { void Heap::CheckPreconditionsForAllocObject(ObjPtr<mirror::Class> c, size_t byte_count) { CHECK(c == nullptr || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) || - (c->IsVariableSize() || c->GetObjectSize() == byte_count)) << c->GetClassFlags(); + (c->IsVariableSize() || c->GetObjectSize() == byte_count)) + << "ClassFlags=" << c->GetClassFlags() + << " IsClassClass=" << c->IsClassClass() + << " byte_count=" << byte_count + << " IsVariableSize=" << c->IsVariableSize() + << " ObjectSize=" << c->GetObjectSize() + << " sizeof(Class)=" << sizeof(mirror::Class) + << " klass=" << c.Ptr(); CHECK_GE(byte_count, sizeof(mirror::Object)); } diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index e59c4bb28e..495fec7a48 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -1111,7 +1111,9 @@ void Hprof::DumpHeapObject(mirror::Object* obj) { if (space != nullptr) { if (space->IsZygoteSpace()) { heap_type = HPROF_HEAP_ZYGOTE; - } else if (space->IsImageSpace()) { + } else if (space->IsImageSpace() && heap->ObjectIsInBootImageSpace(obj)) { + // Only count objects in the boot image as HPROF_HEAP_IMAGE, this leaves app image objects as + // HPROF_HEAP_APP. b/35762934 heap_type = HPROF_HEAP_IMAGE; } } else { diff --git a/runtime/openjdkjvmti/ti_field.cc b/runtime/openjdkjvmti/ti_field.cc index 8c3f2fffbd..1e5fbda35b 100644 --- a/runtime/openjdkjvmti/ti_field.cc +++ b/runtime/openjdkjvmti/ti_field.cc @@ -88,7 +88,6 @@ jvmtiError FieldUtil::GetFieldName(jvmtiEnv* env, *signature_ptr = signature_copy.get(); } - // TODO: Support generic signature. if (generic_ptr != nullptr) { *generic_ptr = nullptr; if (!art_field->GetDeclaringClass()->IsProxyClass()) { diff --git a/runtime/openjdkjvmti/ti_heap.cc b/runtime/openjdkjvmti/ti_heap.cc index eb2cbbd60a..976ce66f11 100644 --- a/runtime/openjdkjvmti/ti_heap.cc +++ b/runtime/openjdkjvmti/ti_heap.cc @@ -159,32 +159,19 @@ jint ReportPrimitiveArray(art::ObjPtr<art::mirror::Object> obj, return 0; } -} // namespace - -struct IterateThroughHeapData { - IterateThroughHeapData(HeapUtil* _heap_util, - jvmtiEnv* _env, - jint heap_filter, - art::ObjPtr<art::mirror::Class> klass, - const jvmtiHeapCallbacks* _callbacks, - const void* _user_data) - : heap_util(_heap_util), - filter_klass(klass), - env(_env), - callbacks(_callbacks), - user_data(_user_data), - filter_out_tagged((heap_filter & JVMTI_HEAP_FILTER_TAGGED) != 0), +struct HeapFilter { + explicit HeapFilter(jint heap_filter) + : filter_out_tagged((heap_filter & JVMTI_HEAP_FILTER_TAGGED) != 0), filter_out_untagged((heap_filter & JVMTI_HEAP_FILTER_UNTAGGED) != 0), filter_out_class_tagged((heap_filter & JVMTI_HEAP_FILTER_CLASS_TAGGED) != 0), filter_out_class_untagged((heap_filter & JVMTI_HEAP_FILTER_CLASS_UNTAGGED) != 0), any_filter(filter_out_tagged || filter_out_untagged || filter_out_class_tagged || - filter_out_class_untagged), - stop_reports(false) { + filter_out_class_untagged) { } - bool ShouldReportByHeapFilter(jlong tag, jlong class_tag) { + bool ShouldReportByHeapFilter(jlong tag, jlong class_tag) const { if (!any_filter) { return true; } @@ -201,16 +188,37 @@ struct IterateThroughHeapData { return true; } - HeapUtil* heap_util; - art::ObjPtr<art::mirror::Class> filter_klass; - jvmtiEnv* env; - const jvmtiHeapCallbacks* callbacks; - const void* user_data; const bool filter_out_tagged; const bool filter_out_untagged; const bool filter_out_class_tagged; const bool filter_out_class_untagged; const bool any_filter; +}; + +} // namespace + +struct IterateThroughHeapData { + IterateThroughHeapData(HeapUtil* _heap_util, + jvmtiEnv* _env, + art::ObjPtr<art::mirror::Class> klass, + jint _heap_filter, + const jvmtiHeapCallbacks* _callbacks, + const void* _user_data) + : heap_util(_heap_util), + heap_filter(_heap_filter), + filter_klass(klass), + env(_env), + callbacks(_callbacks), + user_data(_user_data), + stop_reports(false) { + } + + HeapUtil* heap_util; + const HeapFilter heap_filter; + art::ObjPtr<art::mirror::Class> filter_klass; + jvmtiEnv* env; + const jvmtiHeapCallbacks* callbacks; + const void* user_data; bool stop_reports; }; @@ -233,7 +241,7 @@ static void IterateThroughHeapObjectCallback(art::mirror::Object* obj, void* arg ithd->heap_util->GetTags()->GetTag(klass.Ptr(), &class_tag); // For simplicity, even if we find a tag = 0, assume 0 = not tagged. - if (!ithd->ShouldReportByHeapFilter(tag, class_tag)) { + if (!ithd->heap_filter.ShouldReportByHeapFilter(tag, class_tag)) { return; } @@ -298,8 +306,8 @@ jvmtiError HeapUtil::IterateThroughHeap(jvmtiEnv* env, IterateThroughHeapData ithd(this, env, - heap_filter, soa.Decode<art::mirror::Class>(klass), + heap_filter, callbacks, user_data); @@ -315,12 +323,14 @@ class FollowReferencesHelper FINAL { art::ObjPtr<art::mirror::Object> initial_object, const jvmtiHeapCallbacks* callbacks, art::ObjPtr<art::mirror::Class> class_filter, + jint heap_filter, const void* user_data) : env(jvmti_env), tag_table_(h->GetTags()), initial_object_(initial_object), callbacks_(callbacks), class_filter_(class_filter), + heap_filter_(heap_filter), user_data_(user_data), start_(0), stop_reports_(false) { @@ -767,10 +777,15 @@ class FollowReferencesHelper FINAL { } const jlong class_tag = tag_table_->GetTagOrZero(referree->GetClass()); + jlong tag = tag_table_->GetTagOrZero(referree); + + if (!heap_filter_.ShouldReportByHeapFilter(tag, class_tag)) { + return JVMTI_VISIT_OBJECTS; + } + const jlong referrer_class_tag = referrer == nullptr ? 0 : tag_table_->GetTagOrZero(referrer->GetClass()); const jlong size = static_cast<jlong>(referree->SizeOf()); - jlong tag = tag_table_->GetTagOrZero(referree); jlong saved_tag = tag; jlong referrer_tag = 0; jlong saved_referrer_tag = 0; @@ -816,6 +831,7 @@ class FollowReferencesHelper FINAL { art::ObjPtr<art::mirror::Object> initial_object_; const jvmtiHeapCallbacks* callbacks_; art::ObjPtr<art::mirror::Class> class_filter_; + const HeapFilter heap_filter_; const void* user_data_; std::vector<art::mirror::Object*> worklist_; @@ -830,7 +846,7 @@ class FollowReferencesHelper FINAL { }; jvmtiError HeapUtil::FollowReferences(jvmtiEnv* env, - jint heap_filter ATTRIBUTE_UNUSED, + jint heap_filter, jclass klass, jobject initial_object, const jvmtiHeapCallbacks* callbacks, @@ -860,6 +876,7 @@ jvmtiError HeapUtil::FollowReferences(jvmtiEnv* env, self->DecodeJObject(initial_object), callbacks, class_filter, + heap_filter, user_data); frh.Init(); frh.Work(); diff --git a/runtime/openjdkjvmti/ti_phase.cc b/runtime/openjdkjvmti/ti_phase.cc index 60371cfafe..e494cb6530 100644 --- a/runtime/openjdkjvmti/ti_phase.cc +++ b/runtime/openjdkjvmti/ti_phase.cc @@ -56,7 +56,6 @@ struct PhaseUtil::PhaseCallback : public art::RuntimePhaseCallback { } void NextRuntimePhase(RuntimePhase phase) REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE { - // TODO: Events. switch (phase) { case RuntimePhase::kInitialAgents: PhaseUtil::current_phase_ = JVMTI_PHASE_PRIMORDIAL; diff --git a/runtime/openjdkjvmti/ti_search.cc b/runtime/openjdkjvmti/ti_search.cc index df80f85ed8..f51a98f976 100644 --- a/runtime/openjdkjvmti/ti_search.cc +++ b/runtime/openjdkjvmti/ti_search.cc @@ -212,7 +212,6 @@ jvmtiError SearchUtil::AddToBootstrapClassLoaderSearch(jvmtiEnv* env ATTRIBUTE_U return ERR(WRONG_PHASE); } if (current->GetClassLinker() == nullptr) { - // TODO: Support boot classpath change in OnLoad. return ERR(WRONG_PHASE); } if (segment == nullptr) { diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt index e81cb9c50c..46805d7272 100644 --- a/test/913-heaps/expected.txt +++ b/test/913-heaps/expected.txt @@ -119,3 +119,178 @@ root@root --(thread)--> 1@1000 [size=16, length=-1] 5@1002 --(field@24)--> 6@1000 [size=16, length=-1] 5@1002 --(field@28)--> 1@1000 [size=16, length=-1] --- +--- heap_filter --- +---- tagged objects +--- +--- +--- +--- +---- untagged objects +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] +root@root --(system-class)--> 2@0 [size=32, length=-1] +root@root --(thread)--> 3000@0 [size=132, length=-1] +0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] +1001@0 --(superclass)--> 1000@0 [size=123, length=-1] +1002@0 --(interface)--> 2001@0 [size=124, length=-1] +1002@0 --(superclass)--> 1001@0 [size=123, length=-1] +1@1000 --(class)--> 1000@0 [size=123, length=-1] +1@1000 --(field@12)--> 3@1001 [size=24, length=-1] +1@1000 --(field@8)--> 2@1000 [size=16, length=-1] +2001@0 --(interface)--> 2000@0 [size=124, length=-1] +2@1000 --(class)--> 1000@0 [size=123, length=-1] +3@1001 --(class)--> 1001@0 [size=123, length=-1] +3@1001 --(field@16)--> 4@1000 [size=16, length=-1] +3@1001 --(field@20)--> 5@1002 [size=32, length=-1] +4@1000 --(class)--> 1000@0 [size=123, length=-1] +5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@24)--> 6@1000 [size=16, length=-1] +5@1002 --(field@28)--> 1@1000 [size=16, length=-1] +6@1000 --(class)--> 1000@0 [size=123, length=-1] +--- +1001@0 --(superclass)--> 1000@0 [size=123, length=-1] +1002@0 --(interface)--> 2001@0 [size=124, length=-1] +1002@0 --(superclass)--> 1001@0 [size=123, length=-1] +1@1000 --(class)--> 1000@0 [size=123, length=-1] +1@1000 --(field@12)--> 3@1001 [size=24, length=-1] +1@1000 --(field@8)--> 2@1000 [size=16, length=-1] +2001@0 --(interface)--> 2000@0 [size=124, length=-1] +2@1000 --(class)--> 1000@0 [size=123, length=-1] +3@1001 --(class)--> 1001@0 [size=123, length=-1] +3@1001 --(field@16)--> 4@1000 [size=16, length=-1] +3@1001 --(field@20)--> 5@1002 [size=32, length=-1] +4@1000 --(class)--> 1000@0 [size=123, length=-1] +5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@24)--> 6@1000 [size=16, length=-1] +5@1002 --(field@28)--> 1@1000 [size=16, length=-1] +6@1000 --(class)--> 1000@0 [size=123, length=-1] +--- +root@root --(jni-global)--> 1@1000 [size=16, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(system-class)--> 2@0 [size=32, length=-1] +root@root --(thread)--> 1@1000 [size=16, length=-1] +root@root --(thread)--> 3000@0 [size=132, length=-1] +1001@0 --(superclass)--> 1000@0 [size=123, length=-1] +1002@0 --(interface)--> 2001@0 [size=124, length=-1] +1002@0 --(superclass)--> 1001@0 [size=123, length=-1] +1@1000 --(class)--> 1000@0 [size=123, length=-1] +1@1000 --(field@12)--> 3@1001 [size=24, length=-1] +1@1000 --(field@8)--> 2@1000 [size=16, length=-1] +2001@0 --(interface)--> 2000@0 [size=124, length=-1] +2@1000 --(class)--> 1000@0 [size=123, length=-1] +3@1001 --(class)--> 1001@0 [size=123, length=-1] +3@1001 --(field@16)--> 4@1000 [size=16, length=-1] +3@1001 --(field@20)--> 5@1002 [size=32, length=-1] +4@1000 --(class)--> 1000@0 [size=123, length=-1] +5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@24)--> 6@1000 [size=16, length=-1] +5@1002 --(field@28)--> 1@1000 [size=16, length=-1] +6@1000 --(class)--> 1000@0 [size=123, length=-1] +--- +1001@0 --(superclass)--> 1000@0 [size=123, length=-1] +1002@0 --(interface)--> 2001@0 [size=124, length=-1] +1002@0 --(superclass)--> 1001@0 [size=123, length=-1] +1@1000 --(class)--> 1000@0 [size=123, length=-1] +1@1000 --(field@12)--> 3@1001 [size=24, length=-1] +1@1000 --(field@8)--> 2@1000 [size=16, length=-1] +2001@0 --(interface)--> 2000@0 [size=124, length=-1] +2@1000 --(class)--> 1000@0 [size=123, length=-1] +3@1001 --(class)--> 1001@0 [size=123, length=-1] +3@1001 --(field@16)--> 4@1000 [size=16, length=-1] +3@1001 --(field@20)--> 5@1002 [size=32, length=-1] +4@1000 --(class)--> 1000@0 [size=123, length=-1] +5@1002 --(class)--> 1002@0 [size=123, length=-1] +5@1002 --(field@24)--> 6@1000 [size=16, length=-1] +5@1002 --(field@28)--> 1@1000 [size=16, length=-1] +6@1000 --(class)--> 1000@0 [size=123, length=-1] +--- +---- tagged classes +root@root --(stack-local[id=1,tag=3000,depth=3,method=doFollowReferencesTest,vreg=1,location= 28])--> 3000@0 [size=132, length=-1] +root@root --(system-class)--> 2@0 [size=32, length=-1] +root@root --(thread)--> 3000@0 [size=132, length=-1] +1001@0 --(superclass)--> 1000@0 [size=123, length=-1] +1002@0 --(interface)--> 2001@0 [size=124, length=-1] +1002@0 --(superclass)--> 1001@0 [size=123, length=-1] +1@1000 --(class)--> 1000@0 [size=123, length=-1] +2001@0 --(interface)--> 2000@0 [size=124, length=-1] +2@1000 --(class)--> 1000@0 [size=123, length=-1] +3@1001 --(class)--> 1001@0 [size=123, length=-1] +4@1000 --(class)--> 1000@0 [size=123, length=-1] +5@1002 --(class)--> 1002@0 [size=123, length=-1] +6@1000 --(class)--> 1000@0 [size=123, length=-1] +--- +1001@0 --(superclass)--> 1000@0 [size=123, length=-1] +1002@0 --(interface)--> 2001@0 [size=124, length=-1] +1002@0 --(superclass)--> 1001@0 [size=123, length=-1] +1@1000 --(class)--> 1000@0 [size=123, length=-1] +2001@0 --(interface)--> 2000@0 [size=124, length=-1] +2@1000 --(class)--> 1000@0 [size=123, length=-1] +3@1001 --(class)--> 1001@0 [size=123, length=-1] +4@1000 --(class)--> 1000@0 [size=123, length=-1] +5@1002 --(class)--> 1002@0 [size=123, length=-1] +6@1000 --(class)--> 1000@0 [size=123, length=-1] +--- +root@root --(system-class)--> 2@0 [size=32, length=-1] +root@root --(thread)--> 3000@0 [size=132, length=-1] +1001@0 --(superclass)--> 1000@0 [size=123, length=-1] +1002@0 --(interface)--> 2001@0 [size=124, length=-1] +1002@0 --(superclass)--> 1001@0 [size=123, length=-1] +1@1000 --(class)--> 1000@0 [size=123, length=-1] +2001@0 --(interface)--> 2000@0 [size=124, length=-1] +2@1000 --(class)--> 1000@0 [size=123, length=-1] +3@1001 --(class)--> 1001@0 [size=123, length=-1] +4@1000 --(class)--> 1000@0 [size=123, length=-1] +5@1002 --(class)--> 1002@0 [size=123, length=-1] +6@1000 --(class)--> 1000@0 [size=123, length=-1] +--- +1001@0 --(superclass)--> 1000@0 [size=123, length=-1] +1002@0 --(interface)--> 2001@0 [size=124, length=-1] +1002@0 --(superclass)--> 1001@0 [size=123, length=-1] +1@1000 --(class)--> 1000@0 [size=123, length=-1] +2001@0 --(interface)--> 2000@0 [size=124, length=-1] +2@1000 --(class)--> 1000@0 [size=123, length=-1] +3@1001 --(class)--> 1001@0 [size=123, length=-1] +4@1000 --(class)--> 1000@0 [size=123, length=-1] +5@1002 --(class)--> 1002@0 [size=123, length=-1] +6@1000 --(class)--> 1000@0 [size=123, length=-1] +--- +---- untagged classes +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] +0@0 --(array-element@0)--> 1@1000 [size=16, length=-1] +1@1000 --(field@12)--> 3@1001 [size=24, length=-1] +1@1000 --(field@8)--> 2@1000 [size=16, length=-1] +3@1001 --(field@16)--> 4@1000 [size=16, length=-1] +3@1001 --(field@20)--> 5@1002 [size=32, length=-1] +5@1002 --(field@24)--> 6@1000 [size=16, length=-1] +5@1002 --(field@28)--> 1@1000 [size=16, length=-1] +--- +1@1000 --(field@12)--> 3@1001 [size=24, length=-1] +1@1000 --(field@8)--> 2@1000 [size=16, length=-1] +3@1001 --(field@16)--> 4@1000 [size=16, length=-1] +3@1001 --(field@20)--> 5@1002 [size=32, length=-1] +5@1002 --(field@24)--> 6@1000 [size=16, length=-1] +5@1002 --(field@28)--> 1@1000 [size=16, length=-1] +--- +root@root --(jni-global)--> 1@1000 [size=16, length=-1] +root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] +root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 19])--> 1@1000 [size=16, length=-1] +root@root --(thread)--> 1@1000 [size=16, length=-1] +1@1000 --(field@12)--> 3@1001 [size=24, length=-1] +1@1000 --(field@8)--> 2@1000 [size=16, length=-1] +3@1001 --(field@16)--> 4@1000 [size=16, length=-1] +3@1001 --(field@20)--> 5@1002 [size=32, length=-1] +5@1002 --(field@24)--> 6@1000 [size=16, length=-1] +5@1002 --(field@28)--> 1@1000 [size=16, length=-1] +--- +1@1000 --(field@12)--> 3@1001 [size=24, length=-1] +1@1000 --(field@8)--> 2@1000 [size=16, length=-1] +3@1001 --(field@16)--> 4@1000 [size=16, length=-1] +3@1001 --(field@20)--> 5@1002 [size=32, length=-1] +5@1002 --(field@24)--> 6@1000 [size=16, length=-1] +5@1002 --(field@28)--> 1@1000 [size=16, length=-1] +--- diff --git a/test/913-heaps/src/Main.java b/test/913-heaps/src/Main.java index 7a91d1f325..df89f347e0 100644 --- a/test/913-heaps/src/Main.java +++ b/test/913-heaps/src/Main.java @@ -31,6 +31,17 @@ public class Main { // Test klass filter. System.out.println("--- klass ---"); new TestConfig(A.class, 0).doFollowReferencesTest(); + + // Test heap filter. + System.out.println("--- heap_filter ---"); + System.out.println("---- tagged objects"); + new TestConfig(null, 0x4).doFollowReferencesTest(); + System.out.println("---- untagged objects"); + new TestConfig(null, 0x8).doFollowReferencesTest(); + System.out.println("---- tagged classes"); + new TestConfig(null, 0x10).doFollowReferencesTest(); + System.out.println("---- untagged classes"); + new TestConfig(null, 0x20).doFollowReferencesTest(); } public static void doTest() throws Exception { |