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();
341 ZoneGrowableArray<const ICData*>* ic_data_array =
342 new (zone()) ZoneGrowableArray<const ICData*>();
343 function.RestoreICDataMap(ic_data_array,
false );
344 const PcDescriptors& descriptors =
348 const int kCoverageNone = 0;
349 const int kCoverageMiss = 1;
350 const int kCoverageHit = 2;
352 intptr_t func_length =
function.SourceSize() + 1;
353 GrowableArray<char>
coverage(func_length);
355 for (
int i = 0; i < func_length; i++) {
365 auto update_coverage = [&](TokenPosition token_pos,
bool was_executed) {
366 if (!(token_pos.IsReal() && token_pos.IsWithin(begin_pos, end_pos))) {
370 const intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
372 coverage[token_offset] = kCoverageHit;
374 if (coverage[token_offset] == kCoverageNone) {
375 coverage[token_offset] = kCoverageMiss;
380 if (!report_branch_coverage) {
381 PcDescriptors::Iterator iter(descriptors,
382 UntaggedPcDescriptors::kIcCall |
383 UntaggedPcDescriptors::kUnoptStaticCall);
384 while (iter.MoveNext()) {
386 ASSERT(iter.DeoptId() < ic_data_array->length());
387 const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
388 if (ic_data !=
nullptr) {
389 const TokenPosition& token_pos = iter.TokenPos();
390 update_coverage(token_pos, ic_data->AggregateCount() > 0);
397 if (!coverage_array.IsNull()) {
398 for (intptr_t i = 0; i < coverage_array.Length(); i += 2) {
399 bool is_branch_coverage;
402 if (is_branch_coverage == report_branch_coverage) {
403 const bool was_executed =
405 update_coverage(token_pos, was_executed);
410 JSONObject cov(jsobj, report_branch_coverage ?
"branchCoverage" :
"coverage");
412 JSONArray hits(&cov,
"hits");
413 TokenPosition
pos = begin_pos;
414 for (
int i = 0; i < func_length; i++) {
415 if (coverage[i] == kCoverageHit) {
417 hits.AddValue(GetTokenPosOrLine(script,
pos));
423 JSONArray misses(&cov,
"misses");
424 TokenPosition
pos = begin_pos;
425 for (
int i = 0; i < func_length; i++) {
426 if (coverage[i] == kCoverageMiss) {
428 misses.AddValue(GetTokenPosOrLine(script,
pos));
435void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj,
436 const Function& func,
438 const TokenPosition& begin_pos = func.token_pos();
439 const TokenPosition& end_pos = func.end_token_pos();
440 intptr_t func_length = func.SourceSize() + 1;
442 BitVector possible(zone(), func_length);
447 UntaggedPcDescriptors::kUnoptStaticCall |
448 UntaggedPcDescriptors::kRuntimeCall);
450 const PcDescriptors& descriptors =
455 while (iter.MoveNext()) {
456 const TokenPosition& token_pos = iter.TokenPos();
457 if (!token_pos.IsWithin(begin_pos, end_pos)) {
461 intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
462 possible.Add(token_offset);
465 JSONArray bpts(jsobj,
"possibleBreakpoints");
466 TokenPosition
pos = begin_pos;
467 for (
int i = 0; i < func_length; i++) {
468 if (possible.Contains(i)) {
470 bpts.AddValue(GetTokenPosOrLine(script,
pos));
476void SourceReport::PrintProfileData(JSONObject* jsobj,
477 ProfileFunction* profile_function) {
478 ASSERT(profile_function !=
nullptr);
479 ASSERT(profile_function->NumSourcePositions() > 0);
482 JSONObject
profile(jsobj,
"profile");
485 JSONObject profileData(&profile,
"metadata");
486 profileData.AddProperty(
"sampleCount", profile_.
sample_count());
491 JSONArray positions(&profile,
"positions");
492 for (intptr_t i = 0; i < profile_function->NumSourcePositions(); i++) {
493 const ProfileFunctionSourcePosition& position =
494 profile_function->GetSourcePosition(i);
495 if (position.token_pos().IsReal()) {
497 positions.AddValue(position.token_pos().Pos());
500 positions.AddValue(position.token_pos().ToCString());
507 JSONArray exclusiveTicks(&profile,
"exclusiveTicks");
508 for (intptr_t i = 0; i < profile_function->NumSourcePositions(); i++) {
509 const ProfileFunctionSourcePosition& position =
510 profile_function->GetSourcePosition(i);
511 exclusiveTicks.AddValue(position.exclusive_ticks());
516 JSONArray inclusiveTicks(&profile,
"inclusiveTicks");
517 for (intptr_t i = 0; i < profile_function->NumSourcePositions(); i++) {
518 const ProfileFunctionSourcePosition& position =
519 profile_function->GetSourcePosition(i);
520 inclusiveTicks.AddValue(position.inclusive_ticks());
526void SourceReport::PrintScriptTable(JSONArray*
scripts) {
527 for (intptr_t i = 0; i < script_table_entries_.
length(); i++) {
528 const Script*
script = script_table_entries_[i]->script;
533void SourceReport::VisitFunction(JSONArray* jsarr,
534 const Function& func,
535 CompileMode compile_mode) {
536 if (ShouldSkipFunction(func)) {
541 const TokenPosition begin_pos = func.token_pos();
542 const TokenPosition end_pos = func.end_token_pos();
544 const intptr_t script_index = GetScriptIndex(script);
545 if (script_index < 0) {
556 JSONObject range(jsarr);
557 range.AddProperty(
"scriptIndex", script_index);
558 range.AddProperty(
"startPos", begin_pos);
559 range.AddProperty(
"endPos", end_pos);
560 range.AddProperty(
"compiled",
false);
561 range.AddProperty(
"error", err);
564 code = func.unoptimized_code();
567 JSONObject range(jsarr);
568 range.AddProperty(
"scriptIndex", script_index);
569 range.AddProperty(
"startPos", begin_pos);
570 range.AddProperty(
"endPos", end_pos);
571 range.AddProperty(
"compiled",
false);
577 JSONObject range(jsarr);
578 range.AddProperty(
"scriptIndex", script_index);
579 range.AddProperty(
"startPos", begin_pos);
580 range.AddProperty(
"endPos", end_pos);
581 range.AddProperty(
"compiled",
true);
584 PrintCallSitesData(&range, func, code);
587 PrintCoverageData(&range, func, code,
false);
590 PrintCoverageData(&range, func, code,
true);
593 PrintPossibleBreakpointsData(&range, func, code);
596 ProfileFunction* profile_function = profile_.
FindFunction(func);
597 if ((profile_function !=
nullptr) &&
598 (profile_function->NumSourcePositions() > 0)) {
599 PrintProfileData(&range, profile_function);
604void SourceReport::VisitField(JSONArray* jsarr,
606 CompileMode compile_mode) {
607 if (ShouldSkipField(field) || !field.HasInitializerFunction())
return;
609 VisitFunction(jsarr, func, compile_mode);
612void SourceReport::VisitLibrary(JSONArray* jsarr,
const Library& lib) {
621 if (compile_mode ==
kForceCompile && IsLibraryAlreadyCompiled(lib)) {
624 while (it.HasNext()) {
625 cls = it.GetNextClass();
626 if (!cls.is_finalized()) {
632 const intptr_t script_index = GetScriptIndex(script);
633 if (script_index < 0) {
636 JSONObject range(jsarr);
637 range.AddProperty(
"scriptIndex", script_index);
638 range.AddProperty(
"startPos", cls.token_pos());
639 range.AddProperty(
"endPos", cls.end_token_pos());
640 range.AddProperty(
"compiled",
false);
641 range.AddProperty(
"error", err);
644 ASSERT(cls.is_finalized());
646 cls.EnsureDeclarationLoaded();
649 const intptr_t script_index = GetScriptIndex(script);
650 if (script_index < 0) {
653 JSONObject range(jsarr);
654 range.AddProperty(
"scriptIndex", script_index);
655 range.AddProperty(
"startPos", cls.token_pos());
656 range.AddProperty(
"endPos", cls.end_token_pos());
657 range.AddProperty(
"compiled",
false);
662 functions = cls.current_functions();
663 for (
int i = 0; i < functions.Length(); i++) {
664 func ^= functions.At(i);
666 if (func.kind() == UntaggedFunction::kImplicitStaticGetter) {
667 field ^= func.accessor_field();
668 if (field.is_const() && field.is_static()) {
672 VisitFunction(jsarr, func, compile_mode);
675 fields = cls.fields();
676 for (intptr_t i = 0; i < fields.Length(); i++) {
677 field ^= fields.At(i);
678 VisitField(jsarr, field, compile_mode);
683void SourceReport::VisitClosures(JSONArray* jsarr) {
685 VisitFunction(jsarr, func, compile_mode_);
702 zone(), thread()->isolate_group()->object_store()->libraries());
706 for (intptr_t i = 0; i < libs.Length(); i++) {
708 if (script.IsNull() || ScriptIsLoadedByLibrary(script, lib)) {
709 VisitLibrary(&ranges, lib);
714 VisitClosures(&ranges);
723 CollectAllScripts(&local_script_table, &local_script_table_entries);
724 CollectConstConstructorCoverageFromScripts(&local_script_table_entries,
726 CleanupCollectedScripts(&local_script_table, &local_script_table_entries);
735void SourceReport::CollectAllScripts(
738 ScriptTableEntry wrapper;
740 zone(), thread()->isolate_group()->object_store()->libraries());
743 for (
int i = 0; i < libs.Length(); i++) {
746 for (intptr_t j = 0; j <
scripts.Length(); j++) {
751 ScriptTableEntry* pair = local_script_table->
LookupValue(&wrapper);
752 if (pair !=
nullptr) {
757 ScriptTableEntry* tmp =
new ScriptTableEntry();
760 tmp->script = wrapper.script;
761 local_script_table_entries->
Add(tmp);
762 local_script_table->
Insert(tmp);
767void SourceReport::CleanupCollectedScripts(
768 DirectChainedHashMap<ScriptTableTrait>* local_script_table,
769 GrowableArray<ScriptTableEntry*>* local_script_table_entries) {
770 for (intptr_t i = 0; i < local_script_table_entries->length(); i++) {
771 delete local_script_table_entries->operator[](i);
772 local_script_table_entries->operator[](i) =
nullptr;
774 local_script_table_entries->Clear();
775 local_script_table->Clear();
778void SourceReport::CollectConstConstructorCoverageFromScripts(
779 GrowableArray<ScriptTableEntry*>* local_script_table_entries,
782 for (intptr_t i = 0; i < local_script_table_entries->length(); i++) {
783 const Script*
script = local_script_table_entries->At(i)->script;
789 const Array& constructors =
791 intptr_t constructors_count = constructors.Length();
794 for (intptr_t i = 0; i < constructors_count; i++) {
795 constructor ^= constructors.At(i);
797 if (ShouldSkipFunction(constructor)) {
800 scriptRef ^= constructor.script();
801 const intptr_t script_index = GetScriptIndex(scriptRef);
802 if (script_index < 0) {
805 code ^= constructor.unoptimized_code();
806 const TokenPosition begin_pos = constructor.token_pos();
807 const TokenPosition end_pos = constructor.end_token_pos();
808 JSONObject range(ranges);
809 range.AddProperty(
"scriptIndex", script_index);
810 range.AddProperty(
"compiled",
812 range.AddProperty(
"startPos", begin_pos);
813 range.AddProperty(
"endPos", end_pos);
815 JSONObject cov(&range,
"coverage");
817 JSONArray hits(&cov,
"hits");
818 hits.AddValue(GetTokenPosOrLine(scriptRef, begin_pos));
821 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