diff options
| -rw-r--r-- | build/art.go | 4 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 2 | ||||
| -rw-r--r-- | dex2oat/dex2oat.cc | 2 | ||||
| -rw-r--r-- | dex2oat/linker/image_test.h | 16 | ||||
| -rw-r--r-- | dex2oat/linker/oat_writer.cc | 103 | ||||
| -rw-r--r-- | dex2oat/linker/oat_writer_test.cc | 18 | ||||
| -rw-r--r-- | oatdump/oatdump.cc | 66 | ||||
| -rw-r--r-- | runtime/art_method.cc | 23 | ||||
| -rw-r--r-- | runtime/art_method.h | 4 | ||||
| -rw-r--r-- | runtime/globals.h | 6 | ||||
| -rw-r--r-- | runtime/oat_file.cc | 10 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.cc | 15 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 19 | ||||
| -rw-r--r-- | tools/ahat/etc/test-dump.pro | 9 | ||||
| -rw-r--r-- | tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java | 17 | ||||
| -rw-r--r-- | tools/ahat/src/test-dump/DumpedStuff.java | 160 | ||||
| -rw-r--r-- | tools/ahat/src/test-dump/Main.java | 137 | ||||
| -rw-r--r-- | tools/ahat/src/test-dump/SuperDumpedStuff.java | 36 | ||||
| -rw-r--r-- | tools/ahat/src/test/com/android/ahat/ProguardMapTest.java | 13 | ||||
| -rw-r--r-- | tools/ahat/src/test/com/android/ahat/SiteTest.java | 69 |
21 files changed, 352 insertions, 379 deletions
diff --git a/build/art.go b/build/art.go index 4e48d2d932..5704b43834 100644 --- a/build/art.go +++ b/build/art.go @@ -46,10 +46,6 @@ func globalFlags(ctx android.BaseContext) ([]string, []string) { cflags = append(cflags, "-DART_USE_TLAB=1") } - if !envFalse(ctx, "ART_ENABLE_VDEX") { - cflags = append(cflags, "-DART_ENABLE_VDEX") - } - imtSize := envDefault(ctx, "ART_IMT_SIZE", "43") cflags = append(cflags, "-DIMT_SIZE="+imtSize) diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 4d846fa4ed..7adb196d14 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1672,7 +1672,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, compiler_driver_, codegen_, inline_stats_, - resolved_method->GetQuickenedInfo(class_linker->GetImagePointerSize()), + resolved_method->GetQuickenedInfo(), handles_); if (builder.BuildGraph() != kAnalysisSuccess) { diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 252d53823a..2bba985c34 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -1007,7 +1007,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, if (method != nullptr) { graph->SetArtMethod(method); ScopedObjectAccess soa(Thread::Current()); - interpreter_metadata = method->GetQuickenedInfo(class_linker->GetImagePointerSize()); + interpreter_metadata = method->GetQuickenedInfo(); } std::unique_ptr<CodeGenerator> codegen( diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 9fa7f697d9..8137fb1f11 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1565,7 +1565,7 @@ class Dex2Oat FINAL { // 2) when we have a vdex file, which means it was already verified. const bool verify = !DoDexLayoutOptimizations() && (input_vdex_file_ == nullptr); if (!oat_writers_[i]->WriteAndOpenDexFiles( - kIsVdexEnabled ? vdex_files_[i].get() : oat_files_[i].get(), + vdex_files_[i].get(), rodata_.back(), instruction_set_, instruction_set_features_.get(), diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index d3d42b98bb..cedbccf7cc 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -269,7 +269,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, std::unique_ptr<MemMap> cur_opened_dex_files_map; std::vector<std::unique_ptr<const DexFile>> cur_opened_dex_files; bool dex_files_ok = oat_writers[i]->WriteAndOpenDexFiles( - kIsVdexEnabled ? vdex_files[i].GetFile() : oat_files[i].GetFile(), + vdex_files[i].GetFile(), rodata.back(), driver->GetInstructionSet(), driver->GetInstructionSetFeatures(), @@ -293,14 +293,12 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, bool image_space_ok = writer->PrepareImageAddressSpace(); ASSERT_TRUE(image_space_ok); - if (kIsVdexEnabled) { - for (size_t i = 0, size = vdex_files.size(); i != size; ++i) { - std::unique_ptr<BufferedOutputStream> vdex_out = - std::make_unique<BufferedOutputStream>( - std::make_unique<FileOutputStream>(vdex_files[i].GetFile())); - oat_writers[i]->WriteVerifierDeps(vdex_out.get(), nullptr); - oat_writers[i]->WriteChecksumsAndVdexHeader(vdex_out.get()); - } + for (size_t i = 0, size = vdex_files.size(); i != size; ++i) { + std::unique_ptr<BufferedOutputStream> vdex_out = + std::make_unique<BufferedOutputStream>( + std::make_unique<FileOutputStream>(vdex_files[i].GetFile())); + oat_writers[i]->WriteVerifierDeps(vdex_out.get(), nullptr); + oat_writers[i]->WriteChecksumsAndVdexHeader(vdex_out.get()); } for (size_t i = 0, size = oat_files.size(); i != size; ++i) { diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 1eec59279e..d3e920f9a0 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -571,10 +571,9 @@ bool OatWriter::WriteAndOpenDexFiles( std::vector<std::unique_ptr<const DexFile>> dex_files; // Initialize VDEX and OAT headers. - if (kIsVdexEnabled) { - // Reserve space for Vdex header and checksums. - vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum); - } + + // Reserve space for Vdex header and checksums. + vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum); oat_size_ = InitOatHeader(instruction_set, instruction_set_features, dchecked_integral_cast<uint32_t>(oat_dex_files_.size()), @@ -582,28 +581,12 @@ bool OatWriter::WriteAndOpenDexFiles( ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get()); - if (kIsVdexEnabled) { - std::unique_ptr<BufferedOutputStream> vdex_out = - std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file)); - // Write DEX files into VDEX, mmap and open them. - if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) || - !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) { - return false; - } - } else { - DCHECK(!update_input_vdex); - // Write DEX files into OAT, mmap and open them. - if (!WriteDexFiles(oat_rodata, vdex_file, update_input_vdex) || - !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) { - return false; - } - - // Do a bulk checksum update for Dex[]. Doing it piece by piece would be - // difficult because we're not using the OutputStream directly. - if (!oat_dex_files_.empty()) { - size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_; - oat_header_->UpdateChecksum(dex_files_map->Begin(), size); - } + std::unique_ptr<BufferedOutputStream> vdex_out = + std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file)); + // Write DEX files into VDEX, mmap and open them. + if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) || + !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) { + return false; } // Write type lookup tables into the oat file. @@ -755,13 +738,12 @@ class OatWriter::OatDexMethodVisitor : public DexMethodVisitor { }; static bool HasCompiledCode(const CompiledMethod* method) { - // The dextodexcompiler puts the quickening info table into the CompiledMethod - // for simplicity. For such methods, we will emit an OatQuickMethodHeader - // only when vdex is disabled. - return method != nullptr && (!method->GetQuickCode().empty() || !kIsVdexEnabled); + return method != nullptr && !method->GetQuickCode().empty(); } static bool HasQuickeningInfo(const CompiledMethod* method) { + // The dextodexcompiler puts the quickening info table into the CompiledMethod + // for simplicity. return method != nullptr && method->GetQuickCode().empty() && !method->GetVmapTable().empty(); } @@ -1214,23 +1196,17 @@ class OatWriter::LayoutReserveOffsetCodeMethodVisitor : public OrderedMethodVisi // The code offset was 0 when the mapping/vmap table offset was set, so it's set // to 0-offset and we need to adjust it by code_offset. uint32_t code_offset = quick_code_offset - thumb_offset; - if (!compiled_method->GetQuickCode().empty()) { - // If the code is compiled, we write the offset of the stack map relative - // to the code, - if (vmap_table_offset != 0u) { - vmap_table_offset += code_offset; - DCHECK_LT(vmap_table_offset, code_offset); - } - if (method_info_offset != 0u) { - method_info_offset += code_offset; - DCHECK_LT(method_info_offset, code_offset); - } - } else { - CHECK(!kIsVdexEnabled); - // We write the offset of the quickening info relative to the code. + CHECK(!compiled_method->GetQuickCode().empty()); + // If the code is compiled, we write the offset of the stack map relative + // to the code. + if (vmap_table_offset != 0u) { vmap_table_offset += code_offset; DCHECK_LT(vmap_table_offset, code_offset); } + if (method_info_offset != 0u) { + method_info_offset += code_offset; + DCHECK_LT(method_info_offset, code_offset); + } uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); uint32_t core_spill_mask = compiled_method->GetCoreSpillMask(); uint32_t fp_spill_mask = compiled_method->GetFpSpillMask(); @@ -2593,10 +2569,6 @@ class OatWriter::WriteQuickeningIndicesMethodVisitor { }; bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) { - if (!kIsVdexEnabled) { - return true; - } - size_t initial_offset = vdex_size_; size_t start_offset = RoundUp(initial_offset, 4u); @@ -2655,10 +2627,6 @@ bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) { } bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) { - if (!kIsVdexEnabled) { - return true; - } - if (verifier_deps == nullptr) { // Nothing to write. Record the offset, but no need // for alignment. @@ -3170,23 +3138,17 @@ bool OatWriter::WriteDexFile(OutputStream* out, } // Update current size and account for the written data. - if (kIsVdexEnabled) { - DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_); - vdex_size_ += oat_dex_file->dex_file_size_; - } else { - DCHECK(!update_input_vdex); - DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_); - oat_size_ += oat_dex_file->dex_file_size_; - } + DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_); + vdex_size_ += oat_dex_file->dex_file_size_; size_dex_file_ += oat_dex_file->dex_file_size_; return true; } bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) { // Dex files are required to be 4 byte aligned. - size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_; + size_t initial_offset = vdex_size_; size_t start_offset = RoundUp(initial_offset, 4); - size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset); + size_t file_offset = start_offset; size_dex_file_alignment_ += start_offset - initial_offset; // Seek to the start of the dex file and flush any pending operations in the stream. @@ -3211,11 +3173,7 @@ bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex return false; } - if (kIsVdexEnabled) { - vdex_size_ = start_offset; - } else { - oat_size_ = start_offset; - } + vdex_size_ = start_offset; oat_dex_file->dex_file_offset_ = start_offset; return true; } @@ -3291,7 +3249,7 @@ bool OatWriter::WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file, ZipEntry* dex_file) { - size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_; + size_t start_offset = vdex_size_; DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent)); // Extract the dex file and get the extracted size. @@ -3384,7 +3342,7 @@ bool OatWriter::WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file, File* dex_file) { - size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_; + size_t start_offset = vdex_size_; DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent)); off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET); @@ -3480,7 +3438,7 @@ bool OatWriter::OpenDexFiles( } size_t map_offset = oat_dex_files_[0].dex_file_offset_; - size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset); + size_t length = vdex_size_ - map_offset; std::string error_msg; std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile( @@ -3488,7 +3446,7 @@ bool OatWriter::OpenDexFiles( PROT_READ | PROT_WRITE, MAP_SHARED, file->Fd(), - kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset), + map_offset, /* low_4gb */ false, file->GetPath().c_str(), &error_msg)); @@ -3692,9 +3650,6 @@ bool OatWriter::WriteDexLayoutSections( } bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) { - if (!kIsVdexEnabled) { - return true; - } // Write checksums off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet); if (actual_offset != sizeof(VdexFile::Header)) { diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index 1ee2e4efd0..022aa1b58c 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -192,7 +192,7 @@ class OatTest : public CommonCompilerTest { OutputStream* oat_rodata = elf_writer->StartRoData(); std::unique_ptr<MemMap> opened_dex_files_map; std::vector<std::unique_ptr<const DexFile>> opened_dex_files; - if (!oat_writer.WriteAndOpenDexFiles(kIsVdexEnabled ? vdex_file : oat_file, + if (!oat_writer.WriteAndOpenDexFiles(vdex_file, oat_rodata, compiler_driver_->GetInstructionSet(), compiler_driver_->GetInstructionSetFeatures(), @@ -224,15 +224,13 @@ class OatTest : public CommonCompilerTest { oat_writer.GetBssMethodsOffset(), oat_writer.GetBssRootsOffset()); - if (kIsVdexEnabled) { - std::unique_ptr<BufferedOutputStream> vdex_out = - std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file)); - if (!oat_writer.WriteVerifierDeps(vdex_out.get(), nullptr)) { - return false; - } - if (!oat_writer.WriteChecksumsAndVdexHeader(vdex_out.get())) { - return false; - } + std::unique_ptr<BufferedOutputStream> vdex_out = + std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file)); + if (!oat_writer.WriteVerifierDeps(vdex_out.get(), nullptr)) { + return false; + } + if (!oat_writer.WriteChecksumsAndVdexHeader(vdex_out.get())) { + return false; } if (!oat_writer.WriteRodata(oat_rodata)) { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index cd2e894e7d..5a3d34c7a5 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -573,46 +573,36 @@ class OatDumper { } if (options_.export_dex_location_) { - if (kIsVdexEnabled) { - std::string error_msg; - std::string vdex_filename = GetVdexFilename(oat_file_.GetLocation()); - if (!OS::FileExists(vdex_filename.c_str())) { - os << "File " << vdex_filename.c_str() << " does not exist\n"; - return false; - } + std::string error_msg; + std::string vdex_filename = GetVdexFilename(oat_file_.GetLocation()); + if (!OS::FileExists(vdex_filename.c_str())) { + os << "File " << vdex_filename.c_str() << " does not exist\n"; + return false; + } - DexFileUniqV vdex_dex_files; - std::unique_ptr<const VdexFile> vdex_file = OpenVdexUnquicken(vdex_filename, - &vdex_dex_files, - &error_msg); - if (vdex_file.get() == nullptr) { - os << "Failed to open vdex file: " << error_msg << "\n"; - return false; - } - if (oat_dex_files_.size() != vdex_dex_files.size()) { - os << "Dex files number in Vdex file does not match Dex files number in Oat file: " - << vdex_dex_files.size() << " vs " << oat_dex_files_.size() << '\n'; - return false; - } + DexFileUniqV vdex_dex_files; + std::unique_ptr<const VdexFile> vdex_file = OpenVdexUnquicken(vdex_filename, + &vdex_dex_files, + &error_msg); + if (vdex_file.get() == nullptr) { + os << "Failed to open vdex file: " << error_msg << "\n"; + return false; + } + if (oat_dex_files_.size() != vdex_dex_files.size()) { + os << "Dex files number in Vdex file does not match Dex files number in Oat file: " + << vdex_dex_files.size() << " vs " << oat_dex_files_.size() << '\n'; + return false; + } - size_t i = 0; - for (const auto& vdex_dex_file : vdex_dex_files) { - const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; - CHECK(oat_dex_file != nullptr); - CHECK(vdex_dex_file != nullptr); - if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get())) { - success = false; - } - i++; - } - } else { - for (size_t i = 0; i < oat_dex_files_.size(); i++) { - const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; - CHECK(oat_dex_file != nullptr); - if (!ExportDexFile(os, *oat_dex_file, /* vdex_dex_file */ nullptr)) { - success = false; - } + size_t i = 0; + for (const auto& vdex_dex_file : vdex_dex_files) { + const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; + CHECK(oat_dex_file != nullptr); + CHECK(vdex_dex_file != nullptr); + if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get())) { + success = false; } + i++; } } @@ -1367,7 +1357,7 @@ class OatDumper { vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset); size_t vmap_table_offset_limit = - (kIsVdexEnabled && IsMethodGeneratedByDexToDexCompiler(oat_method, code_item_accessor)) + IsMethodGeneratedByDexToDexCompiler(oat_method, code_item_accessor) ? oat_file_.GetVdexFile()->Size() : method_header->GetCode() - oat_file_.Begin(); if (vmap_table_offset >= vmap_table_offset_limit) { diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 0a108f93c5..fa0c501e31 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -563,23 +563,14 @@ bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> param return true; } -const uint8_t* ArtMethod::GetQuickenedInfo(PointerSize pointer_size) { - if (kIsVdexEnabled) { - const DexFile& dex_file = GetDeclaringClass()->GetDexFile(); - const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); - if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) { - return nullptr; - } - return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf( - dex_file, GetCodeItemOffset()); - } else { - bool found = false; - OatFile::OatMethod oat_method = FindOatMethodFor(this, pointer_size, &found); - if (!found || (oat_method.GetQuickCode() != nullptr)) { - return nullptr; - } - return oat_method.GetVmapTable(); +const uint8_t* ArtMethod::GetQuickenedInfo() { + const DexFile& dex_file = GetDeclaringClass()->GetDexFile(); + const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); + if (oat_dex_file == nullptr || (oat_dex_file->GetOatFile() == nullptr)) { + return nullptr; } + return oat_dex_file->GetOatFile()->GetVdexFile()->GetQuickenedInfoOf( + dex_file, GetCodeItemOffset()); } const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) { diff --git a/runtime/art_method.h b/runtime/art_method.h index c17eef1834..dca6f37254 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -464,7 +464,7 @@ class ArtMethod FINAL { // where the declaring class is treated as a weak reference (accessing it with // a read barrier would either prevent unloading the class, or crash the runtime if // the GC wants to unload it). - DCHECK(!IsNative()); + DCHECK(!IsNative<kWithoutReadBarrier>()); if (UNLIKELY(IsProxyMethod())) { return nullptr; } @@ -657,7 +657,7 @@ class ArtMethod FINAL { return hotness_count_; } - const uint8_t* GetQuickenedInfo(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); + const uint8_t* GetQuickenedInfo() REQUIRES_SHARED(Locks::mutator_lock_); // Returns the method header for the compiled code containing 'pc'. Note that runtime // methods will return null for this method, as they are not oat based. diff --git a/runtime/globals.h b/runtime/globals.h index 53932fd8cd..f14d6e95a6 100644 --- a/runtime/globals.h +++ b/runtime/globals.h @@ -125,12 +125,6 @@ static constexpr TraceClockSource kDefaultTraceClockSource = TraceClockSource::k static constexpr bool kDefaultMustRelocate = true; -#ifdef ART_ENABLE_VDEX -static constexpr bool kIsVdexEnabled = true; -#else -static constexpr bool kIsVdexEnabled = false; -#endif - // Size of a heap reference. static constexpr size_t kHeapReferenceSize = sizeof(uint32_t); diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 4429adeb81..69bd46d4c1 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -193,7 +193,7 @@ OatFileBase* OatFileBase::OpenOatFile(const std::string& vdex_filename, ret->PreLoad(); - if (kIsVdexEnabled && !ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) { + if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) { return nullptr; } @@ -233,7 +233,7 @@ OatFileBase* OatFileBase::OpenOatFile(int vdex_fd, std::string* error_msg) { std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(oat_location, executable)); - if (kIsVdexEnabled && !ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) { + if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) { return nullptr; } @@ -1275,7 +1275,7 @@ OatFile* OatFile::Open(const std::string& oat_filename, std::string vdex_filename = GetVdexFilename(oat_filename); // Check that the files even exist, fast-fail. - if (kIsVdexEnabled && !OS::FileExists(vdex_filename.c_str())) { + if (!OS::FileExists(vdex_filename.c_str())) { *error_msg = StringPrintf("File %s does not exist.", vdex_filename.c_str()); return nullptr; } else if (!OS::FileExists(oat_filename.c_str())) { @@ -1427,11 +1427,11 @@ const uint8_t* OatFile::BssEnd() const { } const uint8_t* OatFile::DexBegin() const { - return kIsVdexEnabled ? vdex_->Begin() : Begin(); + return vdex_->Begin(); } const uint8_t* OatFile::DexEnd() const { - return kIsVdexEnabled ? vdex_->End() : End(); + return vdex_->End(); } ArrayRef<ArtMethod*> OatFile::GetBssMethods() const { diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index b8a13da9b3..cd18ce102e 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -475,17 +475,10 @@ OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& // Verify the dex checksum. std::string error_msg; - if (kIsVdexEnabled) { - VdexFile* vdex = file.GetVdexFile(); - if (!DexChecksumUpToDate(*vdex, &error_msg)) { - LOG(ERROR) << error_msg; - return kOatDexOutOfDate; - } - } else { - if (!DexChecksumUpToDate(file, &error_msg)) { - LOG(ERROR) << error_msg; - return kOatDexOutOfDate; - } + VdexFile* vdex = file.GetVdexFile(); + if (!DexChecksumUpToDate(*vdex, &error_msg)) { + LOG(ERROR) << error_msg; + return kOatDexOutOfDate; } CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter(); diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 7694f45e78..a98da0f029 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -354,11 +354,6 @@ TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexVdexFd) { // Case: We have a DEX file and up-to-date (ODEX) VDEX file for it, but no // ODEX file. TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) { - // This test case is only meaningful if vdex is enabled. - if (!kIsVdexEnabled) { - return; - } - std::string dex_location = GetScratchDir() + "/VdexUpToDateNoOdex.jar"; std::string odex_location = GetOdexDir() + "/VdexUpToDateNoOdex.oat"; @@ -402,10 +397,6 @@ TEST_F(OatFileAssistantTest, EmptyVdexOdex) { // Case: We have a DEX file and up-to-date (OAT) VDEX file for it, but no OAT // file. TEST_F(OatFileAssistantTest, VdexUpToDateNoOat) { - // This test case is only meaningful if vdex is enabled. - if (!kIsVdexEnabled) { - return; - } if (IsExecutedAsRoot()) { // We cannot simulate non writable locations when executed as root: b/38000545. LOG(ERROR) << "Test skipped because it's running as root"; @@ -624,11 +615,6 @@ TEST_F(OatFileAssistantTest, OatDexOutOfDate) { // Case: We have a DEX file and an (ODEX) VDEX file out of date with respect // to the dex checksum, but no ODEX file. TEST_F(OatFileAssistantTest, VdexDexOutOfDate) { - // This test case is only meaningful if vdex is enabled. - if (!kIsVdexEnabled) { - return; - } - std::string dex_location = GetScratchDir() + "/VdexDexOutOfDate.jar"; std::string odex_location = GetOdexDir() + "/VdexDexOutOfDate.oat"; @@ -646,11 +632,6 @@ TEST_F(OatFileAssistantTest, VdexDexOutOfDate) { // Case: We have a MultiDEX (ODEX) VDEX file where the non-main multidex entry // is out of date and there is no corresponding ODEX file. TEST_F(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) { - // This test case is only meaningful if vdex is enabled. - if (!kIsVdexEnabled) { - return; - } - std::string dex_location = GetScratchDir() + "/VdexMultiDexNonMainOutOfDate.jar"; std::string odex_location = GetOdexDir() + "/VdexMultiDexNonMainOutOfDate.odex"; diff --git a/tools/ahat/etc/test-dump.pro b/tools/ahat/etc/test-dump.pro index 284e4b8621..296d411cfd 100644 --- a/tools/ahat/etc/test-dump.pro +++ b/tools/ahat/etc/test-dump.pro @@ -3,3 +3,12 @@ public static void main(java.lang.String[]); } +-keep public class SuperDumpedStuff { + public void allocateObjectAtUnObfSuperSite(); +} + +# Produce useful obfuscated stack traces so we can test useful deobfuscation +# of stack traces. +-renamesourcefileattribute SourceFile +-keepattributes SourceFile,LineNumberTable + diff --git a/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java b/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java index 131bbf3cf6..32bb209dc6 100644 --- a/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java +++ b/tools/ahat/src/main/com/android/ahat/proguard/ProguardMap.java @@ -88,12 +88,10 @@ public class ProguardMap { String key = obfuscatedMethodName + clearSignature; FrameData frame = mFrames.get(key); if (frame == null) { - return new Frame(obfuscatedMethodName, clearSignature, - obfuscatedFilename, obfuscatedLine); + frame = new FrameData(obfuscatedMethodName, 0); } return new Frame(frame.clearMethodName, clearSignature, - getFileName(clearClassName, frame.clearMethodName), - obfuscatedLine - frame.lineDelta); + getFileName(clearClassName), obfuscatedLine - frame.lineDelta); } } @@ -313,15 +311,10 @@ public class ProguardMap { return builder.toString(); } - // Return a file name for the given clear class name and method. - private static String getFileName(String clearClass, String method) { - int dot = method.lastIndexOf('.'); - if (dot != -1) { - clearClass = method.substring(0, dot); - } - + // Return a file name for the given clear class name. + private static String getFileName(String clearClass) { String filename = clearClass; - dot = filename.lastIndexOf('.'); + int dot = filename.lastIndexOf('.'); if (dot != -1) { filename = filename.substring(dot + 1); } diff --git a/tools/ahat/src/test-dump/DumpedStuff.java b/tools/ahat/src/test-dump/DumpedStuff.java new file mode 100644 index 0000000000..98ead07492 --- /dev/null +++ b/tools/ahat/src/test-dump/DumpedStuff.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import libcore.util.NativeAllocationRegistry; + +// We take a heap dump that includes a single instance of this +// DumpedStuff class. Objects stored as fields in this class can be easily +// found in the hprof dump by searching for the instance of the DumpedStuff +// class and reading the desired field. +public class DumpedStuff extends SuperDumpedStuff { + private void allocateObjectAtKnownSite() { + objectAllocatedAtKnownSite = new Object(); + allocateObjectAtKnownSubSite(); + allocateObjectAtObfSuperSite(); + allocateObjectAtUnObfSuperSite(); + allocateObjectAtOverriddenSite(); + } + + private void allocateObjectAtKnownSubSite() { + objectAllocatedAtKnownSubSite = new Object(); + } + + public void allocateObjectAtOverriddenSite() { + objectAllocatedAtOverriddenSite = new Object(); + } + + DumpedStuff(boolean baseline) { + allocateObjectAtKnownSite(); + + int n = baseline ? 400000 : 1000000; + bigArray = new byte[n]; + for (int i = 0; i < n; i++) { + bigArray[i] = (byte)((i * i) & 0xFF); + } + + // 0x12345, 50000, and 0xABCDABCD are arbitrary values. + NativeAllocationRegistry registry = new NativeAllocationRegistry( + Main.class.getClassLoader(), 0x12345, 50000); + registry.registerNativeAllocation(anObject, 0xABCDABCD); + + { + Object object = new Object(); + aLongStrongPathToSamplePathObject = new Reference(new Reference(new Reference(object))); + aShortWeakPathToSamplePathObject = new WeakReference(new Reference(object)); + } + + addedObject = baseline ? null : new AddedObject(); + removedObject = baseline ? new RemovedObject() : null; + modifiedObject = new ModifiedObject(); + modifiedObject.value = baseline ? 5 : 8; + modifiedObject.modifiedRefField = baseline ? "A1" : "A2"; + modifiedObject.unmodifiedRefField = "B"; + modifiedStaticField = baseline ? "C1" : "C2"; + modifiedArray = baseline ? new int[]{0, 1, 2, 3} : new int[]{3, 1, 2, 0}; + + // Deep matching dominator trees shouldn't smash the stack when we try + // to diff them. Make some deep dominator trees to help test it. + for (int i = 0; i < 10000; i++) { + StackSmasher smasher = new StackSmasher(); + smasher.child = stackSmasher; + stackSmasher = smasher; + + if (!baseline) { + smasher = new StackSmasher(); + smasher.child = stackSmasherAdded; + stackSmasherAdded = smasher; + } + } + + gcPathArray[2].right.left = gcPathArray[2].left.right; + } + + public static class ObjectTree { + public ObjectTree left; + public ObjectTree right; + + public ObjectTree(ObjectTree left, ObjectTree right) { + this.left = left; + this.right = right; + } + } + + public static class AddedObject { + } + + public static class RemovedObject { + } + + public static class UnchangedObject { + } + + public static class ModifiedObject { + public int value; + public String modifiedRefField; + public String unmodifiedRefField; + } + + public static class StackSmasher { + public StackSmasher child; + } + + public static class Reference { + public Object referent; + + public Reference(Object referent) { + this.referent = referent; + } + } + + public String basicString = "hello, world"; + public String nonAscii = "Sigma (Ʃ) is not ASCII"; + public String embeddedZero = "embedded\0..."; // Non-ASCII for string compression purposes. + public char[] charArray = "char thing".toCharArray(); + public String nullString = null; + public Object anObject = new Object(); + public Reference aReference = new Reference(anObject); + public ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); + public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue); + public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue); + public WeakReference aNullReferentReference = new WeakReference(null, referenceQueue); + public SoftReference aSoftReference = new SoftReference(new Object()); + public byte[] bigArray; + public ObjectTree[] gcPathArray = new ObjectTree[]{null, null, + new ObjectTree( + new ObjectTree(null, new ObjectTree(null, null)), + new ObjectTree(null, null)), + null}; + public Reference aLongStrongPathToSamplePathObject; + public WeakReference aShortWeakPathToSamplePathObject; + public WeakReference aWeakRefToGcRoot = new WeakReference(Main.class); + public SoftReference aWeakChain = new SoftReference(new Reference(new Reference(new Object()))); + public Object[] basicStringRef; + public AddedObject addedObject; + public UnchangedObject unchangedObject = new UnchangedObject(); + public RemovedObject removedObject; + public ModifiedObject modifiedObject; + public StackSmasher stackSmasher; + public StackSmasher stackSmasherAdded; + public static String modifiedStaticField; + public int[] modifiedArray; + public Object objectAllocatedAtKnownSite; + public Object objectAllocatedAtKnownSubSite; +} diff --git a/tools/ahat/src/test-dump/Main.java b/tools/ahat/src/test-dump/Main.java index 079be7da81..de3674846b 100644 --- a/tools/ahat/src/test-dump/Main.java +++ b/tools/ahat/src/test-dump/Main.java @@ -16,11 +16,6 @@ import dalvik.system.VMDebug; import java.io.IOException; -import java.lang.ref.PhantomReference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; -import libcore.util.NativeAllocationRegistry; import org.apache.harmony.dalvik.ddmc.DdmVmInternal; /** @@ -31,138 +26,6 @@ public class Main { // collected before we take the heap dump. public static DumpedStuff stuff; - public static class ObjectTree { - public ObjectTree left; - public ObjectTree right; - - public ObjectTree(ObjectTree left, ObjectTree right) { - this.left = left; - this.right = right; - } - } - - public static class AddedObject { - } - - public static class RemovedObject { - } - - public static class UnchangedObject { - } - - public static class ModifiedObject { - public int value; - public String modifiedRefField; - public String unmodifiedRefField; - } - - public static class StackSmasher { - public StackSmasher child; - } - - public static class Reference { - public Object referent; - - public Reference(Object referent) { - this.referent = referent; - } - } - - // We will take a heap dump that includes a single instance of this - // DumpedStuff class. Objects stored as fields in this class can be easily - // found in the hprof dump by searching for the instance of the DumpedStuff - // class and reading the desired field. - public static class DumpedStuff { - public String basicString = "hello, world"; - public String nonAscii = "Sigma (Ʃ) is not ASCII"; - public String embeddedZero = "embedded\0..."; // Non-ASCII for string compression purposes. - public char[] charArray = "char thing".toCharArray(); - public String nullString = null; - public Object anObject = new Object(); - public Reference aReference = new Reference(anObject); - public ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); - public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue); - public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue); - public WeakReference aNullReferentReference = new WeakReference(null, referenceQueue); - public SoftReference aSoftReference = new SoftReference(new Object()); - public byte[] bigArray; - public ObjectTree[] gcPathArray = new ObjectTree[]{null, null, - new ObjectTree( - new ObjectTree(null, new ObjectTree(null, null)), - new ObjectTree(null, null)), - null}; - public Reference aLongStrongPathToSamplePathObject; - public WeakReference aShortWeakPathToSamplePathObject; - public WeakReference aWeakRefToGcRoot = new WeakReference(Main.class); - public SoftReference aWeakChain = new SoftReference(new Reference(new Reference(new Object()))); - public Object[] basicStringRef; - public AddedObject addedObject; - public UnchangedObject unchangedObject = new UnchangedObject(); - public RemovedObject removedObject; - public ModifiedObject modifiedObject; - public StackSmasher stackSmasher; - public StackSmasher stackSmasherAdded; - public static String modifiedStaticField; - public int[] modifiedArray; - public Object objectAllocatedAtKnownSite1; - public Object objectAllocatedAtKnownSite2; - - private void allocateObjectAtKnownSite1() { - objectAllocatedAtKnownSite1 = new Object(); - allocateObjectAtKnownSite2(); - } - - private void allocateObjectAtKnownSite2() { - objectAllocatedAtKnownSite2 = new Object(); - } - - DumpedStuff(boolean baseline) { - int n = baseline ? 400000 : 1000000; - bigArray = new byte[n]; - for (int i = 0; i < n; i++) { - bigArray[i] = (byte)((i * i) & 0xFF); - } - - // 0x12345, 50000, and 0xABCDABCD are arbitrary values. - NativeAllocationRegistry registry = new NativeAllocationRegistry( - Main.class.getClassLoader(), 0x12345, 50000); - registry.registerNativeAllocation(anObject, 0xABCDABCD); - - { - Object object = new Object(); - aLongStrongPathToSamplePathObject = new Reference(new Reference(new Reference(object))); - aShortWeakPathToSamplePathObject = new WeakReference(new Reference(object)); - } - - addedObject = baseline ? null : new AddedObject(); - removedObject = baseline ? new RemovedObject() : null; - modifiedObject = new ModifiedObject(); - modifiedObject.value = baseline ? 5 : 8; - modifiedObject.modifiedRefField = baseline ? "A1" : "A2"; - modifiedObject.unmodifiedRefField = "B"; - modifiedStaticField = baseline ? "C1" : "C2"; - modifiedArray = baseline ? new int[]{0, 1, 2, 3} : new int[]{3, 1, 2, 0}; - - allocateObjectAtKnownSite1(); - - // Deep matching dominator trees shouldn't smash the stack when we try - // to diff them. Make some deep dominator trees to help test it. - for (int i = 0; i < 10000; i++) { - StackSmasher smasher = new StackSmasher(); - smasher.child = stackSmasher; - stackSmasher = smasher; - - if (!baseline) { - smasher = new StackSmasher(); - smasher.child = stackSmasherAdded; - stackSmasherAdded = smasher; - } - } - - gcPathArray[2].right.left = gcPathArray[2].left.right; - } - } - public static void main(String[] args) throws IOException { if (args.length < 1) { System.err.println("no output file specified"); diff --git a/tools/ahat/src/test-dump/SuperDumpedStuff.java b/tools/ahat/src/test-dump/SuperDumpedStuff.java new file mode 100644 index 0000000000..5ec62aecb1 --- /dev/null +++ b/tools/ahat/src/test-dump/SuperDumpedStuff.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// A super class for DumpedStuff to test deobfuscation of methods inherited +// from the super class. +public class SuperDumpedStuff { + + public void allocateObjectAtObfSuperSite() { + objectAllocatedAtObfSuperSite = new Object(); + } + + public void allocateObjectAtUnObfSuperSite() { + objectAllocatedAtUnObfSuperSite = new Object(); + } + + public void allocateObjectAtOverriddenSite() { + objectAllocatedAtOverriddenSite = new Object(); + } + + public Object objectAllocatedAtObfSuperSite; + public Object objectAllocatedAtUnObfSuperSite; + public Object objectAllocatedAtOverriddenSite; +} diff --git a/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java b/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java index ad40f45665..02976b5285 100644 --- a/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java +++ b/tools/ahat/src/test/com/android/ahat/ProguardMapTest.java @@ -45,7 +45,6 @@ public class ProguardMapTest { + " 64:66:class.with.only.Fields methodWithObfRes() -> n\n" + " 80:80:void lineObfuscatedMethod():8:8 -> o\n" + " 90:90:void lineObfuscatedMethod2():9 -> p\n" - + " 120:121:void method.from.a.Superclass.supermethod() -> q\n" ; @Test @@ -160,12 +159,10 @@ public class ProguardMapTest { assertEquals("Methods.java", frame.filename); assertEquals(13, frame.line); - frame = map.getFrame("class.with.Methods", "q", "()V", "SourceFile.java", 120); - // TODO: Should this be "supermethod", instead of - // "method.from.a.Superclass.supermethod"? - assertEquals("method.from.a.Superclass.supermethod", frame.method); - assertEquals("()V", frame.signature); - assertEquals("Superclass.java", frame.filename); - assertEquals(120, frame.line); + // Some methods may not have been obfuscated. We should still be able + // to compute the filename properly. + frame = map.getFrame("class.with.Methods", "unObfuscatedMethodName", + "()V", "SourceFile.java", 0); + assertEquals("Methods.java", frame.filename); } } diff --git a/tools/ahat/src/test/com/android/ahat/SiteTest.java b/tools/ahat/src/test/com/android/ahat/SiteTest.java index dc0fe08297..0443d7f264 100644 --- a/tools/ahat/src/test/com/android/ahat/SiteTest.java +++ b/tools/ahat/src/test/com/android/ahat/SiteTest.java @@ -23,6 +23,7 @@ import java.io.IOException; import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; public class SiteTest { @@ -31,36 +32,54 @@ public class SiteTest { TestDump dump = TestDump.getTestDump(); AhatSnapshot snapshot = dump.getAhatSnapshot(); - AhatInstance obj1 = dump.getDumpedAhatInstance("objectAllocatedAtKnownSite1"); - AhatInstance obj2 = dump.getDumpedAhatInstance("objectAllocatedAtKnownSite2"); - Site s2 = obj2.getSite(); - Site s1b = s2.getParent(); - Site s1a = obj1.getSite(); - Site s = s1a.getParent(); + AhatInstance oKnownSite = dump.getDumpedAhatInstance("objectAllocatedAtKnownSite"); + Site sKnownSite = oKnownSite.getSite(); + assertEquals("DumpedStuff.java", sKnownSite.getFilename()); + assertEquals("allocateObjectAtKnownSite", sKnownSite.getMethodName()); + assertEquals(29, sKnownSite.getLineNumber()); + assertSame(sKnownSite, snapshot.getSite(sKnownSite.getId())); - // TODO: The following commented out assertion fails due to a problem with - // proguard deobfuscation. That bug should be fixed. - // assertEquals("Main.java", s.getFilename()); + AhatInstance oKnownSubSite = dump.getDumpedAhatInstance("objectAllocatedAtKnownSubSite"); + Site sKnownSubSite = oKnownSubSite.getSite(); + assertEquals("DumpedStuff.java", sKnownSubSite.getFilename()); + assertEquals("allocateObjectAtKnownSubSite", sKnownSubSite.getMethodName()); + assertEquals(37, sKnownSubSite.getLineNumber()); + assertSame(sKnownSubSite, snapshot.getSite(sKnownSubSite.getId())); - assertEquals("Main.java", s1a.getFilename()); - assertEquals("Main.java", s1b.getFilename()); - assertEquals("Main.java", s2.getFilename()); + Site sKnownSubSiteParent = sKnownSubSite.getParent(); + assertEquals("DumpedStuff.java", sKnownSubSiteParent.getFilename()); + assertEquals("allocateObjectAtKnownSite", sKnownSubSiteParent.getMethodName()); + assertEquals(30, sKnownSubSiteParent.getLineNumber()); + assertSame(sKnownSubSiteParent, snapshot.getSite(sKnownSubSiteParent.getId())); - assertEquals("allocateObjectAtKnownSite1", s1a.getMethodName()); - assertEquals("allocateObjectAtKnownSite1", s1b.getMethodName()); - assertEquals("allocateObjectAtKnownSite2", s2.getMethodName()); + assertNotSame(sKnownSite, sKnownSubSiteParent); + assertSame(sKnownSite.getParent(), sKnownSubSiteParent.getParent()); - // TODO: The following commented out assertion fails due to a problem with - // stack frame line numbers - we don't get different line numbers - // for the different sites, so they are indistiguishable. The - // problem with line numbers should be understood and fixed. - // assertNotSame(s1a, s1b); + Site sKnownSiteParent = sKnownSite.getParent(); + assertEquals("DumpedStuff.java", sKnownSiteParent.getFilename()); + assertEquals("<init>", sKnownSiteParent.getMethodName()); + assertEquals(45, sKnownSiteParent.getLineNumber()); + assertSame(sKnownSiteParent, snapshot.getSite(sKnownSiteParent.getId())); - assertSame(s1a.getParent(), s1b.getParent()); + AhatInstance oObfSuperSite = dump.getDumpedAhatInstance("objectAllocatedAtObfSuperSite"); + Site sObfSuperSite = oObfSuperSite.getSite(); + assertEquals("SuperDumpedStuff.java", sObfSuperSite.getFilename()); + assertEquals("allocateObjectAtObfSuperSite", sObfSuperSite.getMethodName()); + assertEquals(22, sObfSuperSite.getLineNumber()); + assertSame(sObfSuperSite, snapshot.getSite(sObfSuperSite.getId())); - assertSame(s, snapshot.getSite(s.getId())); - assertSame(s1a, snapshot.getSite(s1a.getId())); - assertSame(s1b, snapshot.getSite(s1b.getId())); - assertSame(s2, snapshot.getSite(s2.getId())); + AhatInstance oUnObfSuperSite = dump.getDumpedAhatInstance("objectAllocatedAtUnObfSuperSite"); + Site sUnObfSuperSite = oUnObfSuperSite.getSite(); + assertEquals("SuperDumpedStuff.java", sUnObfSuperSite.getFilename()); + assertEquals("allocateObjectAtUnObfSuperSite", sUnObfSuperSite.getMethodName()); + assertEquals(26, sUnObfSuperSite.getLineNumber()); + assertSame(sUnObfSuperSite, snapshot.getSite(sUnObfSuperSite.getId())); + + AhatInstance oOverriddenSite = dump.getDumpedAhatInstance("objectAllocatedAtOverriddenSite"); + Site sOverriddenSite = oOverriddenSite.getSite(); + assertEquals("DumpedStuff.java", sOverriddenSite.getFilename()); + assertEquals("allocateObjectAtOverriddenSite", sOverriddenSite.getMethodName()); + assertEquals(41, sOverriddenSite.getLineNumber()); + assertSame(sOverriddenSite, snapshot.getSite(sOverriddenSite.getId())); } } |