[vm] Signal bad token positions and lines in KernelLineStartsReader.

First, change LocationForPosition and TokenRangeAtLine to return
whether they successfully located the offset/line. Also change the
wrappers in Script (GetTokenLocation and TokenRangeAtLine) to return
whether or not any information was successfully located.

These methods now only change the out parameters in the case that
appropriate information was found, so any unconditional uses of the out
parameters need the out parameters to be appropriately initialized.

We now allow negative lines to be requested in TokenRangeAtLine (with
the failure behavior described above) so the line returned by
LocationAtPosition can be fed into TokenRangeAtLine without intermediate
checking.

The calculation of the token length, which uses the script source and
not the line starts array, has been moved to a new method,
Script::GetTokenLength.  The new method returns the length (or a
negative value if the token length could not be determined) instead of
using an out parameter.

TEST=Existing tests on trybots, to ensure tests using current
line/number info aren't affected.

Bug: https://github.com/dart-lang/sdk/issues/44436

Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-product-x64-try,vm-kernel-linux-product-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm-try
Change-Id: Ibc048a226d11ff9a340a8d249654d07720fdf115
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175365
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Clement Skau <cskau@google.com>
This commit is contained in:
Tess Strickland 2020-12-16 11:14:12 +00:00 committed by commit-bot@chromium.org
parent 868cb26a2d
commit 66646f312c
16 changed files with 208 additions and 190 deletions

View file

