5#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
29 : report_set_(report_set),
30 compile_mode_(compile_mode),
31 report_lines_(report_lines),
33 libraries_already_compiled_(nullptr),
38 next_script_index_(0) {}
45 : report_set_(report_set),
46 compile_mode_(compile_mode),
47 report_lines_(report_lines),
48 library_filters_(library_filters),
49 libraries_already_compiled_(libraries_already_compiled),
54 next_script_index_(0) {}
60void SourceReport::ClearScriptTable() {
64 ScriptTableTrait::Pair* pair;
65 while ((pair = iter.Next()) !=
nullptr) {
66 delete ScriptTableTrait::ValueOf(*pair);
68 script_table_.
Clear();
70 for (intptr_t
i = 0;
i < script_table_entries_.
length();
i++) {
71 script_table_entries_[
i] =
nullptr;
73 script_table_entries_.
Clear();
75 next_script_index_ = 0;
78void SourceReport::Init(Thread* thread,
80 TokenPosition start_pos,
81 TokenPosition end_pos) {
91 profile_.
Build(thread, thread->isolate(), &samplesForIsolate,
96bool SourceReport::IsReportRequested(ReportKind report_kind) {
97 return (report_set_ & report_kind) != 0;
100bool SourceReport::ShouldSkipFunction(
const Function& func) {
103 if (!func.token_pos().IsReal() || !func.end_token_pos().IsReal()) {
108 if (script_ !=
nullptr && !script_->
IsNull()) {
109 if (func.script() != script_->
ptr()) {
113 if ((func.end_token_pos() < start_pos_) || (func.token_pos() > end_pos_)) {
120 if (func.ForceOptimize())
return true;
122 switch (func.kind()) {
123 case UntaggedFunction::kRegularFunction:
124 case UntaggedFunction::kClosureFunction:
125 case UntaggedFunction::kImplicitClosureFunction:
126 case UntaggedFunction::kImplicitStaticGetter:
127 case UntaggedFunction::kFieldInitializer:
128 case UntaggedFunction::kGetterFunction:
129 case UntaggedFunction::kSetterFunction:
130 case UntaggedFunction::kConstructor:
135 if (func.is_abstract() || func.IsImplicitConstructor() ||
136 func.is_synthetic() || func.is_redirecting_factory()) {
139 if (func.IsNonImplicitClosureFunction() &&
151 if (func.kind() == UntaggedFunction::kConstructor &&
152 func.NumParameters() == func.NumImplicitParameters() &&
156 GrowableObjectArray& subclasses =
158 if (cls.is_abstract() && !cls.HasInstanceFields() &&
159 (subclasses.IsNull() || subclasses.Length() == 0)) {
163 intptr_t numNonStaticFunctions = 0;
164 for (intptr_t
i = 0;
i < clsFuncs.Length(); ++
i) {
165 otherFunc ^= clsFuncs.At(
i);
166 if (!otherFunc.IsStaticFunction()) {
167 ++numNonStaticFunctions;
170 if (numNonStaticFunctions == 1) {
177 if (func.IsGenerativeConstructor()) {
179 if (cls.is_enum_class()) {
187bool SourceReport::ShouldSkipField(
const Field& field) {
188 if (!field.token_pos().IsReal() || !field.end_token_pos().IsReal()) {
193 if (script_ !=
nullptr && !script_->
IsNull()) {
194 if (field.Script() != script_->
ptr()) {
198 if ((field.end_token_pos() < start_pos_) ||
199 (field.token_pos() > end_pos_)) {
207bool SourceReport::IsLibraryAlreadyCompiled(
const Library& lib) {
208 if (libraries_already_compiled_ ==
nullptr)
return false;
210 if (url ==
nullptr)
return false;
211 return libraries_already_compiled_->
Lookup(url) !=
nullptr;
214bool SourceReport::ShouldFiltersIncludeUrl(
const String& url) {
216 const intptr_t num_filters = library_filters_.
Length();
217 for (intptr_t
i = 0;
i < num_filters; ++
i) {
218 filter ^= library_filters_.
At(
i);
219 if (url.StartsWith(filter)) {
226bool SourceReport::ShouldFiltersIncludeScript(
const Script&
script) {
227 if (library_filters_.
IsNull())
return true;
229 if (ShouldFiltersIncludeUrl(url))
return true;
232 return ShouldFiltersIncludeUrl(url);
235intptr_t SourceReport::GetScriptIndex(
const Script&
script) {
236 ScriptTableEntry wrapper;
240 ScriptTableEntry* pair = script_table_.
LookupValue(&wrapper);
241 if (pair !=
nullptr) {
244 ScriptTableEntry* tmp =
new ScriptTableEntry();
246 tmp->script = wrapper.script;
247 if (ShouldFiltersIncludeScript(
script)) {
248 tmp->index = next_script_index_++;
249 script_table_entries_.
Add(tmp);
253 script_table_.
Insert(tmp);
254 ASSERT(script_table_entries_.
length() == next_script_index_);
262void SourceReport::VerifyScriptTable() {
263 for (intptr_t
i = 0;
i < script_table_entries_.
length();
i++) {
264 const String* url = script_table_entries_[
i]->key;
265 const Script*
script = script_table_entries_[
i]->script;
266 intptr_t index = script_table_entries_[
i]->index;
269 ASSERT(url2.Equals(*url));
270 ScriptTableEntry wrapper;
273 ScriptTableEntry* pair = script_table_.
LookupValue(&wrapper);
279bool SourceReport::ScriptIsLoadedByLibrary(
const Script&
script,
280 const Library& lib) {
282 for (intptr_t j = 0; j <
scripts.Length(); j++) {
290void SourceReport::PrintCallSitesData(JSONObject* jsobj,
294 const TokenPosition& begin_pos =
function.token_pos();
295 const TokenPosition& end_pos =
function.end_token_pos();
296 ZoneGrowableArray<const ICData*>* ic_data_array =
297 new (zone()) ZoneGrowableArray<const ICData*>();
298 function.RestoreICDataMap(ic_data_array,
false );
299 const PcDescriptors& descriptors =
302 JSONArray sites(jsobj,
"callSites");
304 PcDescriptors::Iterator iter(
306 UntaggedPcDescriptors::kIcCall | UntaggedPcDescriptors::kUnoptStaticCall);
307 while (iter.MoveNext()) {
309 ASSERT(iter.DeoptId() < ic_data_array->length());
310 const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
311 if (ic_data !=
nullptr) {
312 const TokenPosition& token_pos = iter.TokenPos();
313 if (!token_pos.IsWithin(begin_pos, end_pos)) {
317 ic_data->PrintToJSONArray(sites, token_pos);
322intptr_t SourceReport::GetTokenPosOrLine(
const Script&
script,
323 const TokenPosition& token_pos) {
324 if (!report_lines_) {
325 return token_pos.Pos();
328 const bool found =
script.GetTokenLocation(token_pos, &
line);
333void SourceReport::PrintCoverageData(JSONObject* jsobj,
336 bool report_branch_coverage) {
338 const TokenPosition& begin_pos =
function.token_pos();
339 const TokenPosition& end_pos =
function.end_token_pos();
343 const int kCoverageNone = 0;
344 const int kCoverageMiss = 1;
345 const int kCoverageHit = 2;
347 intptr_t func_length =
function.SourceSize() + 1;
348 GrowableArray<char>
coverage(func_length);
350 for (
int i = 0;
i < func_length;
i++) {
360 auto update_coverage = [&](TokenPosition token_pos,
bool was_executed) {
361 if (!(token_pos.IsReal() && token_pos.IsWithin(begin_pos, end_pos))) {
365 const intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
367 coverage[token_offset] = kCoverageHit;
369 if (
coverage[token_offset] == kCoverageNone) {
370 coverage[token_offset] = kCoverageMiss;
377 if (!coverage_array.IsNull()) {
378 for (intptr_t
i = 0;
i < coverage_array.Length();
i += 2) {
379 bool is_branch_coverage;
382 if (is_branch_coverage == report_branch_coverage) {
383 const bool was_executed =
385 update_coverage(token_pos, was_executed);
390 JSONObject cov(jsobj, report_branch_coverage ?
"branchCoverage" :
"coverage");
392 JSONArray hits(&cov,
"hits");
393 TokenPosition
pos = begin_pos;
394 for (
int i = 0;
i < func_length;
i++) {
397 hits.AddValue(GetTokenPosOrLine(
script,
pos));
403 JSONArray misses(&cov,
"misses");
404 TokenPosition
pos = begin_pos;
405 for (
int i = 0;
i < func_length;
i++) {
408 misses.AddValue(GetTokenPosOrLine(
script,
pos));
415void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj,
416 const Function& func,
418 const TokenPosition& begin_pos = func.token_pos();
419 const TokenPosition& end_pos = func.end_token_pos();
420 intptr_t func_length = func.SourceSize() + 1;
422 BitVector possible(zone(), func_length);
427 UntaggedPcDescriptors::kUnoptStaticCall |
428 UntaggedPcDescriptors::kRuntimeCall);
430 const PcDescriptors& descriptors =
435 while (iter.MoveNext()) {
436 const TokenPosition& token_pos = iter.TokenPos();
437 if (!token_pos.IsWithin(begin_pos, end_pos)) {
441 intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
442 possible.Add(token_offset);
445 JSONArray bpts(jsobj,
"possibleBreakpoints");
446 TokenPosition
pos = begin_pos;
447 for (
int i = 0;
i < func_length;
i++) {
448 if (possible.Contains(
i)) {
450 bpts.AddValue(GetTokenPosOrLine(
script,
pos));
456void SourceReport::PrintProfileData(JSONObject* jsobj,
457 ProfileFunction* profile_function) {
458 ASSERT(profile_function !=
nullptr);
459 ASSERT(profile_function->NumSourcePositions() > 0);
462 JSONObject
profile(jsobj,
"profile");
465 JSONObject profileData(&
profile,
"metadata");
466 profileData.AddProperty(
"sampleCount", profile_.
sample_count());
471 JSONArray positions(&
profile,
"positions");
472 for (intptr_t
i = 0;
i < profile_function->NumSourcePositions();
i++) {
473 const ProfileFunctionSourcePosition& position =
474 profile_function->GetSourcePosition(
i);
475 if (position.token_pos().IsReal()) {
477 positions.AddValue(position.token_pos().Pos());
480 positions.AddValue(position.token_pos().ToCString());
487 JSONArray exclusiveTicks(&
profile,
"exclusiveTicks");
488 for (intptr_t
i = 0;
i < profile_function->NumSourcePositions();
i++) {
489 const ProfileFunctionSourcePosition& position =
490 profile_function->GetSourcePosition(
i);
491 exclusiveTicks.AddValue(position.exclusive_ticks());
496 JSONArray inclusiveTicks(&
profile,
"inclusiveTicks");
497 for (intptr_t
i = 0;
i < profile_function->NumSourcePositions();
i++) {
498 const ProfileFunctionSourcePosition& position =
499 profile_function->GetSourcePosition(
i);
500 inclusiveTicks.AddValue(position.inclusive_ticks());
506void SourceReport::PrintScriptTable(JSONArray*
scripts) {
507 for (intptr_t
i = 0;
i < script_table_entries_.
length();
i++) {
508 const Script*
script = script_table_entries_[
i]->script;
513void SourceReport::VisitFunction(JSONArray* jsarr,
514 const Function& func,
515 CompileMode compile_mode) {
516 if (ShouldSkipFunction(func)) {
521 const TokenPosition begin_pos = func.token_pos();
522 const TokenPosition end_pos = func.end_token_pos();
524 const intptr_t script_index = GetScriptIndex(
script);
525 if (script_index < 0) {
536 JSONObject range(jsarr);
537 range.AddProperty(
"scriptIndex", script_index);
538 range.AddProperty(
"startPos", begin_pos);
539 range.AddProperty(
"endPos", end_pos);
540 range.AddProperty(
"compiled",
false);
541 range.AddProperty(
"error", err);
544 code = func.unoptimized_code();
547 JSONObject range(jsarr);
548 range.AddProperty(
"scriptIndex", script_index);
549 range.AddProperty(
"startPos", begin_pos);
550 range.AddProperty(
"endPos", end_pos);
551 range.AddProperty(
"compiled",
false);
557 JSONObject range(jsarr);
558 range.AddProperty(
"scriptIndex", script_index);
559 range.AddProperty(
"startPos", begin_pos);
560 range.AddProperty(
"endPos", end_pos);
561 range.AddProperty(
"compiled",
true);
564 PrintCallSitesData(&range, func,
code);
567 PrintCoverageData(&range, func,
code,
false);
570 PrintCoverageData(&range, func,
code,
true);
573 PrintPossibleBreakpointsData(&range, func,
code);
576 ProfileFunction* profile_function = profile_.
FindFunction(func);
577 if ((profile_function !=
nullptr) &&
578 (profile_function->NumSourcePositions() > 0)) {
579 PrintProfileData(&range, profile_function);
584void SourceReport::VisitField(JSONArray* jsarr,
586 CompileMode compile_mode) {
587 if (ShouldSkipField(field) || !field.HasInitializerFunction())
return;
589 VisitFunction(jsarr, func, compile_mode);
592void SourceReport::VisitLibrary(JSONArray* jsarr,
const Library& lib) {
601 if (compile_mode ==
kForceCompile && IsLibraryAlreadyCompiled(lib)) {
604 while (it.HasNext()) {
605 cls = it.GetNextClass();
606 if (!cls.is_finalized()) {
612 const intptr_t script_index = GetScriptIndex(
script);
613 if (script_index < 0) {
616 JSONObject range(jsarr);
617 range.AddProperty(
"scriptIndex", script_index);
618 range.AddProperty(
"startPos", cls.token_pos());
619 range.AddProperty(
"endPos", cls.end_token_pos());
620 range.AddProperty(
"compiled",
false);
621 range.AddProperty(
"error", err);
624 ASSERT(cls.is_finalized());
626 cls.EnsureDeclarationLoaded();
629 const intptr_t script_index = GetScriptIndex(
script);
630 if (script_index < 0) {
633 JSONObject range(jsarr);
634 range.AddProperty(
"scriptIndex", script_index);
635 range.AddProperty(
"startPos", cls.token_pos());
636 range.AddProperty(
"endPos", cls.end_token_pos());
637 range.AddProperty(
"compiled",
false);
642 functions = cls.current_functions();
643 for (
int i = 0;
i < functions.Length();
i++) {
644 func ^= functions.At(
i);
646 if (func.kind() == UntaggedFunction::kImplicitStaticGetter) {
647 field ^= func.accessor_field();
648 if (field.is_const() && field.is_static()) {
652 VisitFunction(jsarr, func, compile_mode);
655 fields = cls.fields();
656 for (intptr_t
i = 0;
i < fields.Length();
i++) {
657 field ^= fields.At(
i);
658 VisitField(jsarr, field, compile_mode);
663void SourceReport::VisitClosures(JSONArray* jsarr) {
665 VisitFunction(jsarr, func, compile_mode_);
682 zone(), thread()->isolate_group()->object_store()->libraries());
686 for (intptr_t
i = 0;
i <
libs.Length();
i++) {
688 if (
script.IsNull() || ScriptIsLoadedByLibrary(
script, lib)) {
689 VisitLibrary(&ranges, lib);
694 VisitClosures(&ranges);
703 CollectAllScripts(&local_script_table, &local_script_table_entries);
704 CollectConstConstructorCoverageFromScripts(&local_script_table_entries,
706 CleanupCollectedScripts(&local_script_table, &local_script_table_entries);
715void SourceReport::CollectAllScripts(
718 ScriptTableEntry wrapper;
720 zone(), thread()->isolate_group()->object_store()->libraries());
723 for (
int i = 0;
i <
libs.Length();
i++) {
726 for (intptr_t j = 0; j <
scripts.Length(); j++) {
731 ScriptTableEntry* pair = local_script_table->
LookupValue(&wrapper);
732 if (pair !=
nullptr) {
737 ScriptTableEntry* tmp =
new ScriptTableEntry();
740 tmp->script = wrapper.script;
741 local_script_table_entries->
Add(tmp);
742 local_script_table->
Insert(tmp);
747void SourceReport::CleanupCollectedScripts(
748 DirectChainedHashMap<ScriptTableTrait>* local_script_table,
749 GrowableArray<ScriptTableEntry*>* local_script_table_entries) {
750 for (intptr_t
i = 0;
i < local_script_table_entries->length();
i++) {
751 delete local_script_table_entries->operator[](
i);
752 local_script_table_entries->operator[](
i) =
nullptr;
754 local_script_table_entries->Clear();
755 local_script_table->Clear();
758void SourceReport::CollectConstConstructorCoverageFromScripts(
759 GrowableArray<ScriptTableEntry*>* local_script_table_entries,
762 for (intptr_t
i = 0;
i < local_script_table_entries->length();
i++) {
763 const Script*
script = local_script_table_entries->At(
i)->script;
769 const Array& constructors =
771 intptr_t constructors_count = constructors.Length();
774 for (intptr_t
i = 0;
i < constructors_count;
i++) {
775 constructor ^= constructors.At(
i);
777 if (ShouldSkipFunction(constructor)) {
780 scriptRef ^= constructor.script();
781 const intptr_t script_index = GetScriptIndex(scriptRef);
782 if (script_index < 0) {
785 code ^= constructor.unoptimized_code();
786 const TokenPosition begin_pos = constructor.token_pos();
787 const TokenPosition end_pos = constructor.end_token_pos();
788 JSONObject range(ranges);
789 range.AddProperty(
"scriptIndex", script_index);
790 range.AddProperty(
"compiled",
792 range.AddProperty(
"startPos", begin_pos);
793 range.AddProperty(
"endPos", end_pos);
795 JSONObject cov(&range,
"coverage");
797 JSONArray hits(&cov,
"hits");
798 hits.AddValue(GetTokenPosOrLine(scriptRef, begin_pos));
801 JSONArray misses(&cov,
"misses");
KeyValueTrait::Value LookupValue(typename KeyValueTrait::Key key) const
void Insert(typename KeyValueTrait::Pair kv)
KeyValueTrait::Pair * Lookup(typename KeyValueTrait::Key key) const
Iterator GetIterator() const
static void ForAllClosureFunctions(std::function< bool(const Function &)> callback)
static ErrorPtr EnsureUnoptimizedCode(Thread *thread, const Function &function)
ObjectPtr At(intptr_t index) const
SafepointRwLock * program_lock()
Dart_Port main_port() const
void AddProperty(const char *name, bool b) const
ArrayPtr LoadedScripts() const
virtual const char * ToCString() const
static ObjectPtr RawCast(ObjectPtr obj)
intptr_t sample_count() const
void Build(Thread *thread, Isolate *isolate, SampleFilter *filter, SampleBlockBuffer *sample_block_buffer)
ProfileFunction * FindFunction(const Function &function)
static SampleBlockBuffer * sample_block_buffer()
void PrintJSON(JSONStream *js, const Script &script, TokenPosition start_pos=TokenPosition::kMinSource, TokenPosition end_pos=TokenPosition::kMaxSource)
static const char * kPossibleBreakpointsStr
static const char * kCallSitesStr
static const char * kCoverageStr
static const char * kBranchCoverageStr
SourceReport(intptr_t report_set, CompileMode compile=kNoCompile, bool report_lines=false)
static const char * kProfileStr
static Thread * Current()
Isolate * isolate() const
IsolateGroup * isolate_group() const
static const TokenPosition & Min(const TokenPosition &a, const TokenPosition &b)
static TokenPosition DecodeCoveragePosition(intptr_t encoded_position, bool *is_branch_coverage)
static const TokenPosition & Max(const TokenPosition &a, const TokenPosition &b)
static const TokenPosition kMaxSource
static const TokenPosition kMinSource
Dart_NativeFunction function
#define HANDLESCOPE(thread)
const uint8_t kSafepointKind
scripts
Printing Glyph Map Stats.