Index: runtime/vm/flow_graph_compiler.cc |
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc |
index 2ab89c18385195dcac096b510b7c5fd591b53f3c..b23b034049f402cf3de3b64022eba7cf6257fd6d 100644 |
--- a/runtime/vm/flow_graph_compiler.cc |
+++ b/runtime/vm/flow_graph_compiler.cc |
@@ -196,7 +196,6 @@ FlowGraphCompiler::FlowGraphCompiler( |
pc_descriptors_list_(NULL), |
stackmap_table_builder_(NULL), |
code_source_map_builder_(NULL), |
- saved_code_size_(0), |
block_info_(block_order_.length()), |
deopt_infos_(), |
static_calls_target_table_(), |
@@ -217,11 +216,7 @@ FlowGraphCompiler::FlowGraphCompiler( |
parallel_move_resolver_(this), |
pending_deoptimization_env_(NULL), |
deopt_id_to_ic_data_(NULL), |
- edge_counters_array_(Array::ZoneHandle()), |
- inlined_code_intervals_(Array::ZoneHandle(Object::empty_array().raw())), |
- inline_id_to_function_(inline_id_to_function), |
- inline_id_to_token_pos_(inline_id_to_token_pos), |
- caller_inline_id_(caller_inline_id) { |
+ edge_counters_array_(Array::ZoneHandle()) { |
ASSERT(flow_graph->parsed_function().function().raw() == |
parsed_function.function().raw()); |
if (!is_optimizing) { |
@@ -244,6 +239,9 @@ FlowGraphCompiler::FlowGraphCompiler( |
} |
ASSERT(assembler != NULL); |
ASSERT(!list_class_.IsNull()); |
+ |
+ code_source_map_builder_ = new (zone_) CodeSourceMapBuilder( |
+ caller_inline_id, inline_id_to_token_pos, inline_id_to_function); |
} |
@@ -463,22 +461,6 @@ static void LoopInfoComment( |
} |
-// We collect intervals while generating code. |
-struct IntervalStruct { |
- // 'start' is the pc-offsets where the inlined code started. |
- // 'pos' is the token position where the inlined call occured. |
- intptr_t start; |
- TokenPosition pos; |
- intptr_t inlining_id; |
- IntervalStruct(intptr_t s, TokenPosition tp, intptr_t id) |
- : start(s), pos(tp), inlining_id(id) {} |
- void Dump() { |
- THR_Print("start: 0x%" Px " iid: %" Pd " pos: %s", start, inlining_id, |
- pos.ToCString()); |
- } |
-}; |
- |
- |
void FlowGraphCompiler::VisitBlocks() { |
CompactBlocks(); |
const ZoneGrowableArray<BlockEntryInstr*>* loop_headers = NULL; |
@@ -488,12 +470,6 @@ void FlowGraphCompiler::VisitBlocks() { |
ASSERT(loop_headers != NULL); |
} |
- // For collecting intervals of inlined code. |
- GrowableArray<IntervalStruct> intervals; |
- intptr_t prev_offset = 0; |
- intptr_t prev_inlining_id = 0; |
- TokenPosition prev_inlining_pos = parsed_function_.function().token_pos(); |
- intptr_t max_inlining_id = 0; |
for (intptr_t i = 0; i < block_order().length(); ++i) { |
// Compile the block entry. |
BlockEntryInstr* entry = block_order()[i]; |
@@ -523,24 +499,8 @@ void FlowGraphCompiler::VisitBlocks() { |
for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
Instruction* instr = it.Current(); |
// Compose intervals. |
- if (instr->has_inlining_id() && is_optimizing()) { |
- if (prev_inlining_id != instr->inlining_id()) { |
- intervals.Add( |
- IntervalStruct(prev_offset, prev_inlining_pos, prev_inlining_id)); |
- prev_offset = assembler()->CodeSize(); |
- prev_inlining_id = instr->inlining_id(); |
- if (prev_inlining_id < inline_id_to_token_pos_.length()) { |
- prev_inlining_pos = inline_id_to_token_pos_[prev_inlining_id]; |
- } else { |
- // We will add this token position later when generating the |
- // profile. |
- prev_inlining_pos = TokenPosition::kNoSource; |
- } |
- if (prev_inlining_id > max_inlining_id) { |
- max_inlining_id = prev_inlining_id; |
- } |
- } |
- } |
+ code_source_map_builder_->StartInliningInterval(assembler()->CodeSize(), |
+ instr->inlining_id()); |
if (FLAG_code_comments || FLAG_disassemble || |
FLAG_disassemble_optimized) { |
if (FLAG_source_lines) { |
@@ -573,53 +533,7 @@ void FlowGraphCompiler::VisitBlocks() { |
#endif |
} |
- if (is_optimizing()) { |
- LogBlock lb; |
- intervals.Add( |
- IntervalStruct(prev_offset, prev_inlining_pos, prev_inlining_id)); |
- inlined_code_intervals_ = |
- Array::New(intervals.length() * Code::kInlIntNumEntries, Heap::kOld); |
- Smi& start_h = Smi::Handle(); |
- Smi& caller_inline_id = Smi::Handle(); |
- Smi& inline_id = Smi::Handle(); |
- for (intptr_t i = 0; i < intervals.length(); i++) { |
- if (FLAG_trace_inlining_intervals && is_optimizing()) { |
- const Function& function = |
- *inline_id_to_function_.At(intervals[i].inlining_id); |
- intervals[i].Dump(); |
- THR_Print(" parent iid %" Pd " %s\n", |
- caller_inline_id_[intervals[i].inlining_id], |
- function.ToQualifiedCString()); |
- } |
- |
- const intptr_t id = intervals[i].inlining_id; |
- start_h = Smi::New(intervals[i].start); |
- inline_id = Smi::New(id); |
- caller_inline_id = Smi::New(caller_inline_id_[intervals[i].inlining_id]); |
- |
- const intptr_t p = i * Code::kInlIntNumEntries; |
- inlined_code_intervals_.SetAt(p + Code::kInlIntStart, start_h); |
- inlined_code_intervals_.SetAt(p + Code::kInlIntInliningId, inline_id); |
- } |
- } |
set_current_block(NULL); |
- if (FLAG_trace_inlining_intervals && is_optimizing()) { |
- LogBlock lb; |
- THR_Print("Intervals:\n"); |
- for (intptr_t cc = 0; cc < caller_inline_id_.length(); cc++) { |
- THR_Print(" iid: %" Pd " caller iid: %" Pd "\n", cc, |
- caller_inline_id_[cc]); |
- } |
- Smi& temp = Smi::Handle(); |
- for (intptr_t i = 0; i < inlined_code_intervals_.Length(); |
- i += Code::kInlIntNumEntries) { |
- temp ^= inlined_code_intervals_.At(i + Code::kInlIntStart); |
- ASSERT(!temp.IsNull()); |
- THR_Print("% " Pd " start: 0x%" Px " ", i, temp.Value()); |
- temp ^= inlined_code_intervals_.At(i + Code::kInlIntInliningId); |
- THR_Print("iid: %" Pd " ", temp.Value()); |
- } |
- } |
} |
@@ -1112,6 +1026,39 @@ void FlowGraphCompiler::FinalizeStaticCallTargetsTable(const Code& code) { |
} |
+void FlowGraphCompiler::FinalizeCodeSourceMap(const Code& code) { |
+#ifdef PRODUCT |
+// This data is only used by the profiler. |
+#else |
+ if (FLAG_precompiled_mode) { |
+ // TODO(rmacnak): Include a filtered verion of this to produce stack traces |
+ // with inlined frames. |
+ return; |
+ } |
+ |
+ const Array& inlined_id_array = |
+ Array::Handle(zone(), code_source_map_builder_->InliningIdToFunction()); |
+ INC_STAT(Thread::Current(), total_code_size, |
+ inlined_id_array.Length() * sizeof(uword)); |
+ code.set_inlined_id_to_function(inlined_id_array); |
+ |
+ const CodeSourceMap& map = |
+ CodeSourceMap::Handle(code_source_map_builder_->Finalize()); |
+ INC_STAT(Thread::Current(), total_code_size, map.Length() * sizeof(uint8_t)); |
+ code.set_code_source_map(map); |
+#endif |
+ |
+#if defined(DEBUG) |
+ // Force simulation through the last pc offset. This checks we can decode |
+ // the whole CodeSourceMap without hitting an unknown opcode, stack underflow, |
+ // etc. |
+ GrowableArray<const Function*> fs; |
+ GrowableArray<TokenPosition> tokens; |
+ code.GetInlinedFunctionsAt(code.Size() - 1, &fs, &tokens); |
+#endif |
+} |
+ |
+ |
// Returns 'true' if regular code generation should be skipped. |
bool FlowGraphCompiler::TryIntrinsify() { |
// Intrinsification skips arguments checks, therefore disable if in checked |
@@ -1788,70 +1735,14 @@ const Class& FlowGraphCompiler::BoxClassFor(Representation rep) { |
} |
-RawArray* FlowGraphCompiler::InliningIdToFunction() const { |
- if (inline_id_to_function_.length() == 0) { |
- return Object::empty_array().raw(); |
- } |
- const Array& res = |
- Array::Handle(Array::New(inline_id_to_function_.length(), Heap::kOld)); |
- for (intptr_t i = 0; i < inline_id_to_function_.length(); i++) { |
- res.SetAt(i, *inline_id_to_function_[i]); |
- } |
- return res.raw(); |
-} |
- |
- |
-RawArray* FlowGraphCompiler::InliningIdToTokenPos() const { |
- if (inline_id_to_token_pos_.length() == 0) { |
- return Object::empty_array().raw(); |
- } |
- const Array& res = Array::Handle( |
- zone(), Array::New(inline_id_to_token_pos_.length(), Heap::kOld)); |
- Smi& smi = Smi::Handle(zone()); |
- for (intptr_t i = 0; i < inline_id_to_token_pos_.length(); i++) { |
- smi = Smi::New(inline_id_to_token_pos_[i].value()); |
- res.SetAt(i, smi); |
- } |
- return res.raw(); |
-} |
- |
- |
-RawArray* FlowGraphCompiler::CallerInliningIdMap() const { |
- if (caller_inline_id_.length() == 0) { |
- return Object::empty_array().raw(); |
- } |
- const Array& res = |
- Array::Handle(Array::New(caller_inline_id_.length(), Heap::kOld)); |
- Smi& smi = Smi::Handle(); |
- for (intptr_t i = 0; i < caller_inline_id_.length(); i++) { |
- smi = Smi::New(caller_inline_id_[i]); |
- res.SetAt(i, smi); |
- } |
- return res.raw(); |
-} |
- |
- |
void FlowGraphCompiler::BeginCodeSourceRange() { |
-#if !defined(PRODUCT) |
- // Remember how many bytes of code we emitted so far. This function |
- // is called before we call into an instruction's EmitNativeCode. |
- saved_code_size_ = assembler()->CodeSize(); |
-#endif // !defined(PRODUCT) |
+ code_source_map_builder_->BeginCodeSourceRange(assembler()->CodeSize()); |
} |
-bool FlowGraphCompiler::EndCodeSourceRange(TokenPosition token_pos) { |
-#if !defined(PRODUCT) |
- // This function is called after each instructions' EmitNativeCode. |
- if (saved_code_size_ < assembler()->CodeSize()) { |
- // We emitted more code, now associate the emitted code chunk with |
- // |token_pos|. |
- code_source_map_builder()->AddEntry(saved_code_size_, token_pos); |
- BeginCodeSourceRange(); |
- return true; |
- } |
-#endif // !defined(PRODUCT) |
- return false; |
+void FlowGraphCompiler::EndCodeSourceRange(TokenPosition token_pos) { |
+ code_source_map_builder_->EndCodeSourceRange(assembler()->CodeSize(), |
+ token_pos); |
} |