Index: runtime/vm/code_descriptors.cc |
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc |
index 1e6ff220ba094b03d6dd56e37d5e1c0311ffd6b6..0631bfee3f588446607221bb43bd48133a093a26 100644 |
--- a/runtime/vm/code_descriptors.cc |
+++ b/runtime/vm/code_descriptors.cc |
@@ -4,6 +4,8 @@ |
#include "vm/code_descriptors.h" |
+#include "vm/log.h" |
+ |
namespace dart { |
void DescriptorList::AddDescriptor(RawPcDescriptors::Kind kind, |
@@ -41,25 +43,6 @@ RawPcDescriptors* DescriptorList::FinalizePcDescriptors(uword entry_point) { |
} |
-void CodeSourceMapBuilder::AddEntry(intptr_t pc_offset, |
- TokenPosition token_pos) { |
- // Require pc offset to monotonically increase. |
- ASSERT((prev_pc_offset < pc_offset) || |
- ((prev_pc_offset == 0) && (pc_offset == 0))); |
- CodeSourceMap::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset); |
- CodeSourceMap::EncodeInteger(&encoded_data_, |
- token_pos.value() - prev_token_pos); |
- |
- prev_pc_offset = pc_offset; |
- prev_token_pos = token_pos.value(); |
-} |
- |
- |
-RawCodeSourceMap* CodeSourceMapBuilder::Finalize() { |
- return CodeSourceMap::New(&encoded_data_); |
-} |
- |
- |
void StackMapTableBuilder::AddEntry(intptr_t pc_offset, |
BitmapBuilder* bitmap, |
intptr_t register_bit_count) { |
@@ -132,4 +115,343 @@ RawExceptionHandlers* ExceptionHandlerList::FinalizeExceptionHandlers( |
} |
+static uint8_t* zone_allocator(uint8_t* ptr, |
+ intptr_t old_size, |
+ intptr_t new_size) { |
+ Zone* zone = Thread::Current()->zone(); |
+ return zone->Realloc<uint8_t>(ptr, old_size, new_size); |
+} |
+ |
+ |
+const TokenPosition CodeSourceMapBuilder::kInitialPosition = |
+ TokenPosition::kDartCodePrologue; |
+ |
+ |
+CodeSourceMapBuilder::CodeSourceMapBuilder( |
+ const GrowableArray<intptr_t>& caller_inline_id, |
+ const GrowableArray<TokenPosition>& inline_id_to_token_pos, |
+ const GrowableArray<const Function*>& inline_id_to_function) |
+ : pc_offset_(0), |
+ advance_pc_peephole_(0), |
+ inline_id_stack_(), |
+ token_pos_stack_(), |
+ caller_inline_id_(caller_inline_id), |
+ inline_id_to_token_pos_(inline_id_to_token_pos), |
+ inline_id_to_function_(inline_id_to_function), |
+ buffer_(NULL), |
+ stream_(&buffer_, zone_allocator, 64) { |
+ inline_id_stack_.Add(0); |
+ token_pos_stack_.Add(TokenPosition::kDartCodePrologue); |
+} |
+ |
+ |
+void CodeSourceMapBuilder::StartInliningInterval(int32_t pc_offset, |
+ intptr_t inline_id) { |
+ if (inline_id_stack_.Last() == inline_id) { |
+ // No change in function stack. |
+ return; |
+ } |
+ if (inline_id == -1) { |
+ // Basic blocking missing an inline_id. |
+ return; |
+ } |
+ |
+ // Find a minimal set of pops and pushes to bring us to the new function |
+ // stack. |
+ |
+ // Pop to a common ancestor. |
+ intptr_t common_parent = inline_id; |
+ while (!IsOnStack(common_parent)) { |
+ common_parent = caller_inline_id_[common_parent]; |
+ } |
+ while (inline_id_stack_.Last() != common_parent) { |
+ EmitPop(); |
+ inline_id_stack_.RemoveLast(); |
+ token_pos_stack_.RemoveLast(); |
+ } |
+ |
+ // Push to the new top-of-stack function. |
+ GrowableArray<intptr_t> to_push; |
+ intptr_t id = inline_id; |
+ while (id != common_parent) { |
+ to_push.Add(id); |
+ id = caller_inline_id_[id]; |
+ } |
+ for (intptr_t i = to_push.length() - 1; i >= 0; i--) { |
+ intptr_t push_id = to_push[i]; |
+ TokenPosition call_token; |
+ if (push_id != 0) { |
+ // TODO(rmacnak): Should make this array line up with the others. |
+ call_token = inline_id_to_token_pos_[push_id - 1]; |
+ } |
+ |
+ // Report caller as at the position of the call. |
+ if (call_token != token_pos_stack_.Last()) { |
+ EmitPosition(call_token); |
+ token_pos_stack_[token_pos_stack_.length() - 1] = call_token; |
+ } |
+ |
+ // Push the callee. |
+ EmitPush(push_id); |
+ inline_id_stack_.Add(push_id); |
+ token_pos_stack_.Add(TokenPosition::kDartCodePrologue); |
+ } |
+} |
+ |
+ |
+void CodeSourceMapBuilder::BeginCodeSourceRange(int32_t pc_offset) {} |
+ |
+ |
+void CodeSourceMapBuilder::EndCodeSourceRange(int32_t pc_offset, |
+ TokenPosition pos) { |
+ if (pc_offset == pc_offset_) { |
+ return; // Empty intermediate instruction. |
+ } |
+ if (pos != token_pos_stack_.Last()) { |
+ EmitPosition(pos); |
+ token_pos_stack_[token_pos_stack_.length() - 1] = pos; |
+ } |
+ EmitAdvancePC(pc_offset - pc_offset_); |
+ pc_offset_ = pc_offset; |
+} |
+ |
+ |
+RawArray* CodeSourceMapBuilder::InliningIdToFunction() { |
+ if (inline_id_to_function_.length() <= 1) { |
+ // Not optimizing, or optimizing and nothing inlined. |
+ 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(); |
+} |
+ |
+ |
+RawCodeSourceMap* CodeSourceMapBuilder::Finalize() { |
+ FlushPeephole(); |
+ intptr_t length = stream_.bytes_written(); |
+ const CodeSourceMap& map = CodeSourceMap::Handle(CodeSourceMap::New(length)); |
+ NoSafepointScope no_safepoint; |
+ memmove(map.Data(), buffer_, length); |
+ return map.raw(); |
+} |
+ |
+ |
+void CodeSourceMapReader::GetInlinedFunctionsAt( |
+ int32_t pc_offset, |
+ GrowableArray<const Function*>* function_stack, |
+ GrowableArray<TokenPosition>* token_positions) { |
+ function_stack->Clear(); |
+ token_positions->Clear(); |
+ |
+ NoSafepointScope no_safepoint; |
+ ReadStream stream(map_.Data(), map_.Length()); |
+ |
+ int32_t current_pc_offset = 0; |
+ function_stack->Add(&root_); |
+ token_positions->Add(CodeSourceMapBuilder::kInitialPosition); |
+ |
+ while (stream.PendingBytes() > 0) { |
+ uint8_t opcode = stream.Read<uint8_t>(); |
+ switch (opcode) { |
+ case CodeSourceMapBuilder::kChangePosition: { |
+ int32_t position = stream.Read<int32_t>(); |
+ (*token_positions)[token_positions->length() - 1] = |
+ TokenPosition(position); |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kAdvancePC: { |
+ int32_t delta = stream.Read<int32_t>(); |
+ current_pc_offset += delta; |
+ if (current_pc_offset > pc_offset) { |
+ return; |
+ } |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kPushFunction: { |
+ int32_t func = stream.Read<int32_t>(); |
+ function_stack->Add( |
+ &Function::Handle(Function::RawCast(functions_.At(func)))); |
+ token_positions->Add(CodeSourceMapBuilder::kInitialPosition); |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kPopFunction: { |
+ // We never pop the root function. |
+ ASSERT(function_stack->length() > 1); |
+ ASSERT(token_positions->length() > 1); |
+ function_stack->RemoveLast(); |
+ token_positions->RemoveLast(); |
+ break; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+} |
+ |
+ |
+#ifndef PRODUCT |
+void CodeSourceMapReader::PrintJSONInlineIntervals(JSONObject* jsobj) { |
+ { |
+ JSONArray inlined_functions(jsobj, "_inlinedFunctions"); |
+ Function& function = Function::Handle(); |
+ for (intptr_t i = 0; i < functions_.Length(); i++) { |
+ function ^= functions_.At(i); |
+ ASSERT(!function.IsNull()); |
+ inlined_functions.AddValue(function); |
+ } |
+ } |
+ |
+ GrowableArray<intptr_t> function_stack; |
+ JSONArray inline_intervals(jsobj, "_inlinedIntervals"); |
+ NoSafepointScope no_safepoint; |
+ ReadStream stream(map_.Data(), map_.Length()); |
+ |
+ int32_t current_pc_offset = 0; |
+ function_stack.Add(0); |
+ |
+ while (stream.PendingBytes() > 0) { |
+ uint8_t opcode = stream.Read<uint8_t>(); |
+ switch (opcode) { |
+ case CodeSourceMapBuilder::kChangePosition: { |
+ stream.Read<int32_t>(); |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kAdvancePC: { |
+ int32_t delta = stream.Read<int32_t>(); |
+ // Format: [start, end, inline functions...] |
+ JSONArray inline_interval(&inline_intervals); |
+ inline_interval.AddValue(static_cast<intptr_t>(current_pc_offset)); |
+ inline_interval.AddValue( |
+ static_cast<intptr_t>(current_pc_offset + delta - 1)); |
+ for (intptr_t i = 0; i < function_stack.length(); i++) { |
+ inline_interval.AddValue(function_stack[i]); |
+ } |
+ current_pc_offset += delta; |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kPushFunction: { |
+ int32_t func = stream.Read<int32_t>(); |
+ function_stack.Add(func); |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kPopFunction: { |
+ // We never pop the root function. |
+ ASSERT(function_stack.length() > 1); |
+ function_stack.RemoveLast(); |
+ break; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+} |
+#endif // !PRODUCT |
+ |
+ |
+void CodeSourceMapReader::DumpInlineIntervals(uword start) { |
+ GrowableArray<const Function*> function_stack; |
+ LogBlock lb; |
+ NoSafepointScope no_safepoint; |
+ ReadStream stream(map_.Data(), map_.Length()); |
+ |
+ int32_t current_pc_offset = 0; |
+ function_stack.Add(&root_); |
+ |
+ THR_Print("Inline intervals {\n"); |
+ while (stream.PendingBytes() > 0) { |
+ uint8_t opcode = stream.Read<uint8_t>(); |
+ switch (opcode) { |
+ case CodeSourceMapBuilder::kChangePosition: { |
+ stream.Read<int32_t>(); |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kAdvancePC: { |
+ int32_t delta = stream.Read<int32_t>(); |
+ THR_Print("%" Px "-%" Px ": ", start + current_pc_offset, |
+ start + current_pc_offset + delta - 1); |
+ for (intptr_t i = 0; i < function_stack.length(); i++) { |
+ THR_Print("%s ", function_stack[i]->ToCString()); |
+ } |
+ THR_Print("\n"); |
+ current_pc_offset += delta; |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kPushFunction: { |
+ int32_t func = stream.Read<int32_t>(); |
+ function_stack.Add( |
+ &Function::Handle(Function::RawCast(functions_.At(func)))); |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kPopFunction: { |
+ // We never pop the root function. |
+ ASSERT(function_stack.length() > 1); |
+ function_stack.RemoveLast(); |
+ break; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+ THR_Print("}\n"); |
+} |
+ |
+ |
+void CodeSourceMapReader::DumpSourcePositions(uword start) { |
+ GrowableArray<const Function*> function_stack; |
+ GrowableArray<TokenPosition> token_positions; |
+ LogBlock lb; |
+ NoSafepointScope no_safepoint; |
+ ReadStream stream(map_.Data(), map_.Length()); |
+ |
+ int32_t current_pc_offset = 0; |
+ function_stack.Add(&root_); |
+ token_positions.Add(CodeSourceMapBuilder::kInitialPosition); |
+ |
+ THR_Print("Source positions {\n"); |
+ while (stream.PendingBytes() > 0) { |
+ uint8_t opcode = stream.Read<uint8_t>(); |
+ switch (opcode) { |
+ case CodeSourceMapBuilder::kChangePosition: { |
+ int32_t position = stream.Read<int32_t>(); |
+ token_positions[token_positions.length() - 1] = TokenPosition(position); |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kAdvancePC: { |
+ int32_t delta = stream.Read<int32_t>(); |
+ THR_Print("%" Px "-%" Px ": ", start + current_pc_offset, |
+ start + current_pc_offset + delta - 1); |
+ for (intptr_t i = 0; i < function_stack.length(); i++) { |
+ THR_Print("%s@%" Pd " ", function_stack[i]->ToCString(), |
+ token_positions[i].value()); |
+ } |
+ THR_Print("\n"); |
+ current_pc_offset += delta; |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kPushFunction: { |
+ int32_t func = stream.Read<int32_t>(); |
+ function_stack.Add( |
+ &Function::Handle(Function::RawCast(functions_.At(func)))); |
+ token_positions.Add(CodeSourceMapBuilder::kInitialPosition); |
+ break; |
+ } |
+ case CodeSourceMapBuilder::kPopFunction: { |
+ // We never pop the root function. |
+ ASSERT(function_stack.length() > 1); |
+ ASSERT(token_positions.length() > 1); |
+ function_stack.RemoveLast(); |
+ token_positions.RemoveLast(); |
+ break; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+ THR_Print("}\n"); |
+} |
+ |
} // namespace dart |