diff options
author | Michaël Zasso <targos@protonmail.com> | 2019-08-01 08:38:30 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2019-08-01 12:53:56 +0200 |
commit | 2dcc3665abf57c3607cebffdeeca062f5894885d (patch) | |
tree | 4f560748132edcfb4c22d6f967a7e80d23d7ea2c /deps/v8/src/diagnostics/disassembler.cc | |
parent | 1ee47d550c6de132f06110aa13eceb7551d643b3 (diff) | |
download | android-node-v8-2dcc3665abf57c3607cebffdeeca062f5894885d.tar.gz android-node-v8-2dcc3665abf57c3607cebffdeeca062f5894885d.tar.bz2 android-node-v8-2dcc3665abf57c3607cebffdeeca062f5894885d.zip |
deps: update V8 to 7.6.303.28
PR-URL: https://github.com/nodejs/node/pull/28016
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Refael Ackermann (רפאל פלחי) <refack@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Diffstat (limited to 'deps/v8/src/diagnostics/disassembler.cc')
-rw-r--r-- | deps/v8/src/diagnostics/disassembler.cc | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/deps/v8/src/diagnostics/disassembler.cc b/deps/v8/src/diagnostics/disassembler.cc new file mode 100644 index 0000000000..8307ef3ff4 --- /dev/null +++ b/deps/v8/src/diagnostics/disassembler.cc @@ -0,0 +1,446 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/diagnostics/disassembler.h" + +#include <memory> +#include <unordered_map> +#include <vector> + +#include "src/codegen/assembler-inl.h" +#include "src/codegen/code-comments.h" +#include "src/codegen/code-reference.h" +#include "src/codegen/macro-assembler.h" +#include "src/debug/debug.h" +#include "src/deoptimizer/deoptimizer.h" +#include "src/diagnostics/disasm.h" +#include "src/execution/isolate-data.h" +#include "src/ic/ic.h" +#include "src/objects/objects-inl.h" +#include "src/snapshot/embedded/embedded-data.h" +#include "src/snapshot/serializer-common.h" +#include "src/strings/string-stream.h" +#include "src/utils/vector.h" +#include "src/wasm/wasm-code-manager.h" +#include "src/wasm/wasm-engine.h" + +namespace v8 { +namespace internal { + +#ifdef ENABLE_DISASSEMBLER + +class V8NameConverter : public disasm::NameConverter { + public: + explicit V8NameConverter(Isolate* isolate, CodeReference code = {}) + : isolate_(isolate), code_(code) {} + const char* NameOfAddress(byte* pc) const override; + const char* NameInCode(byte* addr) const override; + const char* RootRelativeName(int offset) const override; + + const CodeReference& code() const { return code_; } + + private: + void InitExternalRefsCache() const; + + Isolate* isolate_; + CodeReference code_; + + EmbeddedVector<char, 128> v8_buffer_; + + // Map from root-register relative offset of the external reference value to + // the external reference name (stored in the external reference table). + // This cache is used to recognize [root_reg + offs] patterns as direct + // access to certain external reference's value. + mutable std::unordered_map<int, const char*> directly_accessed_external_refs_; +}; + +void V8NameConverter::InitExternalRefsCache() const { + ExternalReferenceTable* external_reference_table = + isolate_->external_reference_table(); + if (!external_reference_table->is_initialized()) return; + + base::AddressRegion addressable_region = + isolate_->root_register_addressable_region(); + Address isolate_root = isolate_->isolate_root(); + + for (uint32_t i = 0; i < ExternalReferenceTable::kSize; i++) { + Address address = external_reference_table->address(i); + if (addressable_region.contains(address)) { + int offset = static_cast<int>(address - isolate_root); + const char* name = external_reference_table->name(i); + directly_accessed_external_refs_.insert({offset, name}); + } + } +} + +const char* V8NameConverter::NameOfAddress(byte* pc) const { + if (!code_.is_null()) { + const char* name = + isolate_ ? isolate_->builtins()->Lookup(reinterpret_cast<Address>(pc)) + : nullptr; + + if (name != nullptr) { + SNPrintF(v8_buffer_, "%p (%s)", static_cast<void*>(pc), name); + return v8_buffer_.begin(); + } + + int offs = static_cast<int>(reinterpret_cast<Address>(pc) - + code_.instruction_start()); + // print as code offset, if it seems reasonable + if (0 <= offs && offs < code_.instruction_size()) { + SNPrintF(v8_buffer_, "%p <+0x%x>", static_cast<void*>(pc), offs); + return v8_buffer_.begin(); + } + + wasm::WasmCodeRefScope wasm_code_ref_scope; + wasm::WasmCode* wasm_code = + isolate_ ? isolate_->wasm_engine()->code_manager()->LookupCode( + reinterpret_cast<Address>(pc)) + : nullptr; + if (wasm_code != nullptr) { + SNPrintF(v8_buffer_, "%p (%s)", static_cast<void*>(pc), + wasm::GetWasmCodeKindAsString(wasm_code->kind())); + return v8_buffer_.begin(); + } + } + + return disasm::NameConverter::NameOfAddress(pc); +} + +const char* V8NameConverter::NameInCode(byte* addr) const { + // The V8NameConverter is used for well known code, so we can "safely" + // dereference pointers in generated code. + return code_.is_null() ? "" : reinterpret_cast<const char*>(addr); +} + +const char* V8NameConverter::RootRelativeName(int offset) const { + if (isolate_ == nullptr) return nullptr; + + const int kRootsTableStart = IsolateData::roots_table_offset(); + const unsigned kRootsTableSize = sizeof(RootsTable); + const int kExtRefsTableStart = IsolateData::external_reference_table_offset(); + const unsigned kExtRefsTableSize = ExternalReferenceTable::kSizeInBytes; + const int kBuiltinsTableStart = IsolateData::builtins_table_offset(); + const unsigned kBuiltinsTableSize = + Builtins::builtin_count * kSystemPointerSize; + + if (static_cast<unsigned>(offset - kRootsTableStart) < kRootsTableSize) { + uint32_t offset_in_roots_table = offset - kRootsTableStart; + + // Fail safe in the unlikely case of an arbitrary root-relative offset. + if (offset_in_roots_table % kSystemPointerSize != 0) return nullptr; + + RootIndex root_index = + static_cast<RootIndex>(offset_in_roots_table / kSystemPointerSize); + + SNPrintF(v8_buffer_, "root (%s)", RootsTable::name(root_index)); + return v8_buffer_.begin(); + + } else if (static_cast<unsigned>(offset - kExtRefsTableStart) < + kExtRefsTableSize) { + uint32_t offset_in_extref_table = offset - kExtRefsTableStart; + + // Fail safe in the unlikely case of an arbitrary root-relative offset. + if (offset_in_extref_table % ExternalReferenceTable::kEntrySize != 0) { + return nullptr; + } + + // Likewise if the external reference table is uninitialized. + if (!isolate_->external_reference_table()->is_initialized()) { + return nullptr; + } + + SNPrintF(v8_buffer_, "external reference (%s)", + isolate_->external_reference_table()->NameFromOffset( + offset_in_extref_table)); + return v8_buffer_.begin(); + + } else if (static_cast<unsigned>(offset - kBuiltinsTableStart) < + kBuiltinsTableSize) { + uint32_t offset_in_builtins_table = (offset - kBuiltinsTableStart); + + Builtins::Name builtin_id = static_cast<Builtins::Name>( + offset_in_builtins_table / kSystemPointerSize); + + const char* name = Builtins::name(builtin_id); + SNPrintF(v8_buffer_, "builtin (%s)", name); + return v8_buffer_.begin(); + + } else { + // It must be a direct access to one of the external values. + if (directly_accessed_external_refs_.empty()) { + InitExternalRefsCache(); + } + + auto iter = directly_accessed_external_refs_.find(offset); + if (iter != directly_accessed_external_refs_.end()) { + SNPrintF(v8_buffer_, "external value (%s)", iter->second); + return v8_buffer_.begin(); + } + return nullptr; + } +} + +static void DumpBuffer(std::ostream* os, StringBuilder* out) { + (*os) << out->Finalize() << std::endl; + out->Reset(); +} + +static const int kOutBufferSize = 2048 + String::kMaxShortPrintLength; +static const int kRelocInfoPosition = 57; + +static void PrintRelocInfo(StringBuilder* out, Isolate* isolate, + const ExternalReferenceEncoder* ref_encoder, + std::ostream* os, CodeReference host, + RelocInfo* relocinfo, bool first_reloc_info = true) { + // Indent the printing of the reloc info. + if (first_reloc_info) { + // The first reloc info is printed after the disassembled instruction. + out->AddPadding(' ', kRelocInfoPosition - out->position()); + } else { + // Additional reloc infos are printed on separate lines. + DumpBuffer(os, out); + out->AddPadding(' ', kRelocInfoPosition); + } + + RelocInfo::Mode rmode = relocinfo->rmode(); + if (rmode == RelocInfo::DEOPT_SCRIPT_OFFSET) { + out->AddFormatted(" ;; debug: deopt position, script offset '%d'", + static_cast<int>(relocinfo->data())); + } else if (rmode == RelocInfo::DEOPT_INLINING_ID) { + out->AddFormatted(" ;; debug: deopt position, inlining id '%d'", + static_cast<int>(relocinfo->data())); + } else if (rmode == RelocInfo::DEOPT_REASON) { + DeoptimizeReason reason = static_cast<DeoptimizeReason>(relocinfo->data()); + out->AddFormatted(" ;; debug: deopt reason '%s'", + DeoptimizeReasonToString(reason)); + } else if (rmode == RelocInfo::DEOPT_ID) { + out->AddFormatted(" ;; debug: deopt index %d", + static_cast<int>(relocinfo->data())); + } else if (RelocInfo::IsEmbeddedObjectMode(rmode)) { + HeapStringAllocator allocator; + StringStream accumulator(&allocator); + relocinfo->target_object().ShortPrint(&accumulator); + std::unique_ptr<char[]> obj_name = accumulator.ToCString(); + const bool is_compressed = RelocInfo::IsCompressedEmbeddedObject(rmode); + out->AddFormatted(" ;; %sobject: %s", + is_compressed ? "(compressed) " : "", obj_name.get()); + } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) { + const char* reference_name = + ref_encoder ? ref_encoder->NameOfAddress( + isolate, relocinfo->target_external_reference()) + : "unknown"; + out->AddFormatted(" ;; external reference (%s)", reference_name); + } else if (RelocInfo::IsCodeTargetMode(rmode)) { + out->AddFormatted(" ;; code:"); + Code code = isolate->heap()->GcSafeFindCodeForInnerPointer( + relocinfo->target_address()); + Code::Kind kind = code.kind(); + if (code.is_builtin()) { + out->AddFormatted(" Builtin::%s", Builtins::name(code.builtin_index())); + } else { + out->AddFormatted(" %s", Code::Kind2String(kind)); + } + } else if (RelocInfo::IsWasmStubCall(rmode) && host.is_wasm_code()) { + // Host is isolate-independent, try wasm native module instead. + const char* runtime_stub_name = + host.as_wasm_code()->native_module()->GetRuntimeStubName( + relocinfo->wasm_stub_call_address()); + out->AddFormatted(" ;; wasm stub: %s", runtime_stub_name); + } else if (RelocInfo::IsRuntimeEntry(rmode) && isolate && + isolate->deoptimizer_data() != nullptr) { + // A runtime entry relocinfo might be a deoptimization bailout. + Address addr = relocinfo->target_address(); + DeoptimizeKind type; + if (Deoptimizer::IsDeoptimizationEntry(isolate, addr, &type)) { + out->AddFormatted(" ;; %s deoptimization bailout", + Deoptimizer::MessageFor(type)); + } else { + out->AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode)); + } + } else { + out->AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode)); + } +} + +static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder, + std::ostream* os, CodeReference code, + const V8NameConverter& converter, byte* begin, byte* end, + Address current_pc) { + CHECK(!code.is_null()); + v8::internal::EmbeddedVector<char, 128> decode_buffer; + v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer; + StringBuilder out(out_buffer.begin(), out_buffer.length()); + byte* pc = begin; + disasm::Disassembler d(converter, + disasm::Disassembler::kContinueOnUnimplementedOpcode); + RelocIterator* it = nullptr; + CodeCommentsIterator cit(code.code_comments(), code.code_comments_size()); + // Relocation exists if we either have no isolate (wasm code), + // or we have an isolate and it is not an off-heap instruction stream. + if (!isolate || + !InstructionStream::PcIsOffHeap(isolate, bit_cast<Address>(begin))) { + it = new RelocIterator(code); + } else { + // No relocation information when printing code stubs. + } + int constants = -1; // no constants being decoded at the start + + while (pc < end) { + // First decode instruction so that we know its length. + byte* prev_pc = pc; + if (constants > 0) { + SNPrintF(decode_buffer, "%08x constant", + *reinterpret_cast<int32_t*>(pc)); + constants--; + pc += 4; + } else { + int num_const = d.ConstantPoolSizeAt(pc); + if (num_const >= 0) { + SNPrintF(decode_buffer, + "%08x constant pool begin (num_const = %d)", + *reinterpret_cast<int32_t*>(pc), num_const); + constants = num_const; + pc += 4; + } else if (it != nullptr && !it->done() && + it->rinfo()->pc() == reinterpret_cast<Address>(pc) && + it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) { + // raw pointer embedded in code stream, e.g., jump table + byte* ptr = *reinterpret_cast<byte**>(pc); + SNPrintF(decode_buffer, "%08" V8PRIxPTR " jump table entry %4zu", + reinterpret_cast<intptr_t>(ptr), + static_cast<size_t>(ptr - begin)); + pc += sizeof(ptr); + } else { + decode_buffer[0] = '\0'; + pc += d.InstructionDecode(decode_buffer, pc); + } + } + + // Collect RelocInfo for this instruction (prev_pc .. pc-1) + std::vector<const char*> comments; + std::vector<Address> pcs; + std::vector<RelocInfo::Mode> rmodes; + std::vector<intptr_t> datas; + if (it != nullptr) { + while (!it->done() && it->rinfo()->pc() < reinterpret_cast<Address>(pc)) { + // Collect all data. + pcs.push_back(it->rinfo()->pc()); + rmodes.push_back(it->rinfo()->rmode()); + datas.push_back(it->rinfo()->data()); + it->next(); + } + } + while (cit.HasCurrent() && + cit.GetPCOffset() < static_cast<Address>(pc - begin)) { + comments.push_back(cit.GetComment()); + cit.Next(); + } + + // Comments. + for (size_t i = 0; i < comments.size(); i++) { + out.AddFormatted(" %s", comments[i]); + DumpBuffer(os, &out); + } + + // Instruction address and instruction offset. + if (FLAG_log_colour && reinterpret_cast<Address>(prev_pc) == current_pc) { + // If this is the given "current" pc, make it yellow and bold. + out.AddFormatted("\033[33;1m"); + } + out.AddFormatted("%p %4" V8PRIxPTRDIFF " ", static_cast<void*>(prev_pc), + prev_pc - begin); + + // Instruction. + out.AddFormatted("%s", decode_buffer.begin()); + + // Print all the reloc info for this instruction which are not comments. + for (size_t i = 0; i < pcs.size(); i++) { + // Put together the reloc info + const CodeReference& host = code; + Address constant_pool = + host.is_null() ? kNullAddress : host.constant_pool(); + Code code_pointer; + if (!host.is_null() && host.is_js()) { + code_pointer = *host.as_js_code(); + } + + RelocInfo relocinfo(pcs[i], rmodes[i], datas[i], code_pointer, + constant_pool); + + bool first_reloc_info = (i == 0); + PrintRelocInfo(&out, isolate, ref_encoder, os, code, &relocinfo, + first_reloc_info); + } + + // If this is a constant pool load and we haven't found any RelocInfo + // already, check if we can find some RelocInfo for the target address in + // the constant pool. + if (pcs.empty() && !code.is_null()) { + RelocInfo dummy_rinfo(reinterpret_cast<Address>(prev_pc), RelocInfo::NONE, + 0, Code()); + if (dummy_rinfo.IsInConstantPool()) { + Address constant_pool_entry_address = + dummy_rinfo.constant_pool_entry_address(); + RelocIterator reloc_it(code); + while (!reloc_it.done()) { + if (reloc_it.rinfo()->IsInConstantPool() && + (reloc_it.rinfo()->constant_pool_entry_address() == + constant_pool_entry_address)) { + PrintRelocInfo(&out, isolate, ref_encoder, os, code, + reloc_it.rinfo()); + break; + } + reloc_it.next(); + } + } + } + + if (FLAG_log_colour && reinterpret_cast<Address>(prev_pc) == current_pc) { + out.AddFormatted("\033[m"); + } + + DumpBuffer(os, &out); + } + + // Emit comments following the last instruction (if any). + while (cit.HasCurrent() && + cit.GetPCOffset() < static_cast<Address>(pc - begin)) { + out.AddFormatted(" %s", cit.GetComment()); + DumpBuffer(os, &out); + cit.Next(); + } + + delete it; + return static_cast<int>(pc - begin); +} + +int Disassembler::Decode(Isolate* isolate, std::ostream* os, byte* begin, + byte* end, CodeReference code, Address current_pc) { + V8NameConverter v8NameConverter(isolate, code); + if (isolate) { + // We have an isolate, so support external reference names. + SealHandleScope shs(isolate); + DisallowHeapAllocation no_alloc; + ExternalReferenceEncoder ref_encoder(isolate); + return DecodeIt(isolate, &ref_encoder, os, code, v8NameConverter, begin, + end, current_pc); + } else { + // No isolate => isolate-independent code. No external reference names. + return DecodeIt(nullptr, nullptr, os, code, v8NameConverter, begin, end, + current_pc); + } +} + +#else // ENABLE_DISASSEMBLER + +int Disassembler::Decode(Isolate* isolate, std::ostream* os, byte* begin, + byte* end, CodeReference code, Address current_pc) { + return 0; +} + +#endif // ENABLE_DISASSEMBLER + +} // namespace internal +} // namespace v8 |