@ -82,23 +82,25 @@ DEFINE_NATIVE_ENTRY(AssertionError_throwNew, 0, 3) {
const Script& script = Script::Handle(FindScript(&iterator));
// Initialize argument 'failed_assertion' with source snippet.
intptr_t from_line, from_column;
script.GetTokenLocation(assertion_start, &from_line, &from_column);
intptr_t to_line, to_column;
script.GetTokenLocation(assertion_end, &to_line, &to_column);
auto& condition_text = String::Handle();
// Extract the assertion condition text (if source is available).
auto& condition_text = String::Handle(
script.GetSnippet(from_line, from_column, to_line, to_column));
intptr_t from_line = -1, from_column = -1;
if (script.GetTokenLocation(assertion_start, &from_line, &from_column)) {
// Extract the assertion condition text (if source is available).
intptr_t to_line, to_column;
script.GetTokenLocation(assertion_end, &to_line, &to_column);
condition_text =
script.GetSnippet(from_line, from_column, to_line, to_column);
}
if (condition_text.IsNull()) {
condition_text = Symbols::OptimizedOut().raw();
}
args.SetAt(0, condition_text);
// Initialize location arguments starting at position 1.
// Do not set a column if the source has been generated as it will be wrong.
args.SetAt(1, String::Handle(script.url()));
args.SetAt(2, Smi::Handle(Smi::New(from_line)));
args.SetAt(3, Smi::Handle(Smi::New(script.HasSource() ? from_column : -1)));
args.SetAt(3, Smi::Handle(Smi::New(from_column)));
args.SetAt(4, message);
Exceptions::ThrowByType(Exceptions::kAssertion, args);
@ -181,8 +183,8 @@ DEFINE_NATIVE_ENTRY(FallThroughError_throwNew, 0, 1) {
iterator.NextFrame(); // Skip native call.
const Script& script = Script::Handle(Exceptions::GetCallerScript(&iterator));
args.SetAt(0, String::Handle(script.url()));
intptr_t line;
script.GetTokenLocation(fallthrough_pos, &line, NULL);
intptr_t line = -1;
script.GetTokenLocation(fallthrough_pos, &line);
args.SetAt(1, Smi::Handle(Smi::New(line)));
Exceptions::ThrowByType(Exceptions::kFallThrough, args);
@ -208,8 +210,8 @@ DEFINE_NATIVE_ENTRY(AbstractClassInstantiationError_throwNew, 0, 2) {
const Script& script = Script::Handle(Exceptions::GetCallerScript(&iterator));
args.SetAt(0, class_name);
args.SetAt(1, String::Handle(script.url()));
intptr_t line;
script.GetTokenLocation(error_pos, &line, NULL);
intptr_t line = -1;
script.GetTokenLocation(error_pos, &line);
args.SetAt(2, Smi::Handle(Smi::New(line)));
Exceptions::ThrowByType(Exceptions::kAbstractClassInstantiation, args);

View file

@ -1628,17 +1628,8 @@ DEFINE_NATIVE_ENTRY(DeclarationMirror_location, 0, 1) {
}
const String& uri = String::Handle(zone, script.url());
intptr_t from_line = 0;
intptr_t from_col = 0;
if (script.HasSource()) {
script.GetTokenLocation(token_pos, &from_line, &from_col);
} else {
// Avoid the slow path of printing the token stream when precise source
// information is not available.
script.GetTokenLocation(token_pos, &from_line, NULL);
}
// We should always have at least the line number.
ASSERT(from_line != 0);
intptr_t from_line = 0, from_col = 0;
script.GetTokenLocation(token_pos, &from_line, &from_col);
return CreateSourceLocation(uri, from_line, from_col);
}

View file

@ -140,7 +140,12 @@ void Expect::FloatEquals(const E& expected, const A& actual, const T& tol) {
inline void Expect::StringEquals(const char* expected, const char* actual) {
if (strcmp(expected, actual) == 0) return;
Fail("expected:\n<\"%s\">\nbut was:\n<\"%s\">", expected, actual);
if (actual == nullptr) {
Fail("expected:\n<\"%s\">\nbut was nullptr", expected);
} else {
if (strcmp(expected, actual) == 0) return;
Fail("expected:\n<\"%s\">\nbut was:\n<\"%s\">", expected, actual);
}
}
inline void Expect::IsSubstring(const char* needle, const char* haystack) {

View file

@ -535,13 +535,13 @@ void FlowGraphCompiler::EmitSourceLine(Instruction* instr) {
}
const Script& script =
Script::Handle(zone(), instr->env()->function().script());
intptr_t line_nr;
intptr_t column_nr;
script.GetTokenLocation(instr->token_pos(), &line_nr, &column_nr);
const String& line = String::Handle(zone(), script.GetLine(line_nr));
assembler()->Comment("Line %" Pd " in '%s':\n %s", line_nr,
instr->env()->function().ToFullyQualifiedCString(),
line.ToCString());
intptr_t line_nr, column_nr;
if (script.GetTokenLocation(instr->token_pos(), &line_nr, &column_nr)) {
const String& line = String::Handle(zone(), script.GetLine(line_nr));
assembler()->Comment("Line %" Pd " in '%s':\n %s", line_nr,
instr->env()->function().ToFullyQualifiedCString(),
line.ToCString());
}
}
static bool IsPusher(Instruction* instr) {

View file

@ -567,7 +567,7 @@ intptr_t ActivationFrame::LineNumber() {
const TokenPosition& token_pos = TokenPos();
if ((line_number_ < 0) && token_pos.IsReal()) {
const Script& script = Script::Handle(SourceScript());
script.GetTokenLocation(token_pos, &line_number_, nullptr);
script.GetTokenLocation(token_pos, &line_number_, &column_number_);
}
return line_number_;
}
@ -1465,7 +1465,7 @@ intptr_t CodeBreakpoint::LineNumber() {
// Compute line number lazily since it causes scanning of the script.
if (line_number_ < 0) {
const Script& script = Script::Handle(SourceCode());
script.GetTokenLocation(token_pos_, &line_number_, NULL);
script.GetTokenLocation(token_pos_, &line_number_);
}
return line_number_;
}
@ -2241,7 +2241,8 @@ static void RefineBreakpointPos(const Script& script,
TokenPosition token_end_pos =
TokenPosition::Min(next_closest_token_position, end_of_line_pos);
if ((exact_token_pos.IsReal() && (token_end_pos < exact_token_pos)) ||
if ((token_end_pos.IsReal() && exact_token_pos.IsReal() &&
(token_end_pos < exact_token_pos)) ||
(token_start_column > *best_column)) {
// Prefer the token with the lowest column number compatible
// with the requested column.
@ -2386,8 +2387,8 @@ TokenPosition Debugger::ResolveBreakpointPos(const Function& func,
const TokenPosition begin_pos = best_fit_pos;
TokenPosition end_of_line_pos = TokenPosition::kNoSource;
if (best_line == -1) {
script.GetTokenLocation(begin_pos, &best_line, nullptr);
if (best_line < 0) {
script.GetTokenLocation(begin_pos, &best_line);
}
ASSERT(best_line > 0);
TokenPosition ignored = TokenPosition::kNoSource;
@ -2754,8 +2755,8 @@ BreakpointLocation* Debugger::SetCodeBreakpoints(
MakeCodeBreakpointAt(func, loc);
}
if (FLAG_verbose_debug) {
intptr_t line_number;
intptr_t column_number;
intptr_t line_number = -1;
intptr_t column_number = -1;
script.GetTokenLocation(breakpoint_pos, &line_number, &column_number);
OS::PrintErr("Resolved code breakpoint for function '%s' at line %" Pd
" col %" Pd "\n",
@ -2818,8 +2819,8 @@ BreakpointLocation* Debugger::SetBreakpoint(const Script& script,
// initializer of a field at |token_pos|. Hence, Register an unresolved
// breakpoint.
if (FLAG_verbose_debug) {
intptr_t line_number;
intptr_t column_number;
intptr_t line_number = -1;
intptr_t column_number = -1;
script.GetTokenLocation(token_pos, &line_number, &column_number);
if (func.IsNull()) {
OS::PrintErr(
@ -3855,12 +3856,11 @@ TokenPosition Debugger::FindExactTokenPosition(const Script& script,
intptr_t column_number) {
intptr_t line;
intptr_t col;
script.GetTokenLocation(start_of_line, &line, &col);
if (line < 0) {
return TokenPosition::kNoSource;
if (script.GetTokenLocation(start_of_line, &line, &col)) {
return TokenPosition::Deserialize(start_of_line.Pos() +
(column_number - col));
}
return TokenPosition::Deserialize(start_of_line.Pos() +
(column_number - col));
return TokenPosition::kNoSource;
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)

View file

@ -382,14 +382,15 @@ intptr_t DeoptContext::MaterializeDeferredObjects() {
const Function& top_function = Function::Handle(code.function());
const Script& script = Script::Handle(top_function.script());
const TokenPosition token_pos = code.GetTokenIndexOfPC(top_frame->pc());
intptr_t line, column;
script.GetTokenLocation(token_pos, &line, &column);
String& line_string = String::Handle(script.GetLine(line));
THR_Print(" Function: %s\n", top_function.ToFullyQualifiedCString());
char line_buffer[80];
Utils::SNPrint(line_buffer, sizeof(line_buffer), " Line %" Pd ": '%s'",
line, line_string.ToCString());
THR_Print("%s\n", line_buffer);
intptr_t line;
if (script.GetTokenLocation(token_pos, &line)) {
String& line_string = String::Handle(script.GetLine(line));
char line_buffer[80];
Utils::SNPrint(line_buffer, sizeof(line_buffer), " Line %" Pd ": '%s'",
line, line_string.ToCString());
THR_Print("%s\n", line_buffer);
}
THR_Print(" Deopt args: %" Pd "\n", deopt_arg_count);
}

View file

@ -919,7 +919,7 @@ void Exceptions::CreateAndThrowTypeError(TokenPosition location,
zone, script.IsNull() ? Symbols::OptimizedOut().raw() : script.url());
intptr_t line = -1;
intptr_t column = -1;
if (!script.IsNull() && location.IsReal()) {
if (!script.IsNull()) {
script.GetTokenLocation(location, &line, &column);
}
// Initialize '_url', '_line', and '_column' arguments.

View file

@ -35,7 +35,7 @@ KernelLineStartsReader::KernelLineStartsReader(
}
}
void KernelLineStartsReader::LocationForPosition(intptr_t position,
bool KernelLineStartsReader::LocationForPosition(intptr_t position,
intptr_t* line,
intptr_t* col) const {
intptr_t line_count = line_starts_data_.Length();
@ -45,46 +45,43 @@ void KernelLineStartsReader::LocationForPosition(intptr_t position,
current_start += helper_->At(line_starts_data_, i);
if (current_start > position) {
*line = i;
if (col != NULL) {
if (col != nullptr) {
*col = position - previous_start + 1;
}
return;
return true;
}
if (current_start == position) {
*line = i + 1;
if (col != NULL) {
if (col != nullptr) {
*col = 1;
}
return;
return true;
}
previous_start = current_start;
}
// If the start of any of the lines did not cross |position|,
// then it means the position falls on the last line.
*line = line_count;
if (col != NULL) {
*col = position - current_start + 1;
}
return false;
}
void KernelLineStartsReader::TokenRangeAtLine(
intptr_t source_length,
bool KernelLineStartsReader::TokenRangeAtLine(
intptr_t line_number,
TokenPosition* first_token_index,
TokenPosition* last_token_index) const {
ASSERT(line_number <= line_starts_data_.Length());
if (line_number < 0 || line_number > line_starts_data_.Length()) {
return false;
}
intptr_t cumulative = 0;
for (intptr_t i = 0; i < line_number; ++i) {
cumulative += helper_->At(line_starts_data_, i);
}
*first_token_index = dart::TokenPosition::Deserialize(cumulative);
if (line_number == line_starts_data_.Length()) {
*last_token_index = dart::TokenPosition::Deserialize(source_length);
*last_token_index = *first_token_index;
} else {
*last_token_index = dart::TokenPosition::Deserialize(
cumulative + helper_->At(line_starts_data_, line_number) - 1);
}
return true;
}
int32_t KernelLineStartsReader::KernelInt8LineStartsHelper::At(

View file

@ -140,14 +140,21 @@ class KernelLineStartsReader {
return helper_->At(line_starts_data_, index);
}
void LocationForPosition(intptr_t position,
intptr_t* line,
intptr_t* col) const;
// Returns whether the given offset corresponds to a valid source offset
// If it does, then *line and *column (if column is not nullptr) are set
// to the line and column the token starts at.
DART_WARN_UNUSED_RESULT bool LocationForPosition(
intptr_t position,
intptr_t* line,
intptr_t* col = nullptr) const;
void TokenRangeAtLine(intptr_t source_length,
intptr_t line_number,
dart::TokenPosition* first_token_index,
dart::TokenPosition* last_token_index) const;
// Returns whether any tokens were found for the given line. When found,
// *first_token_index and *last_token_index are set to the first and
// last token on the line, respectively.
DART_WARN_UNUSED_RESULT bool TokenRangeAtLine(
intptr_t line_number,
dart::TokenPosition* first_token_index,
dart::TokenPosition* last_token_index) const;
private:
class KernelLineStartsHelper {

View file

@ -9378,13 +9378,18 @@ StringPtr Function::GetSource() const {
Zone* zone = Thread::Current()->zone();
const Script& func_script = Script::Handle(zone, script());
intptr_t from_line;
intptr_t from_col;
intptr_t to_line;
intptr_t to_col;
intptr_t to_length;
func_script.GetTokenLocation(token_pos(), &from_line, &from_col);
func_script.GetTokenLocation(end_token_pos(), &to_line, &to_col, &to_length);
intptr_t from_line, from_col;
if (!func_script.GetTokenLocation(token_pos(), &from_line, &from_col)) {
return String::null();
}
intptr_t to_line, to_col;
if (!func_script.GetTokenLocation(end_token_pos(), &to_line, &to_col)) {
return String::null();
}
intptr_t to_length = func_script.GetTokenLength(end_token_pos());
if (to_length < 0) {
return String::null();
}
if (to_length == 1) {
// Handle special cases for end tokens of closures (where we exclude the
@ -11269,70 +11274,79 @@ static bool IsIdentChar(int32_t c) {
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
void Script::GetTokenLocation(TokenPosition token_pos,
bool Script::GetTokenLocation(const TokenPosition& token_pos,
intptr_t* line,
intptr_t* column,
intptr_t* token_len) const {
intptr_t* column) const {
ASSERT(line != nullptr);
// Set up appropriate values for any early returns.
*line = -1;
if (column != nullptr) {
*column = -1;
}
if (token_len != nullptr) {
*token_len = 1;
}
#if defined(DART_PRECOMPILED_RUNTIME)
// Scripts in the AOT snapshot do not have a line starts array.
#if !defined(DART_PRECOMPILED_RUNTIME)
if (!token_pos.IsReal()) return;
return false;
#else
if (!token_pos.IsReal()) return false;
auto const zone = Thread::Current()->zone();
LookupSourceAndLineStarts(zone);
const TypedData& line_starts_data = TypedData::Handle(zone, line_starts());
if (line_starts_data.IsNull()) return false;
kernel::KernelLineStartsReader line_starts_reader(line_starts_data, zone);
const intptr_t pos = token_pos.Pos();
line_starts_reader.LocationForPosition(pos, line, column);
if (token_len == nullptr) return;
*token_len = 1;
// We don't explicitly save this data: Load the source
// and find it from there.
const String& source = String::Handle(zone, Source());
if (!source.IsNull()) {
intptr_t offset = pos;
if (offset < source.Length() && IsIdentStartChar(source.CharAt(offset))) {
for (intptr_t i = offset + 1;
i < source.Length() && IsIdentChar(source.CharAt(i)); ++i) {
++*token_len;
}
}
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
return line_starts_reader.LocationForPosition(token_pos.Pos(), line, column);
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
void Script::TokenRangeAtLine(intptr_t line_number,
intptr_t Script::GetTokenLength(const TokenPosition& token_pos) const {
#if defined(DART_PRECOMPILED_RUNTIME)
// Scripts in the AOT snapshot do not have their source.
return -1;
#else
if (!HasSource() || !token_pos.IsReal()) return -1;
auto const zone = Thread::Current()->zone();
LookupSourceAndLineStarts(zone);
// We don't explicitly save this data: Load the source and find it from there.
const String& source = String::Handle(zone, Source());
const intptr_t start = token_pos.Pos();
if (start >= source.Length()) return -1; // Can't determine token_len.
intptr_t end = start;
if (IsIdentStartChar(source.CharAt(end++))) {
for (; end < source.Length(); ++end) {
if (!IsIdentChar(source.CharAt(end))) break;
}
}
return end - start;
#endif
}
bool Script::TokenRangeAtLine(intptr_t line_number,
TokenPosition* first_token_index,
TokenPosition* last_token_index) const {
ASSERT(first_token_index != NULL && last_token_index != NULL);
ASSERT(line_number > 0);
ASSERT(first_token_index != nullptr && last_token_index != nullptr);
#if defined(DART_PRECOMPILED_RUNTIME)
// Scripts in the AOT snapshot do not have a line starts array.
#if !defined(DART_PRECOMPILED_RUNTIME)
return false;
#else
// Line numbers are 1-indexed.
if (line_number <= 0) return false;
Zone* zone = Thread::Current()->zone();
LookupSourceAndLineStarts(zone);
const String& source = String::Handle(zone, Source());
const TypedData& line_starts_data = TypedData::Handle(zone, line_starts());
kernel::KernelLineStartsReader line_starts_reader(line_starts_data, zone);
if (!line_starts_reader.TokenRangeAtLine(line_number, first_token_index,
last_token_index)) {
return false;
}
#if defined(DEBUG)
intptr_t source_length;
if (source.IsNull()) {
if (!HasSource()) {
Smi& value = Smi::Handle(zone);
const Array& debug_positions_array = Array::Handle(zone, debug_positions());
value ^= debug_positions_array.At(debug_positions_array.Length() - 1);
source_length = value.Value();
} else {
const String& source = String::Handle(zone, Source());
source_length = source.Length();
}
const TypedData& line_starts_data = TypedData::Handle(zone, line_starts());
kernel::KernelLineStartsReader line_starts_reader(line_starts_data, zone);
line_starts_reader.TokenRangeAtLine(source_length, line_number,
first_token_index, last_token_index);
ASSERT(last_token_index->Serialize() <= source_length);
#endif
return true;
#endif // !defined(DART_PRECOMPILED_RUNTIME)
}
@ -11349,7 +11363,8 @@ static intptr_t GetRelativeSourceIndex(const String& src,
intptr_t column = 1,
intptr_t column_offset = 0,
intptr_t starting_index = 0) {
if (starting_index < 0 || line < 1 || column < 1) {
if (starting_index < 0 || line < 1 || column < 1 || line <= line_offset ||
(line == line_offset + 1 && column <= column_offset)) {
return -1;
}
intptr_t len = src.Length();
@ -11391,10 +11406,10 @@ static intptr_t GetRelativeSourceIndex(const String& src,
}
StringPtr Script::GetLine(intptr_t line_number, Heap::Space space) const {
const String& src = String::Handle(Source());
if (src.IsNull()) {
if (!HasSource()) {
return Symbols::OptimizedOut().raw();
}
const String& src = String::Handle(Source());
const intptr_t start =
GetRelativeSourceIndex(src, line_number, line_offset());
if (start < 0) {
@ -11414,11 +11429,10 @@ StringPtr Script::GetSnippet(intptr_t from_line,
intptr_t from_column,
intptr_t to_line,
intptr_t to_column) const {
const String& src = String::Handle(Source());
if (src.IsNull()) {
if (!HasSource()) {
return Symbols::OptimizedOut().raw();
}
const String& src = String::Handle(Source());
const intptr_t start = GetRelativeSourceIndex(src, from_line, line_offset(),
from_column, col_offset());
// Lines and columns are 1-based, so need to subtract one to get offsets.
@ -24226,13 +24240,14 @@ static void PrintSymbolicStackFrame(Zone* zone,
intptr_t line = -1;
intptr_t column = -1;
if (token_pos.IsReal()) {
if (FLAG_precompiled_mode) {
if (FLAG_precompiled_mode) {
ASSERT(token_pos.IsNoSource() || token_pos.IsReal());
if (token_pos.IsReal()) {
line = token_pos.Pos();
} else {
ASSERT(!script.IsNull());
script.GetTokenLocation(token_pos, &line, &column);
}
} else {
ASSERT(!script.IsNull());
script.GetTokenLocation(token_pos, &line, &column);
}
PrintSymbolicStackFrameIndex(buffer, frame_index);
PrintSymbolicStackFrameBody(buffer, function_name, url, line, column);

View file

@ -4543,16 +4543,20 @@ class Script : public Object {
void SetLocationOffset(intptr_t line_offset, intptr_t col_offset) const;
void GetTokenLocation(TokenPosition token_pos,
// Returns whether a line and column could be computed for the given token
// position and, if so, sets *line and *column (if not nullptr).
bool GetTokenLocation(const TokenPosition& token_pos,
intptr_t* line,
intptr_t* column,
intptr_t* token_len = NULL) const;
intptr_t* column = nullptr) const;
// Returns index of first and last token on the given line. Returns both
// indices < 0 if no token exists on or after the line. If a token exists
// after, but not on given line, returns in *first_token_index the index of
// the first token after the line, and a negative value in *last_token_index.
void TokenRangeAtLine(intptr_t line_number,
// Returns the length of the token at the given position. If the length cannot
// be determined, returns a negative value.
intptr_t GetTokenLength(const TokenPosition& token_pos) const;
// Returns whether any tokens were found for the given line. When found,
// *first_token_index and *last_token_index are set to the first and
// last token on the line, respectively.
bool TokenRangeAtLine(intptr_t line_number,
TokenPosition* first_token_index,
TokenPosition* last_token_index) const;

View file

@ -292,7 +292,7 @@ TEST_CASE(Class_EndTokenPos) {
const Script& scr = Script::Handle(cls.script());
intptr_t line;
intptr_t col;
scr.GetTokenLocation(end_token_pos, &line, &col);
EXPECT(scr.GetTokenLocation(end_token_pos, &line, &col));
EXPECT_EQ(9, line);
EXPECT_EQ(1, col);
}

View file

@ -262,36 +262,36 @@ class ProfileStackWalker {
const char* CurrentToken() {
if (!as_functions_) {
return NULL;
return nullptr;
}
ProfileFunction* func = GetFunction();
const Function& function = *(func->function());
if (function.IsNull()) {
// No function.
return NULL;
return nullptr;
}
Zone* zone = Thread::Current()->zone();
const Script& script = Script::Handle(zone, function.script());
if (script.IsNull()) {
// No script.
return NULL;
return nullptr;
}
ProfileFunctionSourcePosition pfsp(TokenPosition::kNoSource);
if (!func->GetSinglePosition(&pfsp)) {
// Not exactly one source position.
return NULL;
}
TokenPosition token_pos = pfsp.token_pos();
if (!token_pos.IsReal()) {
// Not a location in a script.
return NULL;
return nullptr;
}
intptr_t line = 0, column = 0, token_len = 0;
script.GetTokenLocation(token_pos, &line, &column, &token_len);
const auto& str = String::Handle(
zone, script.GetSnippet(line, column, line, column + token_len));
return str.IsNull() ? NULL : str.ToCString();
const TokenPosition& token_pos = pfsp.token_pos();
intptr_t line, column;
if (script.GetTokenLocation(token_pos, &line, &column)) {
const intptr_t token_len = script.GetTokenLength(token_pos);
const auto& str = String::Handle(
zone, script.GetSnippet(line, column, line, column + token_len));
if (!str.IsNull()) return str.ToCString();
}
// Couldn't get line/number information.
return nullptr;
}
intptr_t CurrentInclusiveTicks() {

View file

@ -38,29 +38,20 @@ StringPtr Report::PrependSnippet(Kind kind,
UNREACHABLE();
}
String& result = String::Handle();
if (!script.IsNull() && !String::Handle(script.Source()).IsNull()) {
if (!script.IsNull() && script.HasSource()) {
const String& script_url = String::Handle(script.url());
if (token_pos.IsReal()) {
intptr_t line, column, token_len;
script.GetTokenLocation(token_pos, &line, &column, &token_len);
intptr_t line, column;
if (script.GetTokenLocation(token_pos, &line, &column)) {
const intptr_t token_len = script.GetTokenLength(token_pos);
if (report_after_token) {
column += token_len;
column += token_len < 0 ? 1 : token_len;
}
// Only report the line position if we have the original source. We still
// need to get a valid column so that we can report the ^ mark below the
// snippet.
// Allocate formatted strings in old space as they may be created during
// optimizing compilation. Those strings are created rarely and should not
// polute old space.
if (script.HasSource()) {
result = String::NewFormatted(
Heap::kOld, "'%s': %s: line %" Pd " pos %" Pd ": ",
script_url.ToCString(), message_header, line, column);
} else {
result =
String::NewFormatted(Heap::kOld, "'%s': %s: line %" Pd ": ",
script_url.ToCString(), message_header, line);
}
result = String::NewFormatted(
Heap::kOld, "'%s': %s: line %" Pd " pos %" Pd ": ",
script_url.ToCString(), message_header, line, column);
// Append the formatted error or warning message.
const Array& strs = Array::Handle(Array::New(6, Heap::kOld));
strs.SetAt(0, result);

View file

@ -281,15 +281,18 @@ void SimulatorDebugger::PrintDartFrame(uword vm_instructions,
const Script& script = Script::Handle(function.script());
const String& func_name = String::Handle(function.QualifiedScrubbedName());
const String& url = String::Handle(script.url());
intptr_t line = -1;
intptr_t column = -1;
if (token_pos.IsReal()) {
script.GetTokenLocation(token_pos, &line, &column);
intptr_t line, column;
if (script.GetTokenLocation(token_pos, &line, &column)) {
OS::PrintErr(
"pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")", pc,
fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
func_name.ToCString(), url.ToCString(), line, column);
} else {
OS::PrintErr("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s)", pc, fp, sp,
is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
func_name.ToCString(), url.ToCString());
}
OS::PrintErr(
"pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")", pc,
fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
func_name.ToCString(), url.ToCString(), line, column);
#if defined(DART_PRECOMPILED_RUNTIME)
intptr_t offset;
auto const symbol_name =

View file

@ -309,15 +309,17 @@ void SimulatorDebugger::PrintDartFrame(uword vm_instructions,
const Script& script = Script::Handle(function.script());
const String& func_name = String::Handle(function.QualifiedScrubbedName());
const String& url = String::Handle(script.url());
intptr_t line = -1;
intptr_t column = -1;
if (token_pos.IsReal()) {
script.GetTokenLocation(token_pos, &line, &column);
intptr_t line, column;
if (script.GetTokenLocation(token_pos, &line, &column)) {
OS::PrintErr(
"pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")", pc,
fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
func_name.ToCString(), url.ToCString(), line, column);
} else {
OS::PrintErr("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s)", pc, fp, sp,
is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
func_name.ToCString(), url.ToCString());
}
OS::PrintErr(
"pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")", pc,
fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
func_name.ToCString(), url.ToCString(), line, column);
#if defined(DART_PRECOMPILED_RUNTIME)
intptr_t offset;
auto const symbol_name =