diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc index 6796fb5f84a..ea1aa0c4a8a 100644 --- a/runtime/vm/clustered_snapshot.cc +++ b/runtime/vm/clustered_snapshot.cc @@ -9,9 +9,12 @@ #include "vm/bss_relocs.h" #include "vm/class_id.h" #include "vm/code_observers.h" +#include "vm/compiler/assembler/disassembler.h" #include "vm/compiler/backend/code_statistics.h" +#include "vm/compiler/backend/il_printer.h" #include "vm/compiler/relocation.h" #include "vm/dart.h" +#include "vm/flag_list.h" #include "vm/heap/heap.h" #include "vm/image_snapshot.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()->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) { @@ -1448,8 +1456,12 @@ class CodeSerializationCluster : public SerializationCluster { WriteField(code, deopt_info_array_); 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(code->ptr()->state_bits_); } } @@ -1565,7 +1577,9 @@ class CodeDeserializationCluster : public DeserializationCluster { #if !defined(PRODUCT) code->ptr()->return_address_metadata_ = d->ReadRef(); code->ptr()->var_descriptors_ = LocalVarDescriptors::null(); - code->ptr()->comments_ = Array::null(); + code->ptr()->comments_ = FLAG_code_comments + ? reinterpret_cast(d->ReadRef()) + : Array::null(); code->ptr()->compile_timestamp_ = 0; #endif @@ -1573,13 +1587,29 @@ 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) { - if (!CodeObservers::AreActive()) return; + if (!CodeObservers::AreActive() && !FLAG_support_disassembler) return; Code& code = Code::Handle(zone); + Object& owner = Object::Handle(zone); for (intptr_t id = start_index_; id < stop_index_; id++) { code ^= refs.At(id); - Code::NotifyCodeObservers(code, code.is_optimized()); +#if !defined(DART_PRECOMPILED_RUNTIME) + if (CodeObservers::AreActive()) { + 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 diff --git a/runtime/vm/compiler/assembler/assembler.cc b/runtime/vm/compiler/assembler/assembler.cc index 6cc1a58efbb..9dfdf2e1c16 100644 --- a/runtime/vm/compiler/assembler/assembler.cc +++ b/runtime/vm/compiler/assembler/assembler.cc @@ -20,10 +20,6 @@ DEFINE_FLAG(bool, false, "Verify instructions offset in code object." "NOTE: This breaks the profiler."); -DEFINE_FLAG(bool, - code_comments, - false, - "Include comments into code and disassembly"); #if defined(TARGET_ARCH_ARM) DEFINE_FLAG(bool, use_far_branches, false, "Enable far branches for ARM."); #endif diff --git a/runtime/vm/compiler/assembler/disassembler.cc b/runtime/vm/compiler/assembler/disassembler.cc index b74310c7b83..ffc8b780dfc 100644 --- a/runtime/vm/compiler/assembler/disassembler.cc +++ b/runtime/vm/compiler/assembler/disassembler.cc @@ -240,10 +240,14 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname, ASSERT(code.pointer_offsets_length() == 0); #endif - const ObjectPool& object_pool = - ObjectPool::Handle(zone, code.GetObjectPool()); - if (!object_pool.IsNull()) { - object_pool.DebugPrint(); + if (FLAG_use_bare_instructions) { + THR_Print("(No object pool for bare instructions.)\n"); + } else { + const ObjectPool& object_pool = + ObjectPool::Handle(zone, code.GetObjectPool()); + if (!object_pool.IsNull()) { + object_pool.DebugPrint(); + } } THR_Print("PC Descriptors for function '%s' {\n", function_fullname); @@ -258,23 +262,25 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname, #if !defined(DART_PRECOMPILED_RUNTIME) const Array& deopt_table = Array::Handle(zone, 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(zone); - TypedData& info = TypedData::Handle(zone); - Smi& reason_and_flags = Smi::Handle(zone); - 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, base + offset.Value(), - DeoptInfo::ToCString(deopt_table, info), - DeoptReasonToCString(static_cast(reason))); + if (!deopt_table.IsNull()) { + intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table); + if (deopt_table_length > 0) { + THR_Print("DeoptInfo: {\n"); + Smi& offset = Smi::Handle(zone); + TypedData& info = TypedData::Handle(zone); + Smi& reason_and_flags = Smi::Handle(zone); + 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, base + offset.Value(), + DeoptInfo::ToCString(deopt_table, info), + DeoptReasonToCString(static_cast(reason))); + } + THR_Print("}\n"); } - THR_Print("}\n"); } #endif // !defined(DART_PRECOMPILED_RUNTIME) @@ -343,6 +349,9 @@ void Disassembler::DisassembleCodeHelper(const char* function_fullname, 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"); 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) { code.DumpInlineIntervals(); @@ -411,6 +421,20 @@ void Disassembler::DisassembleCode(const Function& function, 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) void Disassembler::DisassembleCode(const Function& function, diff --git a/runtime/vm/compiler/assembler/disassembler.h b/runtime/vm/compiler/assembler/disassembler.h index e21068667fc..861051d7dc5 100644 --- a/runtime/vm/compiler/assembler/disassembler.h +++ b/runtime/vm/compiler/assembler/disassembler.h @@ -184,6 +184,8 @@ class Disassembler : public AllStatic { const Code& code, bool optimized); + static void DisassembleStub(const char* name, const Code& code); + private: static void DisassembleCodeHelper(const char* function_fullname, const Code& code, diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc index e1bce80c07f..a27493f7c67 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler.cc +++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc @@ -60,7 +60,6 @@ DEFINE_FLAG(int, "The scale of invocation count, by size of the function."); DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment."); -DECLARE_FLAG(bool, code_comments); DECLARE_FLAG(charp, deoptimize_filter); DECLARE_FLAG(bool, intrinsify); DECLARE_FLAG(int, regexp_optimization_counter_threshold); diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc index 527cc9e822d..b6ba6b279f5 100644 --- a/runtime/vm/compiler/backend/il_printer.cc +++ b/runtime/vm/compiler/backend/il_printer.cc @@ -2,8 +2,6 @@ // 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. -#if !defined(DART_PRECOMPILED_RUNTIME) - #include "vm/compiler/backend/il_printer.h" #include "vm/compiler/backend/il.h" @@ -15,18 +13,11 @@ namespace dart { #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, print_flow_graph_filter, NULL, "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 // a comma-separated list of strings. bool FlowGraphPrinter::PassesFilter(const char* filter, @@ -74,6 +65,16 @@ bool FlowGraphPrinter::ShouldPrint(const Function& 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) { LogBlock lb; THR_Print("*** BEGIN CFG\n%s\n", phase); @@ -1181,8 +1182,12 @@ const char* Environment::ToCString() const { return Thread::Current()->zone()->MakeCopyOfString(buffer); } +#endif // !defined(DART_PRECOMPILED_RUNTIME) + #else // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) +#if !defined(DART_PRECOMPILED_RUNTIME) + const char* Instruction::ToCString() const { return DebugName(); } @@ -1219,8 +1224,8 @@ bool FlowGraphPrinter::ShouldPrint(const Function& function) { return false; } +#endif // !defined(DART_PRECOMPILED_RUNTIME) + #endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) } // namespace dart - -#endif // !defined(DART_PRECOMPILED_RUNTIME) diff --git a/runtime/vm/compiler/graph_intrinsifier.cc b/runtime/vm/compiler/graph_intrinsifier.cc index 9485474d774..e0c0d6394f2 100644 --- a/runtime/vm/compiler/graph_intrinsifier.cc +++ b/runtime/vm/compiler/graph_intrinsifier.cc @@ -17,10 +17,10 @@ #include "vm/compiler/compiler_pass.h" #include "vm/compiler/jit/compiler.h" #include "vm/cpu.h" +#include "vm/flag_list.h" namespace dart { -DECLARE_FLAG(bool, code_comments); DECLARE_FLAG(bool, print_flow_graph); DECLARE_FLAG(bool, print_flow_graph_optimized); @@ -299,8 +299,8 @@ static bool IntrinsifyArraySetIndexed(FlowGraph* flow_graph, break; case kTypedDataInt32ArrayCid: case kExternalTypedDataInt32ArrayCid: - // Use same truncating unbox-instruction for int32 and uint32. - FALL_THROUGH; + // Use same truncating unbox-instruction for int32 and uint32. + FALL_THROUGH; case kTypedDataUint32ArrayCid: case kExternalTypedDataUint32ArrayCid: // Supports smi and mint, slow-case for bigints. diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc index a8a2f94ef51..30eafc1bae8 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -851,6 +851,10 @@ const char* Dart::FeaturesString(Isolate* isolate, buffer.AddString(FLAG_causal_async_stacks ? " 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. #if defined(TARGET_ARCH_ARM) diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h index a3d9e0504c0..3e5757aaccf 100644 --- a/runtime/vm/flag_list.h +++ b/runtime/vm/flag_list.h @@ -71,6 +71,8 @@ constexpr bool kDartUseBytecode = false; R(disassemble_optimized, false, bool, false, "Disassemble optimized code.") \ R(disassemble_relative, false, bool, false, \ "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, \ "Dump megamorphic cache statistics") \ R(dump_symbol_stats, false, bool, false, "Dump symbol table statistics") \ diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc index 739e4fdeec3..dfddab4b9af 100644 --- a/runtime/vm/stub_code.cc +++ b/runtime/vm/stub_code.cc @@ -74,15 +74,7 @@ RawCode* StubCode::Generate( /*optimized=*/false)); #ifndef PRODUCT if (FLAG_support_disassembler && FLAG_disassemble_stubs) { - 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 (!object_pool.IsNull()) { - object_pool.DebugPrint(); - } + Disassembler::DisassembleStub(name, code); } #endif // !PRODUCT return code.raw(); @@ -199,15 +191,7 @@ RawCode* StubCode::GetAllocationStubForClass(const Class& cls) { Code::NotifyCodeObservers(name, stub, /*optimized=*/false); #ifndef PRODUCT if (FLAG_support_disassembler && FLAG_disassemble_stubs) { - LogBlock lb; - 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(); - } + Disassembler::DisassembleStub(name, stub); } #endif // !PRODUCT } @@ -245,15 +229,7 @@ RawCode* StubCode::GetBuildMethodExtractorStub( #ifndef PRODUCT if (FLAG_support_disassembler && FLAG_disassemble_stubs) { - LogBlock lb; - 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(); - } + Disassembler::DisassembleStub(name, stub); } #endif // !PRODUCT return stub.raw(); diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h index cf832cb7d16..8a94b7651c8 100644 --- a/runtime/vm/stub_code.h +++ b/runtime/vm/stub_code.h @@ -22,6 +22,8 @@ class RawCode; class SnapshotReader; class SnapshotWriter; +DECLARE_FLAG(bool, disassemble_stubs); + // Is it permitted for the stubs above to refer to Object::null(), which is // allocated in the VM isolate and shared across all isolates. // However, in cases where a simple GC-safe placeholder is needed on the stack,