[ext-code-space] Support disassembly of CodeT objects

... which will be necessary once builtins become Code-less.

Bug: v8:11880
Change-Id: If48739c3a058e6baf3c2e062d8eaace062c27592
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3822686
Reviewed-by: Jakob Linke <jgruber@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82352}
This commit is contained in:
ishell@chromium.org 2022-08-10 15:14:40 +02:00 committed by V8 LUCI CQ
parent 0bc4b452af
commit 8daad0ea86
8 changed files with 265 additions and 144 deletions

View File

@ -259,7 +259,7 @@ void Builtins::PrintBuiltinCode() {
base::CStrVector(FLAG_print_builtin_code_filter))) {
CodeTracer::Scope trace_scope(isolate_->GetCodeTracer());
OFStream os(trace_scope.file());
Code builtin_code = FromCodeT(code(builtin));
CodeT builtin_code = code(builtin);
builtin_code.Disassemble(builtin_name, os, isolate_);
os << "\n";
}
@ -273,7 +273,7 @@ void Builtins::PrintBuiltinSize() {
++builtin) {
const char* builtin_name = name(builtin);
const char* kind = KindNameOf(builtin);
Code code = FromCodeT(Builtins::code(builtin));
CodeT code = Builtins::code(builtin);
PrintF(stdout, "%s Builtin, %s, %d\n", kind, builtin_name,
code.InstructionSize());
}
@ -457,6 +457,11 @@ Handle<Code> Builtins::CreateInterpreterEntryTrampolineForProfiling(
DCHECK_EQ(d.SafepointTableSizeOf(builtin), 0);
DCHECK_EQ(d.HandlerTableSizeOf(builtin), 0);
DCHECK_EQ(d.ConstantPoolSizeOf(builtin), 0);
// TODO(v8:11036): currently the CodeDesc can't represent the state when the
// code metadata is stored separately from the instruction stream, therefore
// it cannot recreate code comments in the trampoline copy.
// The following DCHECK currently fails if the mksnapshot is run with enabled
// code comments.
DCHECK_EQ(d.CodeCommentsSizeOf(builtin), 0);
DCHECK_EQ(d.UnwindingInfoSizeOf(builtin), 0);

View File

@ -17,8 +17,10 @@ namespace v8 {
namespace internal {
namespace {
struct JSOps {
Handle<Code> code;
template <typename CodeOrCodeT>
struct CodeOrCodeTOps {
Handle<CodeOrCodeT> code;
Address constant_pool() const { return code->constant_pool(); }
Address instruction_start() const { return code->InstructionStart(); }
@ -31,8 +33,11 @@ struct JSOps {
int code_comments_size() const { return code->code_comments_size(); }
};
using CodeOps = CodeOrCodeTOps<Code>;
using CodeTOps = CodeOrCodeTOps<CodeT>;
#if V8_ENABLE_WEBASSEMBLY
struct WasmOps {
struct WasmCodeOps {
const wasm::WasmCode* code;
Address constant_pool() const { return code->constant_pool(); }
@ -82,32 +87,28 @@ struct CodeDescOps {
} // namespace
#if V8_ENABLE_WEBASSEMBLY
#define DISPATCH(ret, method) \
ret CodeReference::method() const { \
DCHECK(!is_null()); \
switch (kind_) { \
case Kind::JS: \
return JSOps{js_code_}.method(); \
case Kind::WASM: \
return WasmOps{wasm_code_}.method(); \
case Kind::CODE_DESC: \
return CodeDescOps{code_desc_}.method(); \
default: \
UNREACHABLE(); \
} \
}
#define HANDLE_WASM(...) __VA_ARGS__
#else
#define DISPATCH(ret, method) \
ret CodeReference::method() const { \
DCHECK(!is_null()); \
DCHECK(kind_ == Kind::JS || kind_ == Kind::CODE_DESC); \
if (kind_ == Kind::JS) { \
return JSOps{js_code_}.method(); \
} else { \
return CodeDescOps{code_desc_}.method(); \
} \
#define HANDLE_WASM(...) UNREACHABLE()
#endif
#define DISPATCH(ret, method) \
ret CodeReference::method() const { \
DCHECK(!is_null()); \
switch (kind_) { \
case Kind::CODE: \
return CodeOps{code_}.method(); \
case Kind::CODET: \
CHECK(V8_EXTERNAL_CODE_SPACE_BOOL); \
return CodeTOps{codet_}.method(); \
case Kind::WASM_CODE: \
HANDLE_WASM(return WasmCodeOps{wasm_code_}.method()); \
case Kind::CODE_DESC: \
return CodeDescOps{code_desc_}.method(); \
default: \
UNREACHABLE(); \
} \
}
#endif // V8_ENABLE_WEBASSEMBLY
DISPATCH(Address, constant_pool)
DISPATCH(Address, instruction_start)
@ -120,6 +121,7 @@ DISPATCH(Address, code_comments)
DISPATCH(int, code_comments_size)
#undef DISPATCH
#undef HANDLE_WASM
} // namespace internal
} // namespace v8

View File

@ -13,6 +13,7 @@ namespace v8 {
namespace internal {
class Code;
class CodeDataContainer;
class CodeDesc;
namespace wasm {
@ -23,11 +24,14 @@ class CodeReference {
public:
CodeReference() : kind_(Kind::NONE), null_(nullptr) {}
explicit CodeReference(const wasm::WasmCode* wasm_code)
: kind_(Kind::WASM), wasm_code_(wasm_code) {}
: kind_(Kind::WASM_CODE), wasm_code_(wasm_code) {}
explicit CodeReference(const CodeDesc* code_desc)
: kind_(Kind::CODE_DESC), code_desc_(code_desc) {}
explicit CodeReference(Handle<Code> js_code)
: kind_(Kind::JS), js_code_(js_code) {}
explicit CodeReference(Handle<Code> code) : kind_(Kind::CODE), code_(code) {}
#ifdef V8_EXTERNAL_CODE_SPACE
explicit CodeReference(Handle<CodeT> codet)
: kind_(Kind::CODET), codet_(codet) {}
#endif // V8_EXTERNAL_CODE_SPACE
Address constant_pool() const;
Address instruction_start() const;
@ -40,26 +44,35 @@ class CodeReference {
int code_comments_size() const;
bool is_null() const { return kind_ == Kind::NONE; }
bool is_js() const { return kind_ == Kind::JS; }
bool is_wasm_code() const { return kind_ == Kind::WASM; }
bool is_code() const { return kind_ == Kind::CODE; }
bool is_codet() const { return kind_ == Kind::CODET; }
bool is_wasm_code() const { return kind_ == Kind::WASM_CODE; }
Handle<Code> as_js_code() const {
DCHECK_EQ(Kind::JS, kind_);
return js_code_;
Handle<Code> as_code() const {
DCHECK_EQ(Kind::CODE, kind_);
return code_;
}
#ifdef V8_EXTERNAL_CODE_SPACE
Handle<CodeT> as_codet() const {
DCHECK_EQ(Kind::CODET, kind_);
return codet_;
}
#endif // V8_EXTERNAL_CODE_SPACE
const wasm::WasmCode* as_wasm_code() const {
DCHECK_EQ(Kind::WASM, kind_);
DCHECK_EQ(Kind::WASM_CODE, kind_);
return wasm_code_;
}
private:
enum class Kind { NONE, JS, WASM, CODE_DESC } kind_;
enum class Kind { NONE, CODE, CODET, WASM_CODE, CODE_DESC } kind_;
union {
std::nullptr_t null_;
const wasm::WasmCode* wasm_code_;
const CodeDesc* code_desc_;
Handle<Code> js_code_;
Handle<Code> code_;
Handle<CodeT> codet_;
};
DISALLOW_NEW_AND_DELETE()

View File

@ -300,16 +300,8 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder,
byte* pc = begin;
disasm::Disassembler d(converter,
disasm::Disassembler::kContinueOnUnimplementedOpcode);
RelocIterator* it = nullptr;
RelocIterator rit(code);
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 || !OffHeapInstructionStream::PcIsOffHeap(
isolate, base::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) {
@ -331,21 +323,21 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder,
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 ||
it->rinfo()->rmode() == RelocInfo::LITERAL_CONSTANT ||
it->rinfo()->rmode() == RelocInfo::DATA_EMBEDDED_OBJECT)) {
} else if (!rit.done() &&
rit.rinfo()->pc() == reinterpret_cast<Address>(pc) &&
(rit.rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE ||
rit.rinfo()->rmode() == RelocInfo::LITERAL_CONSTANT ||
rit.rinfo()->rmode() == RelocInfo::DATA_EMBEDDED_OBJECT)) {
// raw pointer embedded in code stream, e.g., jump table
byte* ptr =
base::ReadUnalignedValue<byte*>(reinterpret_cast<Address>(pc));
if (RelocInfo::IsInternalReference(it->rinfo()->rmode())) {
if (RelocInfo::IsInternalReference(rit.rinfo()->rmode())) {
SNPrintF(decode_buffer,
"%08" V8PRIxPTR " jump table entry %4zu",
reinterpret_cast<intptr_t>(ptr),
static_cast<size_t>(ptr - begin));
} else {
const char* kType = RelocInfo::IsLiteralConstant(it->rinfo()->rmode())
const char* kType = RelocInfo::IsLiteralConstant(rit.rinfo()->rmode())
? " literal constant"
: "embedded data object";
SNPrintF(decode_buffer, "%08" V8PRIxPTR " %s 0x%08" V8PRIxPTR,
@ -364,14 +356,12 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder,
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 (!rit.done() && rit.rinfo()->pc() < reinterpret_cast<Address>(pc)) {
// Collect all data.
pcs.push_back(rit.rinfo()->pc());
rmodes.push_back(rit.rinfo()->rmode());
datas.push_back(rit.rinfo()->data());
rit.next();
}
while (cit.HasCurrent() &&
cit.GetPCOffset() < static_cast<Address>(pc - begin)) {
@ -403,8 +393,8 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder,
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();
if (host.is_code()) {
code_pointer = *host.as_code();
}
RelocInfo relocinfo(pcs[i], rmodes[i], datas[i], code_pointer,
@ -456,7 +446,6 @@ static int DecodeIt(Isolate* isolate, ExternalReferenceEncoder* ref_encoder,
cit.Next();
}
delete it;
return static_cast<int>(pc - begin);
}

View File

@ -2954,13 +2954,20 @@ V8_EXPORT_PRIVATE extern void _v8_internal_Print_Code(void* object) {
return;
}
i::Code code = lookup_result.ToCode();
#ifdef ENABLE_DISASSEMBLER
i::StdoutStream os;
code.Disassemble(nullptr, os, isolate, address);
if (lookup_result.IsCodeDataContainer()) {
i::CodeT code = i::CodeT::cast(lookup_result.code_data_container());
code.Disassemble(nullptr, os, isolate, address);
} else {
lookup_result.code().Disassemble(nullptr, os, isolate, address);
}
#else // ENABLE_DISASSEMBLER
code.Print();
if (lookup_result.IsCodeDataContainer()) {
lookup_result.code_data_container().Print();
} else {
lookup_result.code().Print();
}
#endif // ENABLE_DISASSEMBLER
}

View File

@ -791,13 +791,6 @@ bool CodeDataContainer::has_constant_pool() const {
}
#endif
int Code::code_comments_size() const {
DCHECK_GE(unwinding_info_offset() - code_comments_offset(), 0);
return unwinding_info_offset() - code_comments_offset();
}
bool Code::has_code_comments() const { return code_comments_size() > 0; }
ByteArray Code::unchecked_relocation_info() const {
PtrComprCageBase cage_base = main_cage_base();
return ByteArray::unchecked_cast(
@ -816,6 +809,26 @@ int Code::relocation_size() const {
return unchecked_relocation_info().length();
}
#ifdef V8_EXTERNAL_CODE_SPACE
byte* CodeDataContainer::relocation_start() const {
return V8_UNLIKELY(is_off_heap_trampoline())
? nullptr // Off heap trampolines do not have reloc info.
: code().relocation_start();
}
byte* CodeDataContainer::relocation_end() const {
return V8_UNLIKELY(is_off_heap_trampoline())
? nullptr // Off heap trampolines do not have reloc info.
: code().relocation_end();
}
int CodeDataContainer::relocation_size() const {
return V8_UNLIKELY(is_off_heap_trampoline())
? 0 // Off heap trampolines do not have reloc info.
: code().relocation_size();
}
#endif
Address Code::entry() const { return raw_instruction_start(); }
bool Code::contains(Isolate* isolate, Address inner_pointer) {
@ -967,15 +980,11 @@ inline bool Code::checks_tiering_state() const {
(CodeKindCanDeoptimize(kind()) && marked_for_deoptimization());
}
namespace {
inline constexpr bool CodeKindHasTaggedOutgoingParams(CodeKind kind) {
return kind != CodeKind::JS_TO_WASM_FUNCTION &&
kind != CodeKind::C_WASM_ENTRY && kind != CodeKind::WASM_FUNCTION;
}
} // namespace
inline bool Code::has_tagged_outgoing_params() const {
return CodeKindHasTaggedOutgoingParams(kind());
}
@ -1243,16 +1252,49 @@ Address CodeDataContainer::constant_pool() const {
}
#endif
Address Code::raw_code_comments() const {
return raw_metadata_start() + code_comments_offset();
}
Address Code::code_comments() const {
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapCodeCommentsAddress(*this, builtin_id())
: raw_metadata_start() + code_comments_offset();
: raw_code_comments();
}
int Code::code_comments_size() const {
DCHECK_GE(unwinding_info_offset() - code_comments_offset(), 0);
return unwinding_info_offset() - code_comments_offset();
}
bool Code::has_code_comments() const { return code_comments_size() > 0; }
#ifdef V8_EXTERNAL_CODE_SPACE
Address CodeDataContainer::code_comments() const {
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapCodeCommentsAddress(*this, builtin_id())
: code().code_comments();
}
int CodeDataContainer::code_comments_size() const {
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapCodeCommentsSize(*this, builtin_id())
: code().code_comments_size();
}
bool CodeDataContainer::has_code_comments() const {
return code_comments_size() > 0;
}
#endif
Address Code::raw_unwinding_info_start() const {
return raw_metadata_start() + unwinding_info_offset();
}
Address Code::unwinding_info_start() const {
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapUnwindingInfoAddress(*this, builtin_id())
: raw_metadata_start() + unwinding_info_offset();
: raw_unwinding_info_start();
}
Address Code::unwinding_info_end() const {
@ -1268,6 +1310,33 @@ int Code::unwinding_info_size() const {
bool Code::has_unwinding_info() const { return unwinding_info_size() > 0; }
#ifdef V8_EXTERNAL_CODE_SPACE
Address CodeDataContainer::unwinding_info_start() const {
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapUnwindingInfoAddress(*this, builtin_id())
: code().raw_unwinding_info_start();
}
Address CodeDataContainer::unwinding_info_end() const {
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapMetadataEnd(*this, builtin_id())
: code().raw_metadata_end();
}
int CodeDataContainer::unwinding_info_size() const {
return V8_UNLIKELY(is_off_heap_trampoline())
? OffHeapUnwindingInfoSize(*this, builtin_id())
: code().unwinding_info_size();
DCHECK_GE(unwinding_info_end(), unwinding_info_start());
return static_cast<int>(unwinding_info_end() - unwinding_info_start());
}
bool CodeDataContainer::has_unwinding_info() const {
return unwinding_info_size() > 0;
}
#endif
Code Code::GetCodeFromTargetAddress(Address address) {
{
// TODO(jgruber,v8:6666): Support embedded builtins here. We'd need to pass
@ -1554,15 +1623,19 @@ inline bool CodeDataContainer::is_baseline_leave_frame_builtin() const {
#define DEF_PRIMITIVE_FORWARDING_CDC_GETTER(name, type) \
type CodeDataContainer::name() const { return FromCodeT(*this).name(); }
#define DEF_FORWARDING_CDC_GETTER(name, type) \
DEF_GETTER(CodeDataContainer, name, type) { \
return FromCodeT(*this).name(cage_base); \
#define DEF_FORWARDING_CDC_GETTER(name, type, result_if_off_heap) \
DEF_GETTER(CodeDataContainer, name, type) { \
if (is_off_heap_trampoline()) { \
return GetReadOnlyRoots().result_if_off_heap(); \
} \
return FromCodeT(*this).name(cage_base); \
}
DEF_FORWARDING_CDC_GETTER(deoptimization_data, FixedArray)
DEF_FORWARDING_CDC_GETTER(bytecode_or_interpreter_data, HeapObject)
DEF_FORWARDING_CDC_GETTER(source_position_table, ByteArray)
DEF_FORWARDING_CDC_GETTER(bytecode_offset_table, ByteArray)
DEF_FORWARDING_CDC_GETTER(deoptimization_data, FixedArray, empty_fixed_array)
DEF_FORWARDING_CDC_GETTER(bytecode_or_interpreter_data, HeapObject,
empty_fixed_array)
DEF_FORWARDING_CDC_GETTER(source_position_table, ByteArray, empty_byte_array)
DEF_FORWARDING_CDC_GETTER(bytecode_offset_table, ByteArray, empty_byte_array)
#undef DEF_PRIMITIVE_FORWARDING_CDC_GETTER
#undef DEF_FORWARDING_CDC_GETTER

View File

@ -468,17 +468,8 @@ SharedFunctionInfo DeoptimizationData::GetInlinedFunction(int index) {
#ifdef ENABLE_DISASSEMBLER
const char* Code::GetName(Isolate* isolate) const {
if (is_builtin()) {
return Builtins::name(builtin_id());
} else {
// There are some handlers and ICs that we can also find names for with
// Builtins::Lookup.
return isolate->builtins()->Lookup(raw_instruction_start());
}
}
namespace {
void print_pc(std::ostream& os, int pc) {
if (pc == -1) {
os << "NA";
@ -535,8 +526,9 @@ void DeoptimizationData::DeoptimizationDataPrint(std::ostream& os) {
namespace {
inline void DisassembleCodeRange(Isolate* isolate, std::ostream& os, Code code,
Address begin, size_t size,
template <typename CodeOrCodeT>
inline void DisassembleCodeRange(Isolate* isolate, std::ostream& os,
CodeOrCodeT code, Address begin, size_t size,
Address current_pc) {
Address end = begin + size;
AllowHandleAllocation allow_handles;
@ -547,47 +539,49 @@ inline void DisassembleCodeRange(Isolate* isolate, std::ostream& os, Code code,
CodeReference(handle(code, isolate)), current_pc);
}
} // namespace
void Code::Disassemble(const char* name, std::ostream& os, Isolate* isolate,
Address current_pc) {
os << "kind = " << CodeKindToString(kind()) << "\n";
if (name == nullptr) {
name = GetName(isolate);
template <typename CodeOrCodeT>
void Disassemble(const char* name, std::ostream& os, Isolate* isolate,
CodeOrCodeT code, Address current_pc) {
CodeKind kind = code.kind();
os << "kind = " << CodeKindToString(kind) << "\n";
if (name == nullptr && code.is_builtin()) {
name = Builtins::name(code.builtin_id());
}
if ((name != nullptr) && (name[0] != '\0')) {
os << "name = " << name << "\n";
}
if (CodeKindIsOptimizedJSFunction(kind()) && kind() != CodeKind::BASELINE) {
os << "stack_slots = " << stack_slots() << "\n";
if (CodeKindIsOptimizedJSFunction(kind) && kind != CodeKind::BASELINE) {
os << "stack_slots = " << code.stack_slots() << "\n";
}
os << "compiler = "
<< (is_turbofanned() ? "turbofan"
: is_maglevved() ? "maglev"
: kind() == CodeKind::BASELINE ? "baseline"
: "unknown")
<< (code.is_turbofanned() ? "turbofan"
: code.is_maglevved() ? "maglev"
: kind == CodeKind::BASELINE ? "baseline"
: "unknown")
<< "\n";
os << "address = " << reinterpret_cast<void*>(ptr()) << "\n\n";
os << "address = " << reinterpret_cast<void*>(code.ptr()) << "\n\n";
if (is_off_heap_trampoline()) {
int trampoline_size = raw_instruction_size();
if (code.IsCode() && code.is_off_heap_trampoline()) {
Code trampoline_code = Code::cast(code);
int trampoline_size = trampoline_code.raw_instruction_size();
os << "Trampoline (size = " << trampoline_size << ")\n";
DisassembleCodeRange(isolate, os, *this, raw_instruction_start(),
DisassembleCodeRange(isolate, os, trampoline_code,
trampoline_code.raw_instruction_start(),
trampoline_size, current_pc);
os << "\n";
}
{
int code_size = InstructionSize();
int code_size = code.InstructionSize();
os << "Instructions (size = " << code_size << ")\n";
DisassembleCodeRange(isolate, os, *this, InstructionStart(), code_size,
DisassembleCodeRange(isolate, os, code, code.InstructionStart(), code_size,
current_pc);
if (int pool_size = constant_pool_size()) {
if (int pool_size = code.constant_pool_size()) {
DCHECK_EQ(pool_size & kPointerAlignmentMask, 0);
os << "\nConstant Pool (size = " << pool_size << ")\n";
base::Vector<char> buf = base::Vector<char>::New(50);
intptr_t* ptr = reinterpret_cast<intptr_t*>(constant_pool());
intptr_t* ptr = reinterpret_cast<intptr_t*>(code.constant_pool());
for (int i = 0; i < pool_size; i += kSystemPointerSize, ptr++) {
SNPrintF(buf, "%4d %08" V8PRIxPTR, i, *ptr);
os << static_cast<const void*>(ptr) << " " << buf.begin() << "\n";
@ -597,10 +591,10 @@ void Code::Disassemble(const char* name, std::ostream& os, Isolate* isolate,
os << "\n";
// TODO(cbruni): add support for baseline code.
if (kind() != CodeKind::BASELINE) {
if (kind != CodeKind::BASELINE) {
{
SourcePositionTableIterator it(
source_position_table(),
code.source_position_table(),
SourcePositionTableIterator::kJavaScriptOnly);
if (!it.done()) {
os << "Source positions:\n pc offset position\n";
@ -615,7 +609,8 @@ void Code::Disassemble(const char* name, std::ostream& os, Isolate* isolate,
{
SourcePositionTableIterator it(
source_position_table(), SourcePositionTableIterator::kExternalOnly);
code.source_position_table(),
SourcePositionTableIterator::kExternalOnly);
if (!it.done()) {
os << "External Source positions:\n pc offset fileid line\n";
for (; !it.done(); it.Advance()) {
@ -629,48 +624,65 @@ void Code::Disassemble(const char* name, std::ostream& os, Isolate* isolate,
}
}
if (CodeKindCanDeoptimize(kind())) {
if (CodeKindCanDeoptimize(kind)) {
DeoptimizationData data =
DeoptimizationData::cast(this->deoptimization_data());
DeoptimizationData::cast(code.deoptimization_data());
data.DeoptimizationDataPrint(os);
}
os << "\n";
if (uses_safepoint_table()) {
if (is_maglevved()) {
MaglevSafepointTable table(isolate, current_pc, *this);
if (code.uses_safepoint_table()) {
if (code.is_maglevved()) {
MaglevSafepointTable table(isolate, current_pc, code);
table.Print(os);
} else {
SafepointTable table(isolate, current_pc, *this);
SafepointTable table(isolate, current_pc, code);
table.Print(os);
}
os << "\n";
}
if (has_handler_table()) {
HandlerTable table(*this);
if (code.has_handler_table()) {
HandlerTable table(code);
os << "Handler Table (size = " << table.NumberOfReturnEntries() << ")\n";
if (CodeKindIsOptimizedJSFunction(kind())) {
if (CodeKindIsOptimizedJSFunction(kind)) {
table.HandlerTableReturnPrint(os);
}
os << "\n";
}
os << "RelocInfo (size = " << relocation_size() << ")\n";
for (RelocIterator it(*this); !it.done(); it.next()) {
it.rinfo()->Print(isolate, os);
os << "RelocInfo (size = " << code.relocation_size() << ")\n";
if (code.IsCode()) {
for (RelocIterator it(Code::cast(code)); !it.done(); it.next()) {
it.rinfo()->Print(isolate, os);
}
}
os << "\n";
if (has_unwinding_info()) {
os << "UnwindingInfo (size = " << unwinding_info_size() << ")\n";
if (code.has_unwinding_info()) {
os << "UnwindingInfo (size = " << code.unwinding_info_size() << ")\n";
EhFrameDisassembler eh_frame_disassembler(
reinterpret_cast<byte*>(unwinding_info_start()),
reinterpret_cast<byte*>(unwinding_info_end()));
reinterpret_cast<byte*>(code.unwinding_info_start()),
reinterpret_cast<byte*>(code.unwinding_info_end()));
eh_frame_disassembler.DisassembleToStream(os);
os << "\n";
}
}
} // namespace
void Code::Disassemble(const char* name, std::ostream& os, Isolate* isolate,
Address current_pc) {
i::Disassemble(name, os, isolate, *this, current_pc);
}
#ifdef V8_EXTERNAL_CODE_SPACE
void CodeDataContainer::Disassemble(const char* name, std::ostream& os,
Isolate* isolate, Address current_pc) {
i::Disassemble(name, os, isolate, *this, current_pc);
}
#endif // V8_EXTERNAL_CODE_SPACE
#endif // ENABLE_DISASSEMBLER
void BytecodeArray::Disassemble(std::ostream& os) {

View File

@ -180,6 +180,19 @@ class CodeDataContainer : public HeapObject {
inline int constant_pool_size() const;
inline bool has_constant_pool() const;
inline Address code_comments() const;
inline int code_comments_size() const;
inline bool has_code_comments() const;
inline Address unwinding_info_start() const;
inline Address unwinding_info_end() const;
inline int unwinding_info_size() const;
inline bool has_unwinding_info() const;
inline byte* relocation_start() const;
inline byte* relocation_end() const;
inline int relocation_size() const;
// When builtins un-embedding is enabled for the Isolate
// (see Isolate::is_short_builtin_calls_enabled()) then both embedded and
// un-embedded builtins might be exeuted and thus two kinds of |pc|s might
@ -212,6 +225,12 @@ class CodeDataContainer : public HeapObject {
inline int GetOffsetFromInstructionStart(Isolate* isolate, Address pc) const;
#ifdef ENABLE_DISASSEMBLER
V8_EXPORT_PRIVATE void Disassemble(const char* name, std::ostream& os,
Isolate* isolate,
Address current_pc = kNullAddress);
#endif // ENABLE_DISASSEMBLER
#endif // V8_EXTERNAL_CODE_SPACE
DECL_CAST(CodeDataContainer)
@ -418,6 +437,7 @@ class Code : public HeapObject {
// [code_comments_offset]: Offset of the code comment section.
inline int code_comments_offset() const;
inline void set_code_comments_offset(int offset);
inline Address raw_code_comments() const;
inline Address code_comments() const;
inline int code_comments_size() const;
inline bool has_code_comments() const;
@ -425,13 +445,13 @@ class Code : public HeapObject {
// [unwinding_info_offset]: Offset of the unwinding info section.
inline int32_t unwinding_info_offset() const;
inline void set_unwinding_info_offset(int32_t offset);
inline Address raw_unwinding_info_start() const;
inline Address unwinding_info_start() const;
inline Address unwinding_info_end() const;
inline int unwinding_info_size() const;
inline bool has_unwinding_info() const;
#ifdef ENABLE_DISASSEMBLER
const char* GetName(Isolate* isolate) const;
V8_EXPORT_PRIVATE void Disassemble(const char* name, std::ostream& os,
Isolate* isolate,
Address current_pc = kNullAddress);