[vm/aot] Move precompiled position handling to CodeSourceMap classes.

Since CodeSourceMaps are not serialized when non-symbolic stack traces
are enabled, use a different CSM encoding in this mode. Here, we write
out the line number as before and then the column as a separately
written integer.

Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-nnbd-linux-release-x64-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-simarm_x64-try
Change-Id: If9aec2f52551d04eb45626744957e625bcc17d3d
Bug: https://github.com/dart-lang/sdk/issues/42397
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151824
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
Tess Strickland 2020-06-22 09:29:45 +00:00 committed by commit-bot@chromium.org
parent dbefbc3753
commit ed0eeaebca
6 changed files with 108 additions and 132 deletions

View file

@ -573,18 +573,32 @@ CodeSourceMapPtr CodeSourceMapBuilder::Finalize() {
void CodeSourceMapBuilder::WriteChangePosition(TokenPosition pos) {
stream_.Write<uint8_t>(kChangePosition);
intptr_t position_or_line = pos.value();
#if defined(DART_PRECOMPILER)
intptr_t column = TokenPosition::kNoSourcePos;
if (FLAG_precompiled_mode) {
int32_t loc = TokenPosition::kNoSourcePos;
// 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
// information is found.
position_or_line = TokenPosition::kNoSourcePos;
intptr_t inline_id = buffered_inline_id_stack_.Last();
if (inline_id < inline_id_to_function_.length()) {
const Function* function = inline_id_to_function_[inline_id];
Script& script = Script::Handle(function->script());
loc = script.GetTokenLocationUsingLineStarts(pos.SourcePosition());
script.GetTokenLocationUsingLineStarts(pos.SourcePosition(),
&position_or_line, &column);
}
stream_.Write(loc);
} else {
stream_.Write<int32_t>(pos.value());
}
#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_dwarf_stack_traces_mode) {
stream_.Write<int32_t>(column);
}
#endif
written_token_pos_stack_.Last() = pos;
}
@ -606,9 +620,8 @@ void CodeSourceMapReader::GetInlinedFunctionsAt(
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);
ReadPosition(&stream);
break;
}
case CodeSourceMapBuilder::kAdvancePC: {
@ -668,7 +681,7 @@ void CodeSourceMapReader::PrintJSONInlineIntervals(JSONObject* jsobj) {
uint8_t opcode = stream.Read<uint8_t>();
switch (opcode) {
case CodeSourceMapBuilder::kChangePosition: {
stream.Read<int32_t>();
ReadPosition(&stream);
break;
}
case CodeSourceMapBuilder::kAdvancePC: {
@ -721,7 +734,7 @@ void CodeSourceMapReader::DumpInlineIntervals(uword start) {
uint8_t opcode = stream.Read<uint8_t>();
switch (opcode) {
case CodeSourceMapBuilder::kChangePosition: {
stream.Read<int32_t>();
ReadPosition(&stream);
break;
}
case CodeSourceMapBuilder::kAdvancePC: {
@ -775,8 +788,7 @@ void CodeSourceMapReader::DumpSourcePositions(uword start) {
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);
token_positions[token_positions.length() - 1] = ReadPosition(&stream);
break;
}
case CodeSourceMapBuilder::kAdvancePC: {
@ -830,7 +842,7 @@ intptr_t CodeSourceMapReader::GetNullCheckNameIndexAt(int32_t pc_offset) {
uint8_t opcode = stream.Read<uint8_t>();
switch (opcode) {
case CodeSourceMapBuilder::kChangePosition: {
stream.Read<int32_t>();
ReadPosition(&stream);
break;
}
case CodeSourceMapBuilder::kAdvancePC: {
@ -862,4 +874,17 @@ intptr_t CodeSourceMapReader::GetNullCheckNameIndexAt(int32_t pc_offset) {
return -1;
}
TokenPosition CodeSourceMapReader::ReadPosition(ReadStream* stream) {
const intptr_t line = 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 TokenPosition(line);
}
} // namespace dart

View file

@ -359,6 +359,10 @@ class CodeSourceMapReader : public ValueObject {
intptr_t GetNullCheckNameIndexAt(int32_t pc_offset);
private:
// Reads a TokenPosition value from a CSM, handling the different encoding for
// when non-symbolic stack traces are enabled.
static TokenPosition ReadPosition(ReadStream* stream);
const CodeSourceMap& map_;
const Array& functions_;
const Function& root_;

View file

@ -11,15 +11,36 @@
namespace dart {
#ifdef DART_PRECOMPILER
#if defined(DART_PRECOMPILER)
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) {
// Should only have no line information if also no column information.
ASSERT(line_ > 0 || column_ == 0);
}
explicit DwarfPosition(intptr_t line) : DwarfPosition(line, 0) {}
constexpr DwarfPosition() : line_(0), column_(0) {}
intptr_t line() const { return line_; }
intptr_t column() const { return column_; }
private:
intptr_t line_;
intptr_t column_;
};
static constexpr auto kNoDwarfPositionInfo = DwarfPosition();
class InliningNode : public ZoneAllocated {
public:
InliningNode(const Function& function,
TokenPosition call_pos,
const DwarfPosition& position,
int32_t start_pc_offset)
: function(function),
call_pos(call_pos),
position(position),
start_pc_offset(start_pc_offset),
end_pc_offset(-1),
children_head(NULL),
@ -39,7 +60,7 @@ class InliningNode : public ZoneAllocated {
}
const Function& function;
TokenPosition call_pos;
DwarfPosition position;
int32_t start_pc_offset;
int32_t end_pc_offset;
InliningNode* children_head;
@ -402,6 +423,15 @@ void Dwarf::WriteConcreteFunctions(DwarfWriteStream* stream) {
}
}
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
@ -419,24 +449,23 @@ InliningNode* Dwarf::ExpandInliningTree(const Code& code) {
}
GrowableArray<InliningNode*> node_stack(zone_, 4);
GrowableArray<TokenPosition> token_positions(zone_, 4);
GrowableArray<DwarfPosition> token_positions(zone_, 4);
NoSafepointScope no_safepoint;
ReadStream stream(map.Data(), map.Length());
int32_t current_pc_offset = 0;
token_positions.Add(kNoDwarfPositionInfo);
InliningNode* root_node =
new (zone_) InliningNode(root_function, TokenPosition(), 0);
new (zone_) InliningNode(root_function, token_positions.Last(), 0);
root_node->end_pc_offset = code.Size();
node_stack.Add(root_node);
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);
token_positions[token_positions.length() - 1] = ReadPosition(&stream);
break;
}
case CodeSourceMapBuilder::kAdvancePC: {
@ -448,12 +477,11 @@ InliningNode* Dwarf::ExpandInliningTree(const Code& code) {
int32_t func = stream.Read<int32_t>();
const Function& child_func =
Function::ZoneHandle(zone_, Function::RawCast(functions.At(func)));
TokenPosition call_pos = token_positions.Last();
InliningNode* child_node =
new (zone_) InliningNode(child_func, call_pos, current_pc_offset);
InliningNode* child_node = new (zone_)
InliningNode(child_func, token_positions.Last(), current_pc_offset);
node_stack.Last()->AppendChild(child_node);
node_stack.Add(child_node);
token_positions.Add(CodeSourceMapBuilder::kInitialPosition);
token_positions.Add(kNoDwarfPositionInfo);
break;
}
case CodeSourceMapBuilder::kPopFunction: {
@ -489,7 +517,6 @@ void Dwarf::WriteInliningNode(DwarfWriteStream* stream,
const Script& parent_script,
SnapshotTextObjectNamer* namer) {
intptr_t file = LookupScript(parent_script);
const auto& token_pos = node->call_pos;
intptr_t function_index = LookupFunction(node->function);
const Script& script = Script::Handle(zone_, node->function.script());
@ -504,13 +531,10 @@ void Dwarf::WriteInliningNode(DwarfWriteStream* stream,
stream->OffsetFromSymbol(root_asm_name, node->end_pc_offset);
// DW_AT_call_file
stream->uleb128(file);
intptr_t line = kNoLineInformation;
intptr_t col = kNoColumnInformation;
Script::DecodePrecompiledPosition(token_pos, &line, &col);
// DW_AT_call_line
stream->uleb128(line);
stream->uleb128(node->position.line());
// DW_at_call_column
stream->uleb128(col);
stream->uleb128(node->position.column());
for (InliningNode* child = node->children_head; child != NULL;
child = child->children_next) {
@ -592,7 +616,7 @@ void Dwarf::WriteLineNumberProgram(DwarfWriteStream* stream) {
CodeSourceMap& map = CodeSourceMap::Handle(zone_);
Array& functions = Array::Handle(zone_);
GrowableArray<const Function*> function_stack(zone_, 8);
GrowableArray<TokenPosition> token_positions(zone_, 8);
GrowableArray<DwarfPosition> token_positions(zone_, 8);
SnapshotTextObjectNamer namer(zone_);
for (intptr_t i = 0; i < codes_.length(); i++) {
@ -614,15 +638,14 @@ void Dwarf::WriteLineNumberProgram(DwarfWriteStream* stream) {
int32_t current_pc_offset = 0;
function_stack.Add(&root_function);
token_positions.Add(CodeSourceMapBuilder::kInitialPosition);
token_positions.Add(kNoDwarfPositionInfo);
while (code_map_stream.PendingBytes() > 0) {
uint8_t opcode = code_map_stream.Read<uint8_t>();
switch (opcode) {
case CodeSourceMapBuilder::kChangePosition: {
int32_t position = code_map_stream.Read<int32_t>();
token_positions[token_positions.length() - 1] =
TokenPosition(position);
ReadPosition(&code_map_stream);
break;
}
case CodeSourceMapBuilder::kAdvancePC: {
@ -641,10 +664,8 @@ void Dwarf::WriteLineNumberProgram(DwarfWriteStream* stream) {
}
// 2. Update LNP line.
auto const position = token_positions.Last();
intptr_t line = kNoLineInformation;
intptr_t column = kNoColumnInformation;
Script::DecodePrecompiledPosition(position, &line, &column);
const intptr_t line = token_positions.Last().line();
const intptr_t column = token_positions.Last().column();
if (line != previous_line) {
stream->u1(DW_LNS_advance_line);
stream->sleb128(line - previous_line);
@ -684,7 +705,7 @@ void Dwarf::WriteLineNumberProgram(DwarfWriteStream* stream) {
const Function& child_func = Function::Handle(
zone_, Function::RawCast(functions.At(func_index)));
function_stack.Add(&child_func);
token_positions.Add(CodeSourceMapBuilder::kInitialPosition);
token_positions.Add(kNoDwarfPositionInfo);
break;
}
case CodeSourceMapBuilder::kPopFunction: {

View file

@ -325,9 +325,6 @@ class Dwarf : public ZoneAllocated {
kInlinedFunction,
};
static constexpr intptr_t kNoLineInformation = 0;
static constexpr intptr_t kNoColumnInformation = 0;
void WriteAbstractFunctions(DwarfWriteStream* stream);
void WriteConcreteFunctions(DwarfWriteStream* stream);
InliningNode* ExpandInliningTree(const Code& code);

View file

@ -10755,96 +10755,30 @@ void Script::SetLocationOffset(intptr_t line_offset,
StoreNonPointer(&raw_ptr()->col_offset_, col_offset);
}
// Whether a precompiled (non-special) position contains column information.
using PrecompiledPositionContainsColumn = BitField<int32_t, bool, 0, 1>;
// Can be used if PrecompiledPositionContainsColumn::decode(v) is true.
using PrecompiledPositionColumn =
BitField<int32_t,
uint32_t,
PrecompiledPositionContainsColumn::kNextBit,
10>;
// Can be used if PrecompiledPositionContainsColumn::decode(v) is true.
// Does not include the sign bit, which should be 0 for encoded values.
using PrecompiledPositionLine =
BitField<int32_t,
uint32_t,
PrecompiledPositionColumn::kNextBit,
(sizeof(int32_t) * kBitsPerByte - 1) -
(PrecompiledPositionColumn::bitsize() +
PrecompiledPositionContainsColumn::bitsize())>;
// Can be used if PrecompiledPositionContainsColumn::decode(v) is false.
// Does not include the sign bit, which should be 0 for encoded values.
using PrecompiledPositionLineOnly =
BitField<int32_t,
uint32_t,
PrecompiledPositionContainsColumn::kNextBit,
(sizeof(int32_t) * kBitsPerByte - 1) -
PrecompiledPositionContainsColumn::bitsize()>;
bool Script::DecodePrecompiledPosition(TokenPosition token_pos,
intptr_t* line,
intptr_t* column) {
ASSERT(line != nullptr);
ASSERT(column != nullptr);
auto const value = token_pos.value();
if (value < 0) return false;
// When storing CodeSourceMaps in the snapshot, we just add unencoded lines.
if (!FLAG_dwarf_stack_traces_mode) {
*line = value;
return true;
}
// We encode zero-based offsets from start, so convert back to ordinals.
if (PrecompiledPositionContainsColumn::decode(value)) {
*line = PrecompiledPositionLine::decode(value) + 1;
*column = PrecompiledPositionColumn::decode(value) + 1;
} else {
*line = PrecompiledPositionLineOnly::decode(value) + 1;
}
return true;
}
// Specialized for AOT compilation, which does this lookup for every token
// position that could be part of a stack trace.
int32_t Script::GetTokenLocationUsingLineStarts(
TokenPosition target_token_pos) const {
#if !defined(DART_PRECOMPILED_RUNTIME)
bool Script::GetTokenLocationUsingLineStarts(TokenPosition target_token_pos,
intptr_t* line,
intptr_t* column) const {
#if defined(DART_PRECOMPILED_RUNTIME)
return false;
#else
// Negative positions denote positions that do not correspond to Dart code.
if (target_token_pos.value() < 0) return TokenPosition::kNoSourcePos;
if (target_token_pos.value() < 0) return false;
Zone* zone = Thread::Current()->zone();
TypedData& line_starts_data = TypedData::Handle(zone, line_starts());
// Scripts loaded from bytecode may have null line_starts().
if (line_starts_data.IsNull()) return TokenPosition::kNoSourcePos;
if (line_starts_data.IsNull()) return false;
kernel::KernelLineStartsReader line_starts_reader(line_starts_data, zone);
intptr_t line = -1;
intptr_t col = -1;
line_starts_reader.LocationForPosition(target_token_pos.value(), &line, &col);
line_starts_reader.LocationForPosition(target_token_pos.value(), line,
column);
// The line and column numbers returned are ordinals, so we shouldn't get 0.
ASSERT(line > 0);
ASSERT(col > 0);
// Only return (unencoded) line information when storing CodeSourceMaps.
if (!FLAG_dwarf_stack_traces_mode) {
if (Utils::IsUint(31, line)) {
return line;
}
return TokenPosition::kNoSourcePos;
}
// Encode the returned line and column numbers as 0-based offsets from start
// instead of ordinal numbers for better encoding.
line -= 1;
col -= 1;
if (PrecompiledPositionLine::is_valid(line) &&
PrecompiledPositionColumn::is_valid(col)) {
return PrecompiledPositionLine::encode(line) |
PrecompiledPositionColumn::encode(col) |
PrecompiledPositionContainsColumn::encode(true);
} else if (PrecompiledPositionLineOnly::is_valid(line)) {
return PrecompiledPositionLineOnly::encode(line) |
PrecompiledPositionContainsColumn::encode(false);
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
return TokenPosition::kNoSourcePos;
ASSERT(*line > 0);
ASSERT(*column > 0);
return true;
#endif
}
#if !defined(DART_PRECOMPILED_RUNTIME)
@ -23967,7 +23901,7 @@ static void PrintSymbolicStackFrame(Zone* zone,
intptr_t line = -1;
intptr_t column = -1;
if (FLAG_precompiled_mode) {
Script::DecodePrecompiledPosition(token_pos, &line, &column);
line = token_pos.value();
} else if (token_pos.IsSourcePosition()) {
ASSERT(!script.IsNull());
script.GetTokenLocation(token_pos.SourcePosition(), &line, &column);

View file

@ -4495,14 +4495,9 @@ class Script : public Object {
void SetLocationOffset(intptr_t line_offset, intptr_t col_offset) const;
// Decode line number and column information if present. Returns false if
// this is a special location and thus undecodable.
static bool DecodePrecompiledPosition(TokenPosition token_pos,
intptr_t* line,
intptr_t* column);
// For positions that have line numbers and columns, returns a non-negative
// value. Otherwise, returns -1.
int32_t GetTokenLocationUsingLineStarts(TokenPosition token_pos) const;
bool GetTokenLocationUsingLineStarts(TokenPosition token_pos,
intptr_t* line,
intptr_t* column) const;
void GetTokenLocation(TokenPosition token_pos,
intptr_t* line,
intptr_t* column,