Index: runtime/vm/disassembler.cc |
diff --git a/runtime/vm/disassembler.cc b/runtime/vm/disassembler.cc |
index 927a317fa0b385994cb6dbb641599e159d4e31d8..f7a333f470b5b787eb628df2025815a643821d08 100644 |
--- a/runtime/vm/disassembler.cc |
+++ b/runtime/vm/disassembler.cc |
@@ -5,6 +5,7 @@ |
#include "vm/disassembler.h" |
#include "vm/assembler.h" |
+#include "vm/deopt_instructions.h" |
#include "vm/globals.h" |
#include "vm/il_printer.h" |
#include "vm/instructions.h" |
@@ -16,6 +17,8 @@ |
namespace dart { |
+DECLARE_FLAG(bool, trace_inlining_intervals); |
+ |
void DisassembleToStdout::ConsumeInstruction(const Code& code, |
char* hex_buffer, |
intptr_t hex_size, |
@@ -182,4 +185,146 @@ void Disassembler::Disassemble(uword start, |
} |
} |
+ |
+void Disassembler::DisassembleCode(const Function& function, bool optimized) { |
+ const char* function_fullname = function.ToFullyQualifiedCString(); |
+ THR_Print("Code for %sfunction '%s' {\n", |
+ optimized ? "optimized " : "", |
+ function_fullname); |
+ const Code& code = Code::Handle(function.CurrentCode()); |
+ code.Disassemble(); |
+ THR_Print("}\n"); |
+ |
+ THR_Print("Pointer offsets for function: {\n"); |
+ // Pointer offsets are stored in descending order. |
+ Object& obj = Object::Handle(); |
+ for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) { |
+ const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint(); |
+ obj = *reinterpret_cast<RawObject**>(addr); |
+ THR_Print(" %d : %#" Px " '%s'\n", |
+ code.GetPointerOffsetAt(i), addr, obj.ToCString()); |
+ } |
+ THR_Print("}\n"); |
+ |
+ THR_Print("PC Descriptors for function '%s' {\n", function_fullname); |
+ PcDescriptors::PrintHeaderString(); |
+ const PcDescriptors& descriptors = |
+ PcDescriptors::Handle(code.pc_descriptors()); |
+ THR_Print("%s}\n", descriptors.ToCString()); |
+ |
+ uword start = Instructions::Handle(code.instructions()).EntryPoint(); |
+ const Array& deopt_table = Array::Handle(code.deopt_info_array()); |
+ intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table); |
+ if (deopt_table_length > 0) { |
+ THR_Print("DeoptInfo: {\n"); |
+ Smi& offset = Smi::Handle(); |
+ TypedData& info = TypedData::Handle(); |
+ Smi& reason_and_flags = Smi::Handle(); |
+ for (intptr_t i = 0; i < deopt_table_length; ++i) { |
+ DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason_and_flags); |
+ const intptr_t reason = |
+ DeoptTable::ReasonField::decode(reason_and_flags.Value()); |
+ ASSERT((0 <= reason) && (reason < ICData::kDeoptNumReasons)); |
+ THR_Print("%4" Pd ": 0x%" Px " %s (%s)\n", |
+ i, |
+ start + offset.Value(), |
+ DeoptInfo::ToCString(deopt_table, info), |
+ DeoptReasonToCString( |
+ static_cast<ICData::DeoptReasonId>(reason))); |
+ } |
+ THR_Print("}\n"); |
+ } |
+ |
+ const ObjectPool& object_pool = ObjectPool::Handle(code.GetObjectPool()); |
+ object_pool.DebugPrint(); |
+ |
+ THR_Print("Stackmaps for function '%s' {\n", function_fullname); |
+ if (code.stackmaps() != Array::null()) { |
+ const Array& stackmap_table = Array::Handle(code.stackmaps()); |
+ Stackmap& map = Stackmap::Handle(); |
+ for (intptr_t i = 0; i < stackmap_table.Length(); ++i) { |
+ map ^= stackmap_table.At(i); |
+ THR_Print("%s\n", map.ToCString()); |
+ } |
+ } |
+ THR_Print("}\n"); |
+ |
+ THR_Print("Variable Descriptors for function '%s' {\n", |
+ function_fullname); |
+ const LocalVarDescriptors& var_descriptors = |
+ LocalVarDescriptors::Handle(code.GetLocalVarDescriptors()); |
+ intptr_t var_desc_length = |
+ var_descriptors.IsNull() ? 0 : var_descriptors.Length(); |
+ String& var_name = String::Handle(); |
+ for (intptr_t i = 0; i < var_desc_length; i++) { |
+ var_name = var_descriptors.GetName(i); |
+ RawLocalVarDescriptors::VarInfo var_info; |
+ var_descriptors.GetInfo(i, &var_info); |
+ const int8_t kind = var_info.kind(); |
+ if (kind == RawLocalVarDescriptors::kSavedCurrentContext) { |
+ THR_Print(" saved current CTX reg offset %d\n", var_info.index()); |
+ } else { |
+ if (kind == RawLocalVarDescriptors::kContextLevel) { |
+ THR_Print(" context level %d scope %d", var_info.index(), |
+ var_info.scope_id); |
+ } else if (kind == RawLocalVarDescriptors::kStackVar) { |
+ THR_Print(" stack var '%s' offset %d", |
+ var_name.ToCString(), var_info.index()); |
+ } else { |
+ ASSERT(kind == RawLocalVarDescriptors::kContextVar); |
+ THR_Print(" context var '%s' level %d offset %d", |
+ var_name.ToCString(), var_info.scope_id, var_info.index()); |
+ } |
+ THR_Print(" (valid %s-%s)\n", var_info.begin_pos.ToCString(), |
+ var_info.end_pos.ToCString()); |
+ } |
+ } |
+ THR_Print("}\n"); |
+ |
+ THR_Print("Exception Handlers for function '%s' {\n", function_fullname); |
+ const ExceptionHandlers& handlers = |
+ ExceptionHandlers::Handle(code.exception_handlers()); |
+ THR_Print("%s}\n", handlers.ToCString()); |
+ |
+ { |
+ THR_Print("Static call target functions {\n"); |
+ const Array& table = Array::Handle(code.static_calls_target_table()); |
+ Smi& offset = Smi::Handle(); |
+ Function& function = Function::Handle(); |
+ Code& code = Code::Handle(); |
+ for (intptr_t i = 0; i < table.Length(); |
+ i += Code::kSCallTableEntryLength) { |
+ offset ^= table.At(i + Code::kSCallTableOffsetEntry); |
+ function ^= table.At(i + Code::kSCallTableFunctionEntry); |
+ code ^= table.At(i + Code::kSCallTableCodeEntry); |
+ if (function.IsNull()) { |
+ Class& cls = Class::Handle(); |
+ cls ^= code.owner(); |
+ if (cls.IsNull()) { |
+ const String& code_name = String::Handle(code.Name()); |
+ THR_Print(" 0x%" Px ": %s, %p\n", |
+ start + offset.Value(), |
+ code_name.ToCString(), |
+ code.raw()); |
+ } else { |
+ THR_Print(" 0x%" Px ": allocation stub for %s, %p\n", |
+ start + offset.Value(), |
+ cls.ToCString(), |
+ code.raw()); |
+ } |
+ } else { |
+ THR_Print(" 0x%" Px ": %s, %p\n", |
+ start + offset.Value(), |
+ function.ToFullyQualifiedCString(), |
+ code.raw()); |
+ } |
+ } |
+ THR_Print("}\n"); |
+ } |
+ if (optimized && FLAG_trace_inlining_intervals) { |
+ code.DumpInlinedIntervals(); |
+ } |
+} |
+ |
+ |
} // namespace dart |