Include metadata in AOT to expand inline frames in stack traces and provide line numbers.

Also fix stack trace collection to always include invisible frames. It can happen that a visible function is inlined into an invisible function, and we don't expand inlined frames until we print a stack trace.

dart2js product x64:
compile time: 12.459s
VMIsolate(CodeSize): 152292
Isolate(CodeSize): 3343117
ReadOnlyData(CodeSize): 3728928
Instructions(CodeSize): 8677600
Total(CodeSize): 15901937
->
compile time: 14.195s (+13%)
VMIsolate(CodeSize): 174034
Isolate(CodeSize): 3892418 (+16%)
ReadOnlyData(CodeSize): 5036320 (+35%)
Instructions(CodeSize): 8682624
Total(CodeSize): 17785396 (+12%)

R=asiva@google.com

Review-Url: https://codereview.chromium.org/2687143005 .
This commit is contained in:
Ryan Macnak 2017-02-13 10:27:36 -08:00
parent f0e657015d
commit cfe5e5f075
20 changed files with 306 additions and 118 deletions

View file

@ -0,0 +1,80 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Test correct source positions in stack trace with optimized functions.
import "package:expect/expect.dart";
// (1) Test normal exception.
foo(x) => bar(x);
bar(x) {
if (x == null) throw 42; // throw at position 11:18
return x + 1;
}
test1() {
// First unoptimized.
try {
foo(null);
Expect.fail("Unreachable");
} catch (e, stacktrace) {
String s = stacktrace.toString();
print(s);
Expect.isFalse(s.contains("-1:-1"), "A");
Expect.isTrue(s.contains("optimized_stacktrace_line_and_column_test.dart:11:18"), "B");
}
// Optimized.
for (var i=0; i<10000; i++) foo(42);
try {
foo(null);
Expect.fail("Unreachable");
} catch (e, stacktrace) {
String s = stacktrace.toString();
print(s);
Expect.isFalse(s.contains("-1:-1"), "C");
Expect.isTrue(s.contains("optimized_stacktrace_line_and_column_test.dart:11:18"), "D");
}
}
// (2) Test checked mode exceptions.
maximus(x) => moritz(x);
moritz(x) {
if (x == 333) return 42 ? 0 : 1; // Throws in checked mode.
if (x == 777) {
bool b = x; // Throws in checked mode.
return b;
}
return x + 1;
}
test2() {
for (var i=0; i<100000; i++) maximus(42);
try {
maximus(333);
} catch (e, stacktrace) {
String s = stacktrace.toString();
print(s);
Expect.isTrue(s.contains("maximus"), "E");
Expect.isTrue(s.contains("moritz"), "F");
Expect.isFalse(s.contains("-1:-1"), "G");
}
try {
maximus(777);
} catch (e, stacktrace) {
String s = stacktrace.toString();
print(s);
Expect.isTrue(s.contains("maximus"), "H");
Expect.isTrue(s.contains("moritz"), "I");
Expect.isFalse(s.contains("-1:-1"), "J");
}
}
main() {
test1();
test2();
}

View file

