[vm] Compress CodeSourceMaps by folding opcodes and arguments.
Also delta encode the position/line argument for ChangePosition.
Code size changes on Flutter gallery in release mode from compression:
* ARM7: total -1.39%, readonly -6.47%
* ARM8: total -1.28%, readonly -4.81%
Additional code size changes on Flutter gallery in release mode from
delta encoding position/line:
* ARM7: total -0.48%, readonly -2.37%
* ARM8: total -0.54%, readonly -2.09%
TEST=Existing test on trybots, including stack trace tests and
DWARF decoding tests.
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-x64-try,vm-kernel-linux-debug-x64-try,vm-kernel-linux-release-x64-try,vm-kernel-nnbd-linux-release-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-nnbd-linux-release-x64-try,vm-kernel-linux-product-x64-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-linux-release-simarm64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-ia32-try
Change-Id: Ibaf96b1d6c1916ce2f7c71942e333ca7a0b86c3e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175725
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 12bb667..eecab24 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -361,15 +361,17 @@
return ((-0x20000000000000LL <= value) && (value <= 0x20000000000000LL));
}
+ static constexpr uword NBitMaskUnsafe(uint32_t n) {
+ static_assert((sizeof(uword) * kBitsPerByte) == kBitsPerWord,
+ "Unexpected uword size");
+ return n == kBitsPerWord ? std::numeric_limits<uword>::max()
+ : (static_cast<uword>(1) << n) - 1;
+ }
+
// The lowest n bits are 1, the others are 0.
static uword NBitMask(uint32_t n) {
ASSERT(n <= kBitsPerWord);
- if (n == kBitsPerWord) {
- static_assert((sizeof(uword) * kBitsPerByte) == kBitsPerWord,
- "Unexpected uword size");
- return std::numeric_limits<uword>::max();
- }
- return (static_cast<uword>(1) << n) - 1;
+ return NBitMaskUnsafe(n);
}
static word SignedNBitMask(uint32_t n) {
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index 9c5c023..6a75f04 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -237,6 +237,51 @@
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
+uint8_t CodeSourceMapOps::Read(ReadStream* stream,
+ int32_t* arg1,
+ int32_t* arg2) {
+ ASSERT(stream != nullptr && arg1 != nullptr);
+ const int32_t n = stream->Read<int32_t>();
+ const uint8_t op = OpField::decode(n);
+ *arg1 = ArgField::decode(n);
+ if (*arg1 > kMaxArgValue) {
+ *arg1 |= kSignBits;
+ }
+#if defined(DART_PRECOMPILER)
+ // The special handling for non-symbolic stack trace mode only needs to
+ // happen in the precompiler, because those CSMs are not serialized in
+ // precompiled snapshots.
+ if (op == kChangePosition && FLAG_dwarf_stack_traces_mode) {
+ const int32_t m = stream->Read<int32_t>();
+ if (arg2 != nullptr) {
+ *arg2 = m;
+ }
+ }
+#endif
+ return op;
+}
+
+void CodeSourceMapOps::Write(BaseWriteStream* stream,
+ uint8_t op,
+ int32_t arg1,
+ int32_t arg2) {
+ ASSERT(stream != nullptr);
+ ASSERT(arg1 >= kMinArgValue && arg1 <= kMaxArgValue);
+ if (arg1 < 0) {
+ arg1 &= ~kSignBits;
+ }
+ const int32_t n = OpField::encode(op) | ArgField::encode(arg1);
+ stream->Write(n);
+#if defined(DART_PRECOMPILER)
+ if (op == kChangePosition && FLAG_dwarf_stack_traces_mode) {
+ // For non-symbolic stack traces, the CodeSourceMaps are not serialized,
+ // so we need not worry about increasing snapshot size by including more
+ // information here.
+ stream->Write(arg2);
+ }
+#endif
+}
+
const TokenPosition& CodeSourceMapBuilder::kInitialPosition =
TokenPosition::kDartCodePrologue;
@@ -491,10 +536,11 @@
}
void CodeSourceMapBuilder::WriteChangePosition(const TokenPosition pos) {
- stream_.Write<uint8_t>(kChangePosition);
- intptr_t position_or_line = pos.Serialize();
-#if defined(DART_PRECOMPILER)
+ const TokenPosition& last_written = written_token_pos_stack_.Last();
+ intptr_t position_or_line =
+ Utils::SubWithWrapAround(pos.Serialize(), last_written.Serialize());
intptr_t column = TokenPosition::kNoSource.Serialize();
+#if defined(DART_PRECOMPILER)
if (FLAG_precompiled_mode) {
// Don't use the raw position value directly in precompiled mode. Instead,
// use the value of kNoSource as a fallback when no line or column
@@ -504,17 +550,14 @@
ASSERT(inline_id < inline_id_to_function_.length());
script_ = inline_id_to_function_[inline_id]->script();
script_.GetTokenLocation(pos, &position_or_line, &column);
+ intptr_t old_line = TokenPosition::kNoSource.Serialize();
+ script_.GetTokenLocation(last_written, &old_line);
+ position_or_line =
+ Utils::SubWithWrapAround<int32_t>(position_or_line, old_line);
}
#endif
- stream_.Write<int32_t>(position_or_line);
-#if defined(DART_PRECOMPILER)
- // For non-symbolic stack traces, the CodeSourceMaps are not serialized,
- // so we need not worry about increasing snapshot size by including more
- // information here.
- if (FLAG_precompiled_mode && FLAG_dwarf_stack_traces_mode) {
- stream_.Write<int32_t>(column);
- }
-#endif
+ CodeSourceMapOps::Write(&stream_, CodeSourceMapOps::kChangePosition,
+ position_or_line, column);
written_token_pos_stack_.Last() = pos;
}
@@ -533,29 +576,31 @@
token_positions->Add(InitialPosition());
while (stream.PendingBytes() > 0) {
- uint8_t opcode = stream.Read<uint8_t>();
+ int32_t arg;
+ const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
switch (opcode) {
- case CodeSourceMapBuilder::kChangePosition: {
+ case CodeSourceMapOps::kChangePosition: {
+ const TokenPosition& old_token =
+ (*token_positions)[token_positions->length() - 1];
(*token_positions)[token_positions->length() - 1] =
- ReadPosition(&stream);
+ TokenPosition::Deserialize(
+ Utils::AddWithWrapAround(arg, old_token.Serialize()));
break;
}
- case CodeSourceMapBuilder::kAdvancePC: {
- int32_t delta = stream.Read<int32_t>();
- current_pc_offset += delta;
+ case CodeSourceMapOps::kAdvancePC: {
+ current_pc_offset += arg;
if (current_pc_offset > pc_offset) {
return;
}
break;
}
- case CodeSourceMapBuilder::kPushFunction: {
- int32_t func = stream.Read<int32_t>();
+ case CodeSourceMapOps::kPushFunction: {
function_stack->Add(
- &Function::Handle(Function::RawCast(functions_.At(func))));
+ &Function::Handle(Function::RawCast(functions_.At(arg))));
token_positions->Add(InitialPosition());
break;
}
- case CodeSourceMapBuilder::kPopFunction: {
+ case CodeSourceMapOps::kPopFunction: {
// We never pop the root function.
ASSERT(function_stack->length() > 1);
ASSERT(token_positions->length() > 1);
@@ -563,8 +608,7 @@
token_positions->RemoveLast();
break;
}
- case CodeSourceMapBuilder::kNullCheck: {
- stream.Read<int32_t>();
+ case CodeSourceMapOps::kNullCheck: {
break;
}
default:
@@ -594,38 +638,35 @@
function_stack.Add(0);
while (stream.PendingBytes() > 0) {
- uint8_t opcode = stream.Read<uint8_t>();
+ int32_t arg;
+ const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
switch (opcode) {
- case CodeSourceMapBuilder::kChangePosition: {
- ReadPosition(&stream);
+ case CodeSourceMapOps::kChangePosition: {
break;
}
- case CodeSourceMapBuilder::kAdvancePC: {
- int32_t delta = stream.Read<int32_t>();
+ case CodeSourceMapOps::kAdvancePC: {
// 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));
+ static_cast<intptr_t>(current_pc_offset + arg - 1));
for (intptr_t i = 0; i < function_stack.length(); i++) {
inline_interval.AddValue(function_stack[i]);
}
- current_pc_offset += delta;
+ current_pc_offset += arg;
break;
}
- case CodeSourceMapBuilder::kPushFunction: {
- int32_t func = stream.Read<int32_t>();
- function_stack.Add(func);
+ case CodeSourceMapOps::kPushFunction: {
+ function_stack.Add(arg);
break;
}
- case CodeSourceMapBuilder::kPopFunction: {
+ case CodeSourceMapOps::kPopFunction: {
// We never pop the root function.
ASSERT(function_stack.length() > 1);
function_stack.RemoveLast();
break;
}
- case CodeSourceMapBuilder::kNullCheck: {
- stream.Read<int32_t>();
+ case CodeSourceMapOps::kNullCheck: {
break;
}
default:
@@ -647,37 +688,34 @@
THR_Print("Inline intervals for function '%s' {\n",
root_.ToFullyQualifiedCString());
while (stream.PendingBytes() > 0) {
- uint8_t opcode = stream.Read<uint8_t>();
+ int32_t arg;
+ const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
switch (opcode) {
- case CodeSourceMapBuilder::kChangePosition: {
- ReadPosition(&stream);
+ case CodeSourceMapOps::kChangePosition: {
break;
}
- case CodeSourceMapBuilder::kAdvancePC: {
- int32_t delta = stream.Read<int32_t>();
+ case CodeSourceMapOps::kAdvancePC: {
THR_Print("%" Px "-%" Px ": ", start + current_pc_offset,
- start + current_pc_offset + delta - 1);
+ start + current_pc_offset + arg - 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;
+ current_pc_offset += arg;
break;
}
- case CodeSourceMapBuilder::kPushFunction: {
- int32_t func = stream.Read<int32_t>();
+ case CodeSourceMapOps::kPushFunction: {
function_stack.Add(
- &Function::Handle(Function::RawCast(functions_.At(func))));
+ &Function::Handle(Function::RawCast(functions_.At(arg))));
break;
}
- case CodeSourceMapBuilder::kPopFunction: {
+ case CodeSourceMapOps::kPopFunction: {
// We never pop the root function.
ASSERT(function_stack.length() > 1);
function_stack.RemoveLast();
break;
}
- case CodeSourceMapBuilder::kNullCheck: {
- stream.Read<int32_t>();
+ case CodeSourceMapOps::kNullCheck: {
break;
}
default:
@@ -701,32 +739,35 @@
THR_Print("Source positions for function '%s' {\n",
root_.ToFullyQualifiedCString());
while (stream.PendingBytes() > 0) {
- uint8_t opcode = stream.Read<uint8_t>();
+ int32_t arg;
+ const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
switch (opcode) {
- case CodeSourceMapBuilder::kChangePosition: {
- token_positions[token_positions.length() - 1] = ReadPosition(&stream);
+ case CodeSourceMapOps::kChangePosition: {
+ const TokenPosition& old_token =
+ token_positions[token_positions.length() - 1];
+ token_positions[token_positions.length() - 1] =
+ TokenPosition::Deserialize(
+ Utils::AddWithWrapAround(arg, old_token.Serialize()));
break;
}
- case CodeSourceMapBuilder::kAdvancePC: {
- int32_t delta = stream.Read<int32_t>();
+ case CodeSourceMapOps::kAdvancePC: {
THR_Print("%" Px "-%" Px ": ", start + current_pc_offset,
- start + current_pc_offset + delta - 1);
+ start + current_pc_offset + arg - 1);
for (intptr_t i = 0; i < function_stack.length(); i++) {
THR_Print("%s@%s", function_stack[i]->ToCString(),
token_positions[i].ToCString());
}
THR_Print("\n");
- current_pc_offset += delta;
+ current_pc_offset += arg;
break;
}
- case CodeSourceMapBuilder::kPushFunction: {
- int32_t func = stream.Read<int32_t>();
+ case CodeSourceMapOps::kPushFunction: {
function_stack.Add(
- &Function::Handle(Function::RawCast(functions_.At(func))));
+ &Function::Handle(Function::RawCast(functions_.At(arg))));
token_positions.Add(InitialPosition());
break;
}
- case CodeSourceMapBuilder::kPopFunction: {
+ case CodeSourceMapOps::kPopFunction: {
// We never pop the root function.
ASSERT(function_stack.length() > 1);
ASSERT(token_positions.length() > 1);
@@ -734,11 +775,9 @@
token_positions.RemoveLast();
break;
}
- case CodeSourceMapBuilder::kNullCheck: {
- const intptr_t name_index = stream.Read<int32_t>();
- THR_Print("%" Px "-%" Px ": null check PP#%" Pd "\n",
- start + current_pc_offset, start + current_pc_offset,
- name_index);
+ case CodeSourceMapOps::kNullCheck: {
+ THR_Print("%" Px "-%" Px ": null check PP#%" Pd32 "\n",
+ start + current_pc_offset, start + current_pc_offset, arg);
break;
}
default:
@@ -755,29 +794,26 @@
int32_t current_pc_offset = 0;
while (stream.PendingBytes() > 0) {
- uint8_t opcode = stream.Read<uint8_t>();
+ int32_t arg;
+ const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
switch (opcode) {
- case CodeSourceMapBuilder::kChangePosition: {
- ReadPosition(&stream);
+ case CodeSourceMapOps::kChangePosition: {
break;
}
- case CodeSourceMapBuilder::kAdvancePC: {
- int32_t delta = stream.Read<int32_t>();
- current_pc_offset += delta;
+ case CodeSourceMapOps::kAdvancePC: {
+ current_pc_offset += arg;
RELEASE_ASSERT(current_pc_offset <= pc_offset);
break;
}
- case CodeSourceMapBuilder::kPushFunction: {
- stream.Read<int32_t>();
+ case CodeSourceMapOps::kPushFunction: {
break;
}
- case CodeSourceMapBuilder::kPopFunction: {
+ case CodeSourceMapOps::kPopFunction: {
break;
}
- case CodeSourceMapBuilder::kNullCheck: {
- const int32_t name_index = stream.Read<int32_t>();
+ case CodeSourceMapOps::kNullCheck: {
if (current_pc_offset == pc_offset) {
- return name_index;
+ return arg;
}
break;
}
@@ -790,18 +826,4 @@
return -1;
}
-TokenPosition CodeSourceMapReader::ReadPosition(ReadStream* stream) {
- const TokenPosition line =
- TokenPosition::Deserialize(stream->Read<int32_t>());
-#if defined(DART_PRECOMPILER)
- // The special handling for non-symbolic stack trace mode only needs to
- // happen in the precompiler, because those CSMs are not serialized in
- // precompiled snapshots.
- if (FLAG_dwarf_stack_traces_mode) {
- stream->Read<int32_t>(); // Discard the column information.
- }
-#endif
- return line;
-}
-
} // namespace dart
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index a7e30d0..5356c50 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -186,6 +186,34 @@
DISALLOW_ALLOCATION();
};
+struct CodeSourceMapOps : AllStatic {
+ static const uint8_t kChangePosition = 0;
+ static const uint8_t kAdvancePC = 1;
+ static const uint8_t kPushFunction = 2;
+ static const uint8_t kPopFunction = 3;
+ static const uint8_t kNullCheck = 4;
+
+ static uint8_t Read(ReadStream* stream,
+ int32_t* arg1,
+ int32_t* arg2 = nullptr);
+
+ static void Write(BaseWriteStream* stream,
+ uint8_t op,
+ int32_t arg1 = 0,
+ int32_t arg2 = 0);
+
+ private:
+ static constexpr intptr_t kOpBits = 3;
+
+ using OpField = BitField<int32_t, uint8_t, 0, kOpBits>;
+ using ArgField = BitField<int32_t, int32_t, OpField::kNextBit>;
+
+ static constexpr int32_t kMaxArgValue =
+ Utils::NBitMaskUnsafe(ArgField::bitsize() - 1);
+ static constexpr int32_t kMinArgValue = ~kMaxArgValue;
+ static constexpr int32_t kSignBits = static_cast<uint32_t>(kMinArgValue) << 1;
+};
+
// A CodeSourceMap maps from pc offsets to a stack of inlined functions and
// their positions. This is encoded as a little bytecode that pushes and pops
// functions and changes the top function's position as the PC advances.
@@ -210,12 +238,6 @@
// since it is the most common.
static const TokenPosition& kInitialPosition;
- static const uint8_t kChangePosition = 0;
- static const uint8_t kAdvancePC = 1;
- static const uint8_t kPushFunction = 2;
- static const uint8_t kPopFunction = 3;
- static const uint8_t kNullCheck = 4;
-
void BeginCodeSourceRange(int32_t pc_offset, const InstructionSource& source);
void EndCodeSourceRange(int32_t pc_offset, const InstructionSource& source);
void NoteDescriptor(PcDescriptorsLayout::Kind kind,
@@ -244,8 +266,7 @@
void WriteChangePosition(TokenPosition pos);
void BufferAdvancePC(int32_t distance) { buffered_pc_offset_ += distance; }
void WriteAdvancePC(int32_t distance) {
- stream_.Write<uint8_t>(kAdvancePC);
- stream_.Write<int32_t>(distance);
+ CodeSourceMapOps::Write(&stream_, CodeSourceMapOps::kAdvancePC, distance);
written_pc_offset_ += distance;
}
void BufferPush(intptr_t inline_id) {
@@ -253,8 +274,8 @@
buffered_token_pos_stack_.Add(kInitialPosition);
}
void WritePush(intptr_t inline_id) {
- stream_.Write<uint8_t>(kPushFunction);
- stream_.Write<int32_t>(GetFunctionId(inline_id));
+ CodeSourceMapOps::Write(&stream_, CodeSourceMapOps::kPushFunction,
+ GetFunctionId(inline_id));
written_inline_id_stack_.Add(inline_id);
written_token_pos_stack_.Add(kInitialPosition);
}
@@ -263,13 +284,12 @@
buffered_token_pos_stack_.RemoveLast();
}
void WritePop() {
- stream_.Write<uint8_t>(kPopFunction);
+ CodeSourceMapOps::Write(&stream_, CodeSourceMapOps::kPopFunction);
written_inline_id_stack_.RemoveLast();
written_token_pos_stack_.RemoveLast();
}
void WriteNullCheck(int32_t name_index) {
- stream_.Write<uint8_t>(kNullCheck);
- stream_.Write<int32_t>(name_index);
+ CodeSourceMapOps::Write(&stream_, CodeSourceMapOps::kNullCheck, name_index);
}
void FlushBuffer();
diff --git a/runtime/vm/dwarf.cc b/runtime/vm/dwarf.cc
index cfafd48..ef08d8c 100644
--- a/runtime/vm/dwarf.cc
+++ b/runtime/vm/dwarf.cc
@@ -15,21 +15,19 @@
class DwarfPosition {
public:
- // The DWARF standard uses 0 to denote missing line or column information.
- DwarfPosition(intptr_t line, intptr_t column)
- : line_(line > 0 ? line : 0), column_(column > 0 ? column : 0) {
+ DwarfPosition(int32_t line, int32_t column) : line_(line), column_(column) {
// Should only have no line information if also no column information.
- ASSERT(line_ > 0 || column_ == 0);
+ ASSERT(line_ > 0 || column_ <= 0);
}
- explicit DwarfPosition(intptr_t line) : DwarfPosition(line, 0) {}
- constexpr DwarfPosition() : line_(0), column_(0) {}
+ explicit DwarfPosition(int32_t line) : DwarfPosition(line, -1) {}
+ constexpr DwarfPosition() : line_(-1), column_(-1) {}
- intptr_t line() const { return line_; }
- intptr_t column() const { return column_; }
+ int32_t line() const { return line_; }
+ int32_t column() const { return column_; }
private:
- intptr_t line_;
- intptr_t column_;
+ int32_t line_;
+ int32_t column_;
};
static constexpr auto kNoDwarfPositionInfo = DwarfPosition();
@@ -392,15 +390,6 @@
}
}
-static DwarfPosition ReadPosition(ReadStream* stream) {
- const intptr_t line = stream->Read<int32_t>();
- if (!FLAG_dwarf_stack_traces_mode) {
- return DwarfPosition(line);
- }
- const intptr_t column = stream->Read<int32_t>();
- return DwarfPosition(line, column);
-}
-
// Our state machine encodes position metadata such that we don't know the
// end pc for an inlined function until it is popped, but DWARF DIEs encode
// it where the function is pushed. We expand the state transitions into
@@ -431,21 +420,24 @@
node_stack.Add(root_node);
while (stream.PendingBytes() > 0) {
- uint8_t opcode = stream.Read<uint8_t>();
+ int32_t arg1;
+ int32_t arg2 = -1;
+ const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg1, &arg2);
switch (opcode) {
- case CodeSourceMapBuilder::kChangePosition: {
- token_positions[token_positions.length() - 1] = ReadPosition(&stream);
+ case CodeSourceMapOps::kChangePosition: {
+ const DwarfPosition& old_pos =
+ token_positions[token_positions.length() - 1];
+ token_positions[token_positions.length() - 1] =
+ DwarfPosition(Utils::AddWithWrapAround(old_pos.line(), arg1), arg2);
break;
}
- case CodeSourceMapBuilder::kAdvancePC: {
- int32_t delta = stream.Read<int32_t>();
- current_pc_offset += delta;
+ case CodeSourceMapOps::kAdvancePC: {
+ current_pc_offset += arg1;
break;
}
- case CodeSourceMapBuilder::kPushFunction: {
- int32_t func = stream.Read<int32_t>();
+ case CodeSourceMapOps::kPushFunction: {
const Function& child_func =
- Function::ZoneHandle(zone_, Function::RawCast(functions.At(func)));
+ Function::ZoneHandle(zone_, Function::RawCast(functions.At(arg1)));
InliningNode* child_node = new (zone_)
InliningNode(child_func, token_positions.Last(), current_pc_offset);
node_stack.Last()->AppendChild(child_node);
@@ -453,7 +445,7 @@
token_positions.Add(kNoDwarfPositionInfo);
break;
}
- case CodeSourceMapBuilder::kPopFunction: {
+ case CodeSourceMapOps::kPopFunction: {
// We never pop the root function.
ASSERT(node_stack.length() > 1);
ASSERT(token_positions.length() > 1);
@@ -462,8 +454,7 @@
token_positions.RemoveLast();
break;
}
- case CodeSourceMapBuilder::kNullCheck: {
- stream.Read<int32_t>();
+ case CodeSourceMapOps::kNullCheck: {
break;
}
default:
@@ -499,10 +490,13 @@
stream->OffsetFromSymbol(root_asm_name, node->end_pc_offset);
// DW_AT_call_file
stream->uleb128(file);
+
+ // The DWARF standard uses 0 to denote missing line or column information.
+
// DW_AT_call_line
- stream->uleb128(node->position.line());
+ stream->uleb128(node->position.line() < 0 ? 0 : node->position.line());
// DW_at_call_column
- stream->uleb128(node->position.column());
+ stream->uleb128(node->position.column() < 0 ? 0 : node->position.column());
for (InliningNode* child = node->children_head; child != NULL;
child = child->children_next) {
@@ -609,16 +603,20 @@
token_positions.Add(kNoDwarfPositionInfo);
while (code_map_stream.PendingBytes() > 0) {
- uint8_t opcode = code_map_stream.Read<uint8_t>();
+ int32_t arg1;
+ int32_t arg2 = -1;
+ const uint8_t opcode =
+ CodeSourceMapOps::Read(&code_map_stream, &arg1, &arg2);
switch (opcode) {
- case CodeSourceMapBuilder::kChangePosition: {
- token_positions[token_positions.length() - 1] =
- ReadPosition(&code_map_stream);
+ case CodeSourceMapOps::kChangePosition: {
+ const DwarfPosition& old_pos =
+ token_positions[token_positions.length() - 1];
+ token_positions[token_positions.length() - 1] = DwarfPosition(
+ Utils::AddWithWrapAround(old_pos.line(), arg1), arg2);
break;
}
- case CodeSourceMapBuilder::kAdvancePC: {
- int32_t delta = code_map_stream.Read<int32_t>();
- current_pc_offset += delta;
+ case CodeSourceMapOps::kAdvancePC: {
+ current_pc_offset += arg1;
const Function& function = *(function_stack.Last());
script = function.script();
@@ -632,8 +630,14 @@
}
// 2. Update LNP line.
- const intptr_t line = token_positions.Last().line();
- const intptr_t column = token_positions.Last().column();
+ // The DWARF standard uses 0 to denote missing line or column
+ // information.
+ const intptr_t line = token_positions.Last().line() < 0
+ ? 0
+ : token_positions.Last().line();
+ const intptr_t column = token_positions.Last().column() < 0
+ ? 0
+ : token_positions.Last().column();
if (line != previous_line) {
stream->u1(DW_LNS_advance_line);
stream->sleb128(line - previous_line);
@@ -668,15 +672,14 @@
previous_pc_offset = current_pc_offset;
break;
}
- case CodeSourceMapBuilder::kPushFunction: {
- int32_t func_index = code_map_stream.Read<int32_t>();
- const Function& child_func = Function::Handle(
- zone_, Function::RawCast(functions.At(func_index)));
+ case CodeSourceMapOps::kPushFunction: {
+ const Function& child_func =
+ Function::Handle(zone_, Function::RawCast(functions.At(arg1)));
function_stack.Add(&child_func);
token_positions.Add(kNoDwarfPositionInfo);
break;
}
- case CodeSourceMapBuilder::kPopFunction: {
+ case CodeSourceMapOps::kPopFunction: {
// We never pop the root function.
ASSERT(function_stack.length() > 1);
ASSERT(token_positions.length() > 1);
@@ -684,8 +687,7 @@
token_positions.RemoveLast();
break;
}
- case CodeSourceMapBuilder::kNullCheck: {
- code_map_stream.Read<int32_t>();
+ case CodeSourceMapOps::kNullCheck: {
break;
}
default: