44
55#include < cstddef>
66#include < cstdint>
7- #include < map>
87#include < set>
98#include < sstream>
9+ #include < unordered_map>
1010#include < vector>
1111
1212#include " include/analyze_snapshot_api.h"
@@ -71,6 +71,7 @@ class SnapshotAnalyzer {
7171 const std::vector<const Field*>& fields);
7272 void DumpFunction (const Function& function);
7373 void DumpCode (const Code& code);
74+ void DumpCode (uword start_pc, uword end_pc, const char * name);
7475 void DumpField (const Field& field);
7576 void DumpString (const String& string);
7677 void DumpInstance (const Object& object);
@@ -85,6 +86,7 @@ class SnapshotAnalyzer {
8586 const Dart_SnapshotAnalyzerInformation& info_;
8687 std::vector<std::vector<const Field*>> class_fields_;
8788 std::vector<std::vector<const Field*>> top_level_class_fields_;
89+ std::unordered_map<uword, const char *> stub_names_;
8890
8991 JSONWriter js_;
9092 Thread* thread_;
@@ -250,7 +252,7 @@ void SnapshotAnalyzer::DumpClassInstanceSlots(
250252
251253void SnapshotAnalyzer::DumpFunction (const Function& function) {
252254 js_.PrintProperty (" type" , " Function" );
253- js_.PrintProperty (" name" , function.ToCString ());
255+ js_.PrintProperty (" name" , function.QualifiedScrubbedNameCString ());
254256
255257 js_.PrintProperty (" signature" ,
256258 String::Handle (function.InternalSignature ()).ToCString ());
@@ -262,28 +264,108 @@ void SnapshotAnalyzer::DumpFunction(const Function& function) {
262264 }
263265}
264266
267+ namespace {
268+ // Try to identify stubs which were effectively copied into the isolate
269+ // instructions section by comparing payloads.
270+ const char * TryIdentifyIsolateSpecificStubCopy (ObjectStore* object_store,
271+ const Code& code) {
272+ #define MATCH (member, name ) \
273+ if (object_store->member () != Code::null () && \
274+ StubCode::name ().ptr () == object_store->member () && \
275+ StubCode::name ().Size () == code.Size () && \
276+ memcmp (reinterpret_cast <void *>(code.PayloadStart ()), \
277+ reinterpret_cast <void *>(StubCode::name ().PayloadStart ()), \
278+ code.Size ()) == 0 ) { \
279+ return " _iso_stub_" #name " Stub" ; \
280+ }
281+ OBJECT_STORE_STUB_CODE_LIST (MATCH)
282+ #undef MATCH
283+
284+ return nullptr ;
285+ }
286+ } // namespace
287+
265288void SnapshotAnalyzer::DumpCode (const Code& code) {
266289 js_.PrintProperty (" type" , " Code" );
267290 const auto instruction_base =
268291 reinterpret_cast <uint64_t >(info_.vm_isolate_instructions );
269292
293+ if (code.IsUnknownDartCode ()) {
294+ js_.PrintProperty64 (" offset" , 0 );
295+ js_.PrintProperty64 (" size" , 0 );
296+ js_.PrintProperty (" name" , " UnknownDartCode" );
297+ js_.PrintProperty (" section" , " _kDartVmSnapshotInstructions" );
298+ return ;
299+ }
300+
270301 // On different architectures the type of the underlying
271302 // dart::uword can result in an unsigned long long vs unsigned long
272303 // mismatch.
273304 const auto code_addr = static_cast <uint64_t >(code.PayloadStart ());
274- // Invoking code.PayloadStart() for _kDartVmSnapshotInstructions
275- // when the tree has been shaken always returns 0
276- if (code_addr == 0 ) {
277- js_.PrintProperty64 (" offset" , 0 );
278- js_.PrintProperty64 (" size" , 0 );
279- js_.PrintProperty (" section" , " _kDartVmSnapshotInstructions" );
305+ js_.PrintProperty64 (" offset" , code_addr - instruction_base);
306+ js_.PrintProperty64 (" size" , static_cast <uint64_t >(code.Size ()));
307+ js_.PrintProperty (" section" , " _kDartIsolateSnapshotInstructions" );
308+
309+ if (code.owner () != Object::null ()) {
310+ const auto & owner = Object::Handle (code.owner ());
311+ js_.PrintProperty (" owner" , GetObjectId (owner.ptr ()));
312+ if (owner.IsClass ()) {
313+ js_.PrintfProperty (" name" , " new %s" ,
314+ Class::Cast (owner).ScrubbedNameCString ());
315+ js_.PrintPropertyBool (" is_stub" , true );
316+ } else if (owner.IsAbstractType ()) {
317+ js_.PrintfProperty (" name" , " as %s" ,
318+ AbstractType::Cast (owner).ScrubbedNameCString ());
319+ js_.PrintPropertyBool (" is_stub" , true );
320+ } else if (owner.IsFunction ()) {
321+ js_.PrintProperty (" name" , Function::Cast (owner).UserVisibleNameCString ());
322+ } else if (owner.IsSmi ()) {
323+ // This is a class id of the class which owned the function.
324+ // See Precompiler::DropFunctions.
325+ const auto cid = Smi::Cast (owner).Value ();
326+ auto class_table = thread_->isolate_group ()->class_table ();
327+ if (class_table->IsValidIndex (cid) &&
328+ class_table->At (cid) != Class::null ()) {
329+ const auto & cls = Class::Handle (class_table->At (cid));
330+ js_.PrintProperty (" owner" , GetObjectId (cls.ptr ()));
331+ js_.PrintfProperty (" name" , " unknown function of %s" ,
332+ Class::Cast (cls).ScrubbedNameCString ());
333+ } else {
334+ js_.PrintfProperty (" name" , " unknown function of class #%" Pd " " , cid);
335+ }
336+ } else {
337+ // Expected to handle all possibilities.
338+ UNREACHABLE ();
339+ }
280340 } else {
281- js_.PrintProperty64 (" offset" , code_addr - instruction_base);
282- js_.PrintProperty64 (" size" , static_cast <uint64_t >(code.Size ()));
283- js_.PrintProperty (" section" , " _kDartIsolateSnapshotInstructions" );
341+ js_.PrintPropertyBool (" is_stub" , true );
342+
343+ const auto it = stub_names_.find (code.EntryPoint ());
344+ if (it != stub_names_.end ()) {
345+ js_.PrintProperty (" name" , it->second );
346+ } else if (auto stub_name = TryIdentifyIsolateSpecificStubCopy (
347+ thread_->isolate_group ()->object_store (), code)) {
348+ js_.PrintProperty (" name" , stub_name);
349+ } else {
350+ UNREACHABLE ();
351+ }
284352 }
285353}
286354
355+ void SnapshotAnalyzer::DumpCode (uword start_pc,
356+ uword end_pc,
357+ const char * name) {
358+ js_.PrintProperty (" type" , " Code" );
359+ const auto instruction_base =
360+ reinterpret_cast <uint64_t >(info_.vm_isolate_instructions );
361+
362+ js_.PrintProperty64 (" offset" ,
363+ static_cast <uint64_t >(start_pc) - instruction_base);
364+ js_.PrintProperty64 (" size" , static_cast <uint64_t >(end_pc - start_pc));
365+ js_.PrintProperty (" name" , name);
366+ js_.PrintProperty (" section" , " _kDartIsolateSnapshotInstructions" );
367+ }
368+
287369void SnapshotAnalyzer::DumpField (const Field& field) {
288370 const auto & name = String::Handle (field.name ());
289371 const auto & type = AbstractType::Handle (field.type ());
@@ -383,6 +465,12 @@ void SnapshotAnalyzer::DumpObjectPool(const ObjectPool& pool) {
383465}
384466
385467void SnapshotAnalyzer::DumpInterestingObjects () {
468+ // Collect stubs into stub_names to enable quick name lookup
469+ StubCode::ForEachStub ([&](const char * name, uword entry_point) {
470+ stub_names_[entry_point] = name;
471+ return true ;
472+ });
473+
386474 Zone* zone = thread_->zone ();
387475 auto class_table = thread_->isolate_group ()->class_table ();
388476 class_table->NumCids ();
@@ -426,6 +514,29 @@ void SnapshotAnalyzer::DumpInterestingObjects() {
426514 object = class_table->At (cid);
427515 handle_object (object.ptr ());
428516 }
517+
518+ // - All instructions tables
519+ const auto & instruction_tables = GrowableObjectArray::Handle (
520+ thread_->isolate_group ()->object_store ()->instructions_tables ());
521+ for (intptr_t i = 0 ; i < instruction_tables.Length (); i++) {
522+ object = instruction_tables.At (i);
523+ object = InstructionsTable::Cast (object).code_objects ();
524+ handle_object (object.ptr ());
525+ }
526+
527+ // - All VM stubs
528+ for (intptr_t i = 0 ; i < StubCode::NumEntries (); i++) {
529+ if (!StubCode::EntryAt (i).IsNull ()) {
530+ handle_object (StubCode::EntryAt (i).ptr ());
531+ }
532+ }
533+
534+ // - Object store.
535+ //
536+ // This will include a bunch of stuff we don't care about
537+ // but it will also capture things like isolate specific stubs and
538+ // canonicalized types which themselves include references to stubs.
539+ thread_->isolate_group ()->object_store ()->VisitObjectPointers (&visitor);
429540 }
430541
431542 // Sometimes we have [Field] objects for fields but they are not available
@@ -490,9 +601,28 @@ void SnapshotAnalyzer::DumpInterestingObjects() {
490601 } else if (object->IsInstance ()) {
491602 DumpInstance (*object);
492603 }
493-
494604 js_.CloseObject ();
495605 }
606+
607+ // Finally dump pseudo-Code objects for all entries in the instructions
608+ // tables without code objects.
609+ uint64_t pseudo_code_id = kStartIndex + discovered_objects.size ();
610+ const auto & instruction_tables = GrowableObjectArray::Handle (
611+ thread_->isolate_group ()->object_store ()->instructions_tables ());
612+ auto & instructions_table = InstructionsTable::Handle ();
613+ for (intptr_t i = 0 ; i < instruction_tables.Length (); i++) {
614+ instructions_table ^= instruction_tables.At (i);
615+ for (intptr_t index = 0 ; index < instructions_table.FirstEntryWithCode ();
616+ index++) {
617+ js_.OpenObject ();
618+ js_.PrintProperty64 (" id" , pseudo_code_id);
619+ DumpCode (instructions_table.EntryPointAt (index),
620+ instructions_table.EntryPointAt (index + 1 ), " Unknown Code" );
621+ js_.CloseObject ();
622+ pseudo_code_id++;
623+ }
624+ }
625+
496626 js_.CloseArray ();
497627}
498628
0 commit comments