@ -19,8 +19,9 @@ test1() {
Expect.fail("Unreachable");
} catch (e, stacktrace) {
String s = stacktrace.toString();
Expect.isFalse(s.contains("-1:-1"));
Expect.isTrue(s.contains("11:18"));
print(s);
Expect.isFalse(s.contains("-1:-1"), "A");
Expect.isTrue(s.contains("optimized_stacktrace_line_test.dart:11"), "B");
}
// Optimized.
@ -30,8 +31,9 @@ test1() {
Expect.fail("Unreachable");
} catch (e, stacktrace) {
String s = stacktrace.toString();
Expect.isFalse(s.contains("-1:-1"));
Expect.isTrue(s.contains("11:18"));
print(s);
Expect.isFalse(s.contains("-1:-1"), "C");
Expect.isTrue(s.contains("optimized_stacktrace_line_test.dart:11"), "D");
}
}
@ -56,9 +58,9 @@ test2() {
} catch (e, stacktrace) {
String s = stacktrace.toString();
print(s);
Expect.isTrue(s.contains("maximus"));
Expect.isTrue(s.contains("moritz"));
Expect.isFalse(s.contains("-1:-1"));
Expect.isTrue(s.contains("maximus"), "E");
Expect.isTrue(s.contains("moritz"), "F");
Expect.isFalse(s.contains("-1:-1"), "G");
}
try {
@ -66,9 +68,9 @@ test2() {
} catch (e, stacktrace) {
String s = stacktrace.toString();
print(s);
Expect.isTrue(s.contains("maximus"));
Expect.isTrue(s.contains("moritz"));
Expect.isFalse(s.contains("-1:-1"));
Expect.isTrue(s.contains("maximus"), "H");
Expect.isTrue(s.contains("moritz"), "I");
Expect.isFalse(s.contains("-1:-1"), "J");
}
}

View file

@ -149,7 +149,8 @@ dart/simd128float32_test: Skip # compilers not aware of Simd128
[ $compiler == dart2js ]
# The source positions do not match with dart2js.
dart/optimized_stacktrace_test: RuntimeError
dart/optimized_stacktrace_line_test: RuntimeError
dart/optimized_stacktrace_line_and_column_test: RuntimeError
# Methods can be missing in dart2js stack traces due to inlining. Also when
# minifying they can be renamed, which is issue 7953.
@ -169,7 +170,8 @@ cc/Int8ListLengthMaxElements: Skip # Issue 23536, uses 1 GB memory.
cc/FindCodeObject: SkipSlow # Takes more than 8 minutes. Issue 17440
[ $compiler == dart2analyzer ]
dart/optimized_stacktrace_test: StaticWarning
dart/optimized_stacktrace_line_test: StaticWarning
dart/optimized_stacktrace_line_and_column_test: StaticWarning
[ $compiler == dart2analyzer && $builder_tag == strong ]
*: Skip # Issue 28649
@ -256,14 +258,12 @@ cc/CreateMirrorSystem: SkipByDesign # Imports dart:mirrors
cc/CoreSnapshotSize: SkipByDesign # Imports dart:mirrors
cc/StandaloneSnapshotSize: SkipByDesign # Imports dart:mirrors
[ $runtime == dart_precompiled ]
# StackTraces in precompilation omit inlined frames.
dart/inline_stack_frame_test: Pass, RuntimeError
dart/optimized_stacktrace_test: Pass, RuntimeError
dart/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri
[ $compiler == app_jit ]
dart/optimized_stacktrace_line_and_column_test: RuntimeError,OK # app-jit lacks column information
[ $compiler == app_jit || $compiler == precompiler ]
dart/optimized_stacktrace_test: SkipByDesign # Requires line numbers
[ $runtime == dart_precompiled ]
dart/optimized_stacktrace_line_and_column_test: RuntimeError,OK # AOT lacks column information
dart/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri
[ $runtime == vm && $mode == product ]
cc/IsolateSetCheckedMode: Fail,OK # Expects exact type name.

View file

