[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:
parent
0bc4b452af
commit
8daad0ea86
@ -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);
|
||||
|
||||
|
@ -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 HANDLE_WASM(...) __VA_ARGS__
|
||||
#else
|
||||
#define HANDLE_WASM(...) UNREACHABLE()
|
||||
#endif
|
||||
|
||||
#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: \
|
||||
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(); \
|
||||
} \
|
||||
}
|
||||
#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(); \
|
||||
} \
|
||||
}
|
||||
#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
|
||||
|
@ -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()
|
||||
|
@ -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)) {
|
||||
while (!rit.done() && rit.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();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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) \
|
||||
#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
|
||||
|
@ -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"
|
||||
<< (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()) {
|
||||
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) {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user