| 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
|
|
|