@ -1567,12 +1567,12 @@ class CodeSerializationCluster : public SerializationCluster {
s->Push(code->ptr()->exception_handlers_);
s->Push(code->ptr()->pc_descriptors_);
s->Push(code->ptr()->stackmaps_);
s->Push(code->ptr()->inlined_id_to_function_);
s->Push(code->ptr()->code_source_map_);
if (s->kind() == Snapshot::kAppJIT) {
s->Push(code->ptr()->deopt_info_array_);
s->Push(code->ptr()->static_calls_target_table_);
s->Push(code->ptr()->inlined_id_to_function_);
s->Push(code->ptr()->code_source_map_);
NOT_IN_PRODUCT(s->Push(code->ptr()->return_address_metadata_));
}
}
@ -1621,12 +1621,12 @@ class CodeSerializationCluster : public SerializationCluster {
s->WriteRef(code->ptr()->exception_handlers_);
s->WriteRef(code->ptr()->pc_descriptors_);
s->WriteRef(code->ptr()->stackmaps_);
s->WriteRef(code->ptr()->inlined_id_to_function_);
s->WriteRef(code->ptr()->code_source_map_);
if (s->kind() == Snapshot::kAppJIT) {
s->WriteRef(code->ptr()->deopt_info_array_);
s->WriteRef(code->ptr()->static_calls_target_table_);
s->WriteRef(code->ptr()->inlined_id_to_function_);
s->WriteRef(code->ptr()->code_source_map_);
NOT_IN_PRODUCT(s->WriteRef(code->ptr()->return_address_metadata_));
}
@ -1691,6 +1691,10 @@ class CodeDeserializationCluster : public DeserializationCluster {
code->ptr()->pc_descriptors_ =
reinterpret_cast<RawPcDescriptors*>(d->ReadRef());
code->ptr()->stackmaps_ = reinterpret_cast<RawArray*>(d->ReadRef());
code->ptr()->inlined_id_to_function_ =
reinterpret_cast<RawArray*>(d->ReadRef());
code->ptr()->code_source_map_ =
reinterpret_cast<RawCodeSourceMap*>(d->ReadRef());
#if !defined(DART_PRECOMPILED_RUNTIME)
if (d->kind() == Snapshot::kAppJIT) {
@ -1698,10 +1702,6 @@ class CodeDeserializationCluster : public DeserializationCluster {
reinterpret_cast<RawArray*>(d->ReadRef());
code->ptr()->static_calls_target_table_ =
reinterpret_cast<RawArray*>(d->ReadRef());
code->ptr()->inlined_id_to_function_ =
reinterpret_cast<RawArray*>(d->ReadRef());
code->ptr()->code_source_map_ =
reinterpret_cast<RawCodeSourceMap*>(d->ReadRef());
#if defined(PRODUCT)
code->ptr()->return_address_metadata_ = Object::null();
#else
@ -1710,8 +1710,6 @@ class CodeDeserializationCluster : public DeserializationCluster {
} else {
code->ptr()->deopt_info_array_ = Array::null();
code->ptr()->static_calls_target_table_ = Array::null();
code->ptr()->inlined_id_to_function_ = Array::null();
code->ptr()->code_source_map_ = CodeSourceMap::null();
code->ptr()->return_address_metadata_ = Object::null();
}

View file

@ -315,6 +315,24 @@ RawCodeSourceMap* CodeSourceMapBuilder::Finalize() {
}
void CodeSourceMapBuilder::WriteChangePosition(TokenPosition pos) {
stream_.Write<uint8_t>(kChangePosition);
if (FLAG_precompiled_mode) {
intptr_t line = -1;
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());
line = script.GetTokenLineUsingLineStarts(pos);
}
stream_.Write<int32_t>(static_cast<int32_t>(line));
} else {
stream_.Write<int32_t>(static_cast<int32_t>(pos.value()));
}
written_token_pos_stack_.Last() = pos;
}
void CodeSourceMapReader::GetInlinedFunctionsAt(
int32_t pc_offset,
GrowableArray<const Function*>* function_stack,

View file

@ -182,11 +182,7 @@ class CodeSourceMapBuilder : public ZoneAllocated {
void BufferChangePosition(TokenPosition pos) {
buffered_token_pos_stack_.Last() = pos;
}
void WriteChangePosition(TokenPosition pos) {
stream_.Write<uint8_t>(kChangePosition);
stream_.Write<int32_t>(static_cast<int32_t>(pos.value()));
written_token_pos_stack_.Last() = pos;
}
void WriteChangePosition(TokenPosition pos);
void BufferAdvancePC(int32_t distance) { buffered_pc_offset_ += distance; }
void WriteAdvancePC(int32_t distance) {
stream_.Write<uint8_t>(kAdvancePC);

View file

@ -1040,12 +1040,6 @@ void FlowGraphCompiler::FinalizeStaticCallTargetsTable(const Code& code) {
void FlowGraphCompiler::FinalizeCodeSourceMap(const Code& code) {
if (FLAG_precompiled_mode) {
// TODO(rmacnak): Include a filtered verion of this to produce stack traces
// with inlined frames.
return;
}
const Array& inlined_id_array =
Array::Handle(zone(), code_source_map_builder_->InliningIdToFunction());
INC_STAT(Thread::Current(), total_code_size,

View file

@ -9077,6 +9077,54 @@ void Script::SetLocationOffset(intptr_t line_offset,
}
// Specialized for AOT compilation, which does this lookup for every token
// position that could be part of a stack trace.
intptr_t Script::GetTokenLineUsingLineStarts(
TokenPosition target_token_pos) const {
Zone* zone = Thread::Current()->zone();
Array& line_starts_array = Array::Handle(zone, line_starts());
Smi& token_pos = Smi::Handle(zone);
if (line_starts_array.IsNull()) {
ASSERT(kind() != RawScript::kKernelTag);
GrowableObjectArray& line_starts_list =
GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
const TokenStream& tkns = TokenStream::Handle(zone, tokens());
TokenStream::Iterator tkit(zone, tkns, TokenPosition::kMinSource,
TokenStream::Iterator::kAllTokens);
intptr_t cur_line = line_offset() + 1;
token_pos = Smi::New(0);
line_starts_list.Add(token_pos);
while (tkit.CurrentTokenKind() != Token::kEOS) {
if (tkit.CurrentTokenKind() == Token::kNEWLINE) {
cur_line++;
token_pos = Smi::New(tkit.CurrentPosition().value() + 1);
line_starts_list.Add(token_pos);
}
tkit.Advance();
}
line_starts_array = Array::MakeArray(line_starts_list);
set_line_starts(line_starts_array);
}
ASSERT(line_starts_array.Length() > 0);
intptr_t offset = target_token_pos.value();
intptr_t min = 0;
intptr_t max = line_starts_array.Length() - 1;
// Binary search to find the line containing this offset.
while (min < max) {
int midpoint = (max - min + 1) / 2 + min;
token_pos ^= line_starts_array.At(midpoint);
if (token_pos.Value() > offset) {
max = midpoint - 1;
} else {
min = midpoint;
}
}
return min + 1; // Line numbers start at 1.
}
void Script::GetTokenLocation(TokenPosition token_pos,
intptr_t* line,
intptr_t* column,
@ -9085,7 +9133,7 @@ void Script::GetTokenLocation(TokenPosition token_pos,
Zone* zone = Thread::Current()->zone();
if (kind() == RawScript::kKernelTag) {
const Array& line_starts_array = Array::Handle(line_starts());
const Array& line_starts_array = Array::Handle(zone, line_starts());
if (line_starts_array.IsNull()) {
// Scripts in the AOT snapshot do not have a line starts array.
*line = -1;
@ -9099,13 +9147,13 @@ void Script::GetTokenLocation(TokenPosition token_pos,
}
ASSERT(line_starts_array.Length() > 0);
intptr_t offset = token_pos.value();
int min = 0;
int max = line_starts_array.Length() - 1;
intptr_t min = 0;
intptr_t max = line_starts_array.Length() - 1;
// Binary search to find the line containing this offset.
Smi& smi = Smi::Handle();
Smi& smi = Smi::Handle(zone);
while (min < max) {
int midpoint = (max - min + 1) / 2 + min;
intptr_t midpoint = (max - min + 1) / 2 + min;
smi ^= line_starts_array.At(midpoint);
if (smi.Value() > offset) {
@ -9114,7 +9162,7 @@ void Script::GetTokenLocation(TokenPosition token_pos,
min = midpoint;
}
}
*line = min + 1;
*line = min + 1; // Line numbers start at 1.
smi ^= line_starts_array.At(min);
if (column != NULL) {
*column = offset - smi.Value() + 1;
@ -14087,21 +14135,13 @@ intptr_t Code::GetPrologueOffset() const {
RawArray* Code::inlined_id_to_function() const {
#if defined(DART_PRECOMPILED_RUNTIME)
return Array::null();
#else
return raw_ptr()->inlined_id_to_function_;
#endif
}
void Code::set_inlined_id_to_function(const Array& value) const {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
ASSERT(value.IsOld());
StorePointer(&raw_ptr()->inlined_id_to_function_, value.raw());
#endif
}
@ -14466,8 +14506,8 @@ void Code::GetInlinedFunctionsAtInstruction(
GrowableArray<TokenPosition>* token_positions) const {
const CodeSourceMap& map = CodeSourceMap::Handle(code_source_map());
if (map.IsNull()) {
// Stub code.
return;
ASSERT(!IsFunctionCode());
return; // VM stub or allocation stub.
}
const Array& id_map = Array::Handle(inlined_id_to_function());
const Function& root = Function::Handle(function());
@ -22367,11 +22407,15 @@ static void PrintStackTraceFrame(Zone* zone,
zone, script.IsNull() ? String::New("Kernel") : script.url());
intptr_t line = -1;
intptr_t column = -1;
if (!script.IsNull() && token_pos.IsReal()) {
if (script.HasSource() || script.kind() == RawScript::kKernelTag) {
script.GetTokenLocation(token_pos, &line, &column);
} else {
script.GetTokenLocation(token_pos, &line, NULL);
if (FLAG_precompiled_mode) {
line = token_pos.value();
} else {
if (!script.IsNull() && token_pos.IsReal()) {
if (script.HasSource() || script.kind() == RawScript::kKernelTag) {
script.GetTokenLocation(token_pos, &line, &column);
} else {
script.GetTokenLocation(token_pos, &line, NULL);
}
}
}
if (column >= 0) {
@ -22420,8 +22464,7 @@ const char* StackTrace::ToCStringInternal(const StackTrace& stack_trace_in,
} else {
ASSERT(code.IsFunctionCode());
intptr_t pc_offset = Smi::Value(stack_trace.PcOffsetAtFrame(i));
if (code.is_optimized() && stack_trace.expand_inlined() &&
!FLAG_precompiled_mode) {
if (code.is_optimized() && stack_trace.expand_inlined()) {
code.GetInlinedFunctionsAtReturnAddress(pc_offset, &inlined_functions,
&inlined_token_positions);
ASSERT(inlined_functions.length() >= 1);

View file

@ -3576,6 +3576,7 @@ class Script : public Object {
void SetLocationOffset(intptr_t line_offset, intptr_t col_offset) const;
intptr_t GetTokenLineUsingLineStarts(TokenPosition token_pos) const;
void GetTokenLocation(TokenPosition token_pos,
intptr_t* line,
intptr_t* column,
@ -4408,6 +4409,14 @@ class CodeSourceMap : public Object {
return UnsafeMutableNonPointer(&raw_ptr()->data()[0]);
}
bool Equals(const CodeSourceMap& other) const {
if (Length() != other.Length()) {
return false;
}
NoSafepointScope no_safepoint;
return memcmp(raw_ptr(), other.raw_ptr(), InstanceSize(Length())) == 0;
}
void PrintToJSONObject(JSONObject* jsobj, bool ref) const;
private:
@ -4659,20 +4668,12 @@ class Code : public Object {
}
RawCodeSourceMap* code_source_map() const {
#if defined(DART_PRECOMPILED_RUNTIME)
return CodeSourceMap::null();
#else
return raw_ptr()->code_source_map_;
#endif
}
void set_code_source_map(const CodeSourceMap& code_source_map) const {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#else
ASSERT(code_source_map.IsOld());
StorePointer(&raw_ptr()->code_source_map_, code_source_map.raw());
#endif
}
// Used during reloading (see object_reload.cc). Calls Reset on all ICDatas

View file

@ -495,6 +495,7 @@ void Precompiler::DoCompileAll(
ShareMegamorphicBuckets();
DedupStackMaps();
DedupCodeSourceMaps();
DedupLists();
if (FLAG_dedup_instructions) {
@ -984,6 +985,13 @@ void Precompiler::AddCalleesOf(const Function& function) {
}
}
}
const Array& inlined_functions =
Array::Handle(Z, code.inlined_id_to_function());
for (intptr_t i = 0; i < inlined_functions.Length(); i++) {
target ^= inlined_functions.At(i);
AddTypesOf(target);
}
}
@ -2341,6 +2349,50 @@ void Precompiler::DedupStackMaps() {
}
void Precompiler::DedupCodeSourceMaps() {
class DedupCodeSourceMapsVisitor : public FunctionVisitor {
public:
explicit DedupCodeSourceMapsVisitor(Zone* zone)
: zone_(zone),
canonical_code_source_maps_(),
code_(Code::Handle(zone)),
code_source_map_(CodeSourceMap::Handle(zone)) {}
void Visit(const Function& function) {
if (!function.HasCode()) {
return;
}
code_ = function.CurrentCode();
code_source_map_ = code_.code_source_map();
ASSERT(!code_source_map_.IsNull());
code_source_map_ = DedupCodeSourceMap(code_source_map_);
code_.set_code_source_map(code_source_map_);
}
RawCodeSourceMap* DedupCodeSourceMap(const CodeSourceMap& code_source_map) {
const CodeSourceMap* canonical_code_source_map =
canonical_code_source_maps_.LookupValue(&code_source_map);
if (canonical_code_source_map == NULL) {
canonical_code_source_maps_.Insert(
&CodeSourceMap::ZoneHandle(zone_, code_source_map.raw()));
return code_source_map.raw();
} else {
return canonical_code_source_map->raw();
}
}
private:
Zone* zone_;
CodeSourceMapSet canonical_code_source_maps_;
Code& code_;
CodeSourceMap& code_source_map_;
};
DedupCodeSourceMapsVisitor visitor(Z);
ProgramVisitor::VisitFunctions(&visitor);
}
void Precompiler::DedupLists() {
class DedupListsVisitor : public FunctionVisitor {
public:
@ -2358,6 +2410,11 @@ void Precompiler::DedupLists() {
list_ = DedupList(list_);
code_.set_stackmaps(list_);
}
list_ = code_.inlined_id_to_function();
if (!list_.IsNull()) {
list_ = DedupList(list_);
code_.set_inlined_id_to_function(list_);
}
}
list_ = function.parameter_types();

View file

@ -87,6 +87,27 @@ class StackMapKeyValueTrait {
typedef DirectChainedHashMap<StackMapKeyValueTrait> StackMapSet;
class CodeSourceMapKeyValueTrait {
public:
// Typedefs needed for the DirectChainedHashMap template.
typedef const CodeSourceMap* Key;
typedef const CodeSourceMap* Value;
typedef const CodeSourceMap* Pair;
static Key KeyOf(Pair kv) { return kv; }
static Value ValueOf(Pair kv) { return kv; }
static inline intptr_t Hashcode(Key key) { return key->Length(); }
static inline bool IsKeyEqual(Pair pair, Key key) {
return pair->Equals(*key);
}
};
typedef DirectChainedHashMap<CodeSourceMapKeyValueTrait> CodeSourceMapSet;
class ArrayKeyValueTrait {
public:
// Typedefs needed for the DirectChainedHashMap template.
@ -461,6 +482,7 @@ class Precompiler : public ValueObject {
void SwitchICCalls();
void ShareMegamorphicBuckets();
void DedupStackMaps();
void DedupCodeSourceMaps();
void DedupLists();
void DedupInstructions();
void ResetPrecompilerState();

View file

@ -1139,12 +1139,12 @@ class RawCode : public RawObject {
RawExceptionHandlers* exception_handlers_;
RawPcDescriptors* pc_descriptors_;
RawArray* stackmaps_;
RawArray* inlined_id_to_function_;
RawCodeSourceMap* code_source_map_;
NOT_IN_PRECOMPILED(RawInstructions* active_instructions_);
NOT_IN_PRECOMPILED(RawArray* deopt_info_array_);
// (code-offset, function, code) triples.
NOT_IN_PRECOMPILED(RawArray* static_calls_target_table_);
NOT_IN_PRECOMPILED(RawArray* inlined_id_to_function_);
NOT_IN_PRECOMPILED(RawCodeSourceMap* code_source_map_);
// If return_address_metadata_ is a Smi, it is the offset to the prologue.
// Else, return_address_metadata_ is null.
NOT_IN_PRECOMPILED(RawObject* return_address_metadata_);

View file

@ -10,8 +10,7 @@ namespace dart {
// Count the number of frames that are on the stack.
intptr_t StackTraceUtils::CountFrames(Thread* thread,
int skip_frames,
const Function& async_function,
bool count_invisible_frames) {
const Function& async_function) {
Zone* zone = thread->zone();
intptr_t frame_count = 0;
StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
@ -27,9 +26,7 @@ intptr_t StackTraceUtils::CountFrames(Thread* thread,
} else {
code = frame->LookupDartCode();
function = code.function();
if (function.is_visible() || count_invisible_frames) {
frame_count++;
}
frame_count++;
if (!async_function_is_null &&
(async_function.raw() == function.parent_function())) {
return frame_count;
@ -49,8 +46,7 @@ intptr_t StackTraceUtils::CollectFrames(Thread* thread,
const Array& pc_offset_array,
intptr_t array_offset,
intptr_t count,
int skip_frames,
bool collect_invisible_frames) {
int skip_frames) {
Zone* zone = thread->zone();
StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
StackFrame* frame = frames.NextFrame();
@ -66,13 +62,11 @@ intptr_t StackTraceUtils::CollectFrames(Thread* thread,
} else {
code = frame->LookupDartCode();
function = code.function();
if (function.is_visible() || collect_invisible_frames) {
offset = Smi::New(frame->pc() - code.PayloadStart());
code_array.SetAt(array_offset, code);
pc_offset_array.SetAt(array_offset, offset);
array_offset++;
collected_frames_count++;
}
offset = Smi::New(frame->pc() - code.PayloadStart());
code_array.SetAt(array_offset, code);
pc_offset_array.SetAt(array_offset, offset);
array_offset++;
collected_frames_count++;
}
}
frame = frames.NextFrame();

View file

@ -19,24 +19,20 @@ class StackTraceUtils : public AllStatic {
/// Skips over the first |skip_frames|.
/// If |async_function| is not null, stops at the function that has
/// |async_function| as its parent.
static intptr_t CountFrames(
Thread* thread,
int skip_frames,
const Function& async_function,
bool count_invisible_frames = FLAG_show_invisible_frames);
static intptr_t CountFrames(Thread* thread,
int skip_frames,
const Function& async_function);
/// Collects |count| frames into |code_array| and |pc_offset_array|.
/// Writing begins at |array_offset|.
/// Skips over the first |skip_frames|.
/// Returns the number of frames collected.
static intptr_t CollectFrames(
Thread* thread,
const Array& code_array,
const Array& pc_offset_array,
intptr_t array_offset,
intptr_t count,
int skip_frames,
bool collect_invisible_frames = FLAG_show_invisible_frames);
static intptr_t CollectFrames(Thread* thread,
const Array& code_array,
const Array& pc_offset_array,
intptr_t array_offset,
intptr_t count,
int skip_frames);
/// If |thread| has no async_stack_trace, does nothing.
/// Populates |async_function| with the top function of the async stack

View file

@ -196,10 +196,6 @@ collection_removes_test: Crash # Issue 25911
apply3_test: SkipByDesign # Imports dart:mirrors
[ $compiler == precompiler ]
# Stacktraces in precompilation omit inlined frames.
stacktrace_current_test: Pass, RuntimeError
error_stack_trace1_test: Pass, RuntimeError
regexp/stack-overflow_test: RuntimeError, OK # Smaller limit with irregex interpreter
big_integer_huge_mul_vm_test: Pass, Timeout # --no_intrinsify
big_integer_parsed_mul_div_vm_test: Pass, Timeout # --no_intrinsify

View file

@ -15,6 +15,7 @@ void func3() {
func2();
} on Object catch(e, s) {
var fullTrace = s.toString();
print(fullTrace);
Expect.isTrue(fullTrace.contains("func1"));
Expect.isTrue(fullTrace.contains("func2"));
Expect.isTrue(fullTrace.contains("func3"));

View file

@ -15,6 +15,7 @@ void func3() {
func2();
} on Object catch(e, s) {
var fullTrace = s.toString();
print(fullTrace);
Expect.isTrue(fullTrace.contains("func1"));
Expect.isTrue(fullTrace.contains("func2"));
Expect.isTrue(fullTrace.contains("func3"));
@ -36,6 +37,7 @@ int func5() {
func4();
} on Object catch(e, s) {
var fullTrace = s.toString();
print(fullTrace);
Expect.isTrue(fullTrace.contains("func1"));
Expect.isTrue(fullTrace.contains("func2"));
Expect.isTrue(fullTrace.contains("func3"));

View file

@ -15,6 +15,7 @@ void func3() {
func2();
} on Object catch(e, s) {
var fullTrace = s.toString();
print(fullTrace);
Expect.isTrue(fullTrace.contains("func1"));
Expect.isTrue(fullTrace.contains("func2"));
Expect.isTrue(fullTrace.contains("func3"));
@ -35,6 +36,7 @@ int func5() {
func4();
} on Object catch(e, s) {
var fullTrace = s.toString();
print(fullTrace);
Expect.isFalse(fullTrace.contains("func1"));
Expect.isFalse(fullTrace.contains("func2"));
Expect.isTrue(fullTrace.contains("func3"));

View file

@ -153,18 +153,6 @@ vm/regress_24517_test: Pass, Fail # Issue 24517.
[ $compiler == precompiler && $runtime == dart_precompiled ]
vm/regress_27671_test: Skip # Unsupported
[ $runtime == dart_precompiled ]
# Stacktraces in precompilation omit inlined frames.
full_stacktrace1_test: Pass, RuntimeError
full_stacktrace2_test: Pass, RuntimeError
full_stacktrace3_test: Pass, RuntimeError
stack_trace_test: Pass, RuntimeError
stacktrace_rethrow_error_test: Pass, RuntimeError
stacktrace_rethrow_nonerror_test: Pass, RuntimeError
stacktrace_test: Pass, RuntimeError
vm/regress_28325_test: RuntimeError # Missing source position in AOT.
[ $runtime == dart_precompiled || $mode == product ]
# Imports dart:mirrors
const_evaluation_test: SkipByDesign

View file

@ -249,8 +249,6 @@ no_allow_absolute_addresses_test: SkipByDesign # Not supported.
link_natives_lazily_test: SkipByDesign # Not supported.
[ $compiler == precompiler ]
# Stacktraces in precompilation omit inlined frames.
assert_test: Pass, RuntimeError
map_insert_remove_oom_test: Skip # Heap limit too low. Increasing iteration count to make a higher limit a meaningful test makes it too slow for simarm[64] bots.
io/web_socket_test: Pass, RuntimeError # Issue 24674