mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 21:21:18 +00:00
[vm] Support disassembling snapshot code at runtime for JIT and AOT snapshots.
--code-comments should be passed both at compile/training-time and run-time to get comments in the disassembled instructions. The required --disassemble-* flags need only be passed at run-time. Flow-graph printing is not yet supported because we don't save flow-graph like assembly comments. This functionality is excluded from product builds. Change-Id: If35fbb08cff6eae40069f916ecec9c6f589c0cad Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/124989 Commit-Queue: Samir Jindel <sjindel@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
3bd7ed38fb
commit
dd7760a07d
|
@ -9,9 +9,12 @@
|
||||||
#include "vm/bss_relocs.h"
|
#include "vm/bss_relocs.h"
|
||||||
#include "vm/class_id.h"
|
#include "vm/class_id.h"
|
||||||
#include "vm/code_observers.h"
|
#include "vm/code_observers.h"
|
||||||
|
#include "vm/compiler/assembler/disassembler.h"
|
||||||
#include "vm/compiler/backend/code_statistics.h"
|
#include "vm/compiler/backend/code_statistics.h"
|
||||||
|
#include "vm/compiler/backend/il_printer.h"
|
||||||
#include "vm/compiler/relocation.h"
|
#include "vm/compiler/relocation.h"
|
||||||
#include "vm/dart.h"
|
#include "vm/dart.h"
|
||||||
|
#include "vm/flag_list.h"
|
||||||
#include "vm/heap/heap.h"
|
#include "vm/heap/heap.h"
|
||||||
#include "vm/image_snapshot.h"
|
#include "vm/image_snapshot.h"
|
||||||
#include "vm/native_entry.h"
|
#include "vm/native_entry.h"
|
||||||
|
@ -1387,7 +1390,12 @@ class CodeSerializationCluster : public SerializationCluster {
|
||||||
s->Push(code->ptr()->deopt_info_array_);
|
s->Push(code->ptr()->deopt_info_array_);
|
||||||
s->Push(code->ptr()->static_calls_target_table_);
|
s->Push(code->ptr()->static_calls_target_table_);
|
||||||
}
|
}
|
||||||
NOT_IN_PRODUCT(s->Push(code->ptr()->return_address_metadata_));
|
#if !defined(PRODUCT)
|
||||||
|
s->Push(code->ptr()->return_address_metadata_);
|
||||||
|
if (FLAG_code_comments) {
|
||||||
|
s->Push(code->ptr()->comments_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteAlloc(Serializer* s) {
|
void WriteAlloc(Serializer* s) {
|
||||||
|
@ -1448,8 +1456,12 @@ class CodeSerializationCluster : public SerializationCluster {
|
||||||
WriteField(code, deopt_info_array_);
|
WriteField(code, deopt_info_array_);
|
||||||
WriteField(code, static_calls_target_table_);
|
WriteField(code, static_calls_target_table_);
|
||||||
}
|
}
|
||||||
NOT_IN_PRODUCT(WriteField(code, return_address_metadata_));
|
#if !defined(PRODUCT)
|
||||||
|
WriteField(code, return_address_metadata_);
|
||||||
|
if (FLAG_code_comments) {
|
||||||
|
WriteField(code, comments_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
s->Write<int32_t>(code->ptr()->state_bits_);
|
s->Write<int32_t>(code->ptr()->state_bits_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1565,7 +1577,9 @@ class CodeDeserializationCluster : public DeserializationCluster {
|
||||||
#if !defined(PRODUCT)
|
#if !defined(PRODUCT)
|
||||||
code->ptr()->return_address_metadata_ = d->ReadRef();
|
code->ptr()->return_address_metadata_ = d->ReadRef();
|
||||||
code->ptr()->var_descriptors_ = LocalVarDescriptors::null();
|
code->ptr()->var_descriptors_ = LocalVarDescriptors::null();
|
||||||
code->ptr()->comments_ = Array::null();
|
code->ptr()->comments_ = FLAG_code_comments
|
||||||
|
? reinterpret_cast<RawArray*>(d->ReadRef())
|
||||||
|
: Array::null();
|
||||||
code->ptr()->compile_timestamp_ = 0;
|
code->ptr()->compile_timestamp_ = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1573,14 +1587,30 @@ class CodeDeserializationCluster : public DeserializationCluster {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !(defined(DART_PRECOMPILED_RUNTIME) || defined(PRODUCT))
|
#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
||||||
void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
|
void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
|
||||||
if (!CodeObservers::AreActive()) return;
|
if (!CodeObservers::AreActive() && !FLAG_support_disassembler) return;
|
||||||
Code& code = Code::Handle(zone);
|
Code& code = Code::Handle(zone);
|
||||||
|
Object& owner = Object::Handle(zone);
|
||||||
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
||||||
code ^= refs.At(id);
|
code ^= refs.At(id);
|
||||||
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||||
|
if (CodeObservers::AreActive()) {
|
||||||
Code::NotifyCodeObservers(code, code.is_optimized());
|
Code::NotifyCodeObservers(code, code.is_optimized());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
owner = code.owner();
|
||||||
|
if (owner.IsFunction()) {
|
||||||
|
if ((FLAG_disassemble ||
|
||||||
|
(code.is_optimized() && FLAG_disassemble_optimized)) &&
|
||||||
|
FlowGraphPrinter::ShouldPrint(Function::Cast(owner))) {
|
||||||
|
Disassembler::DisassembleCode(Function::Cast(owner), code,
|
||||||
|
code.is_optimized());
|
||||||
|
}
|
||||||
|
} else if (FLAG_disassemble_stubs) {
|
||||||
|
Disassembler::DisassembleStub(code.Name(), code);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // !DART_PRECOMPILED_RUNTIME
|
#endif // !DART_PRECOMPILED_RUNTIME
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,10 +20,6 @@ DEFINE_FLAG(bool,
|
||||||
false,
|
false,
|
||||||
"Verify instructions offset in code object."
|
"Verify instructions offset in code object."
|
||||||
"NOTE: This breaks the profiler.");
|
"NOTE: This breaks the profiler.");
|
||||||
DEFINE_FLAG(bool,
|
|
||||||
code_comments,
|
|
||||||
false,
|
|
||||||
"Include comments into code and disassembly");
|
|
||||||
#if defined(TARGET_ARCH_ARM)
|
#if defined(TARGET_ARCH_ARM)
|
||||||
DEFINE_FLAG(bool, use_far_branches, false, "Enable far branches for ARM.");
|
DEFINE_FLAG(bool, use_far_branches, false, "Enable far branches for ARM.");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -240,11 +240,15 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname,
|
||||||
ASSERT(code.pointer_offsets_length() == 0);
|
ASSERT(code.pointer_offsets_length() == 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (FLAG_use_bare_instructions) {
|
||||||
|
THR_Print("(No object pool for bare instructions.)\n");
|
||||||
|
} else {
|
||||||
const ObjectPool& object_pool =
|
const ObjectPool& object_pool =
|
||||||
ObjectPool::Handle(zone, code.GetObjectPool());
|
ObjectPool::Handle(zone, code.GetObjectPool());
|
||||||
if (!object_pool.IsNull()) {
|
if (!object_pool.IsNull()) {
|
||||||
object_pool.DebugPrint();
|
object_pool.DebugPrint();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
THR_Print("PC Descriptors for function '%s' {\n", function_fullname);
|
THR_Print("PC Descriptors for function '%s' {\n", function_fullname);
|
||||||
PcDescriptors::PrintHeaderString();
|
PcDescriptors::PrintHeaderString();
|
||||||
|
@ -258,6 +262,7 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname,
|
||||||
|
|
||||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||||
const Array& deopt_table = Array::Handle(zone, code.deopt_info_array());
|
const Array& deopt_table = Array::Handle(zone, code.deopt_info_array());
|
||||||
|
if (!deopt_table.IsNull()) {
|
||||||
intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
|
intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
|
||||||
if (deopt_table_length > 0) {
|
if (deopt_table_length > 0) {
|
||||||
THR_Print("DeoptInfo: {\n");
|
THR_Print("DeoptInfo: {\n");
|
||||||
|
@ -276,6 +281,7 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname,
|
||||||
}
|
}
|
||||||
THR_Print("}\n");
|
THR_Print("}\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||||
|
|
||||||
THR_Print("StackMaps for function '%s' {\n", function_fullname);
|
THR_Print("StackMaps for function '%s' {\n", function_fullname);
|
||||||
|
@ -343,6 +349,9 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname,
|
||||||
THR_Print("}\n");
|
THR_Print("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||||
|
THR_Print("(Cannot show static call target functions in AOT runtime.)\n");
|
||||||
|
#else
|
||||||
{
|
{
|
||||||
THR_Print("Static call target functions {\n");
|
THR_Print("Static call target functions {\n");
|
||||||
const auto& table = Array::Handle(zone, code.static_calls_target_table());
|
const auto& table = Array::Handle(zone, code.static_calls_target_table());
|
||||||
|
@ -393,8 +402,9 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
THR_Print("}\n");
|
THR_Print("}\n");
|
||||||
|
}
|
||||||
|
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||||
|
|
||||||
if (optimized && FLAG_trace_inlining_intervals) {
|
if (optimized && FLAG_trace_inlining_intervals) {
|
||||||
code.DumpInlineIntervals();
|
code.DumpInlineIntervals();
|
||||||
|
@ -411,6 +421,20 @@ void Disassembler::DisassembleCode(const Function& function,
|
||||||
DisassembleCodeHelper(function_fullname, code, optimized);
|
DisassembleCodeHelper(function_fullname, code, optimized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Disassembler::DisassembleStub(const char* name, const Code& code) {
|
||||||
|
LogBlock lb;
|
||||||
|
THR_Print("Code for stub '%s': {\n", name);
|
||||||
|
DisassembleToStdout formatter;
|
||||||
|
code.Disassemble(&formatter);
|
||||||
|
THR_Print("}\n");
|
||||||
|
const ObjectPool& object_pool = ObjectPool::Handle(code.object_pool());
|
||||||
|
if (FLAG_use_bare_instructions) {
|
||||||
|
THR_Print("(No object pool for bare instructions.)\n");
|
||||||
|
} else if (!object_pool.IsNull()) {
|
||||||
|
object_pool.DebugPrint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
#else // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
||||||
|
|
||||||
void Disassembler::DisassembleCode(const Function& function,
|
void Disassembler::DisassembleCode(const Function& function,
|
||||||
|
|
|
@ -184,6 +184,8 @@ class Disassembler : public AllStatic {
|
||||||
const Code& code,
|
const Code& code,
|
||||||
bool optimized);
|
bool optimized);
|
||||||
|
|
||||||
|
static void DisassembleStub(const char* name, const Code& code);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void DisassembleCodeHelper(const char* function_fullname,
|
static void DisassembleCodeHelper(const char* function_fullname,
|
||||||
const Code& code,
|
const Code& code,
|
||||||
|
|
|
@ -60,7 +60,6 @@ DEFINE_FLAG(int,
|
||||||
"The scale of invocation count, by size of the function.");
|
"The scale of invocation count, by size of the function.");
|
||||||
DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment.");
|
DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment.");
|
||||||
|
|
||||||
DECLARE_FLAG(bool, code_comments);
|
|
||||||
DECLARE_FLAG(charp, deoptimize_filter);
|
DECLARE_FLAG(charp, deoptimize_filter);
|
||||||
DECLARE_FLAG(bool, intrinsify);
|
DECLARE_FLAG(bool, intrinsify);
|
||||||
DECLARE_FLAG(int, regexp_optimization_counter_threshold);
|
DECLARE_FLAG(int, regexp_optimization_counter_threshold);
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
// for details. All rights reserved. Use of this source code is governed by a
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
||||||
|
|
||||||
#include "vm/compiler/backend/il_printer.h"
|
#include "vm/compiler/backend/il_printer.h"
|
||||||
|
|
||||||
#include "vm/compiler/backend/il.h"
|
#include "vm/compiler/backend/il.h"
|
||||||
|
@ -15,18 +13,11 @@ namespace dart {
|
||||||
|
|
||||||
#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
||||||
|
|
||||||
DEFINE_FLAG(bool,
|
|
||||||
display_sorted_ic_data,
|
|
||||||
false,
|
|
||||||
"Calls display a unary, sorted-by count form of ICData");
|
|
||||||
DEFINE_FLAG(bool, print_environments, false, "Print SSA environments.");
|
|
||||||
DEFINE_FLAG(charp,
|
DEFINE_FLAG(charp,
|
||||||
print_flow_graph_filter,
|
print_flow_graph_filter,
|
||||||
NULL,
|
NULL,
|
||||||
"Print only IR of functions with matching names");
|
"Print only IR of functions with matching names");
|
||||||
|
|
||||||
DECLARE_FLAG(bool, trace_inlining_intervals);
|
|
||||||
|
|
||||||
// Checks whether function's name matches the given filter, which is
|
// Checks whether function's name matches the given filter, which is
|
||||||
// a comma-separated list of strings.
|
// a comma-separated list of strings.
|
||||||
bool FlowGraphPrinter::PassesFilter(const char* filter,
|
bool FlowGraphPrinter::PassesFilter(const char* filter,
|
||||||
|
@ -74,6 +65,16 @@ bool FlowGraphPrinter::ShouldPrint(const Function& function) {
|
||||||
return PassesFilter(FLAG_print_flow_graph_filter, function);
|
return PassesFilter(FLAG_print_flow_graph_filter, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||||
|
|
||||||
|
DEFINE_FLAG(bool,
|
||||||
|
display_sorted_ic_data,
|
||||||
|
false,
|
||||||
|
"Calls display a unary, sorted-by count form of ICData");
|
||||||
|
DEFINE_FLAG(bool, print_environments, false, "Print SSA environments.");
|
||||||
|
|
||||||
|
DECLARE_FLAG(bool, trace_inlining_intervals);
|
||||||
|
|
||||||
void FlowGraphPrinter::PrintGraph(const char* phase, FlowGraph* flow_graph) {
|
void FlowGraphPrinter::PrintGraph(const char* phase, FlowGraph* flow_graph) {
|
||||||
LogBlock lb;
|
LogBlock lb;
|
||||||
THR_Print("*** BEGIN CFG\n%s\n", phase);
|
THR_Print("*** BEGIN CFG\n%s\n", phase);
|
||||||
|
@ -1181,8 +1182,12 @@ const char* Environment::ToCString() const {
|
||||||
return Thread::Current()->zone()->MakeCopyOfString(buffer);
|
return Thread::Current()->zone()->MakeCopyOfString(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||||
|
|
||||||
#else // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
#else // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
||||||
|
|
||||||
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||||
|
|
||||||
const char* Instruction::ToCString() const {
|
const char* Instruction::ToCString() const {
|
||||||
return DebugName();
|
return DebugName();
|
||||||
}
|
}
|
||||||
|
@ -1219,8 +1224,8 @@ bool FlowGraphPrinter::ShouldPrint(const Function& function) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||||
|
|
||||||
#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
|
||||||
|
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
||||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
#include "vm/compiler/compiler_pass.h"
|
#include "vm/compiler/compiler_pass.h"
|
||||||
#include "vm/compiler/jit/compiler.h"
|
#include "vm/compiler/jit/compiler.h"
|
||||||
#include "vm/cpu.h"
|
#include "vm/cpu.h"
|
||||||
|
#include "vm/flag_list.h"
|
||||||
|
|
||||||
namespace dart {
|
namespace dart {
|
||||||
|
|
||||||
DECLARE_FLAG(bool, code_comments);
|
|
||||||
DECLARE_FLAG(bool, print_flow_graph);
|
DECLARE_FLAG(bool, print_flow_graph);
|
||||||
DECLARE_FLAG(bool, print_flow_graph_optimized);
|
DECLARE_FLAG(bool, print_flow_graph_optimized);
|
||||||
|
|
||||||
|
|
|
@ -851,6 +851,10 @@ const char* Dart::FeaturesString(Isolate* isolate,
|
||||||
buffer.AddString(FLAG_causal_async_stacks ? " causal_async_stacks"
|
buffer.AddString(FLAG_causal_async_stacks ? " causal_async_stacks"
|
||||||
: " no-causal_async_stacks");
|
: " no-causal_async_stacks");
|
||||||
|
|
||||||
|
#if !defined(PRODUCT)
|
||||||
|
buffer.AddString(FLAG_code_comments ? " code-comments"
|
||||||
|
: " no-code-comments");
|
||||||
|
#endif
|
||||||
|
|
||||||
// Generated code must match the host architecture and ABI.
|
// Generated code must match the host architecture and ABI.
|
||||||
#if defined(TARGET_ARCH_ARM)
|
#if defined(TARGET_ARCH_ARM)
|
||||||
|
|
|
@ -71,6 +71,8 @@ constexpr bool kDartUseBytecode = false;
|
||||||
R(disassemble_optimized, false, bool, false, "Disassemble optimized code.") \
|
R(disassemble_optimized, false, bool, false, "Disassemble optimized code.") \
|
||||||
R(disassemble_relative, false, bool, false, \
|
R(disassemble_relative, false, bool, false, \
|
||||||
"Use offsets instead of absolute PCs") \
|
"Use offsets instead of absolute PCs") \
|
||||||
|
R(code_comments, false, bool, false, \
|
||||||
|
"Include comments into code and disassembly.") \
|
||||||
R(dump_megamorphic_stats, false, bool, false, \
|
R(dump_megamorphic_stats, false, bool, false, \
|
||||||
"Dump megamorphic cache statistics") \
|
"Dump megamorphic cache statistics") \
|
||||||
R(dump_symbol_stats, false, bool, false, "Dump symbol table statistics") \
|
R(dump_symbol_stats, false, bool, false, "Dump symbol table statistics") \
|
||||||
|
|
|
@ -74,15 +74,7 @@ RawCode* StubCode::Generate(
|
||||||
/*optimized=*/false));
|
/*optimized=*/false));
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
|
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
|
||||||
LogBlock lb;
|
Disassembler::DisassembleStub(name, code);
|
||||||
THR_Print("Code for stub '%s': {\n", name);
|
|
||||||
DisassembleToStdout formatter;
|
|
||||||
code.Disassemble(&formatter);
|
|
||||||
THR_Print("}\n");
|
|
||||||
const ObjectPool& object_pool = ObjectPool::Handle(code.object_pool());
|
|
||||||
if (!object_pool.IsNull()) {
|
|
||||||
object_pool.DebugPrint();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
#endif // !PRODUCT
|
||||||
return code.raw();
|
return code.raw();
|
||||||
|
@ -199,15 +191,7 @@ RawCode* StubCode::GetAllocationStubForClass(const Class& cls) {
|
||||||
Code::NotifyCodeObservers(name, stub, /*optimized=*/false);
|
Code::NotifyCodeObservers(name, stub, /*optimized=*/false);
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
|
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
|
||||||
LogBlock lb;
|
Disassembler::DisassembleStub(name, stub);
|
||||||
THR_Print("Code for allocation stub '%s': {\n", name);
|
|
||||||
DisassembleToStdout formatter;
|
|
||||||
stub.Disassemble(&formatter);
|
|
||||||
THR_Print("}\n");
|
|
||||||
const ObjectPool& object_pool = ObjectPool::Handle(stub.object_pool());
|
|
||||||
if (!object_pool.IsNull()) {
|
|
||||||
object_pool.DebugPrint();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
#endif // !PRODUCT
|
||||||
}
|
}
|
||||||
|
@ -245,15 +229,7 @@ RawCode* StubCode::GetBuildMethodExtractorStub(
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
|
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
|
||||||
LogBlock lb;
|
Disassembler::DisassembleStub(name, stub);
|
||||||
THR_Print("Code for isolate stub '%s': {\n", name);
|
|
||||||
DisassembleToStdout formatter;
|
|
||||||
stub.Disassemble(&formatter);
|
|
||||||
THR_Print("}\n");
|
|
||||||
const ObjectPool& object_pool = ObjectPool::Handle(stub.object_pool());
|
|
||||||
if (!object_pool.IsNull()) {
|
|
||||||
object_pool.DebugPrint();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
#endif // !PRODUCT
|
||||||
return stub.raw();
|
return stub.raw();
|
||||||
|
|
|
@ -22,6 +22,8 @@ class RawCode;
|
||||||
class SnapshotReader;
|
class SnapshotReader;
|
||||||
class SnapshotWriter;
|
class SnapshotWriter;
|
||||||
|
|
||||||
|
DECLARE_FLAG(bool, disassemble_stubs);
|
||||||
|
|
||||||
// Is it permitted for the stubs above to refer to Object::null(), which is
|
// Is it permitted for the stubs above to refer to Object::null(), which is
|
||||||
// allocated in the VM isolate and shared across all isolates.
|
// allocated in the VM isolate and shared across all isolates.
|
||||||
// However, in cases where a simple GC-safe placeholder is needed on the stack,
|
// However, in cases where a simple GC-safe placeholder is needed on the stack,
|
||||||
|
|
Loading…
Reference in a new issue