4
4
5
5
#include < cstddef>
6
6
#include < cstdint>
7
- #include < map>
8
7
#include < set>
9
8
#include < sstream>
9
+ #include < unordered_map>
10
10
#include < vector>
11
11
12
12
#include " include/analyze_snapshot_api.h"
@@ -71,6 +71,7 @@ class SnapshotAnalyzer {
71
71
const std::vector<const Field*>& fields);
72
72
void DumpFunction (const Function& function);
73
73
void DumpCode (const Code& code);
74
+ void DumpCode (uword start_pc, uword end_pc, const char * name);
74
75
void DumpField (const Field& field);
75
76
void DumpString (const String& string);
76
77
void DumpInstance (const Object& object);
@@ -85,6 +86,7 @@ class SnapshotAnalyzer {
85
86
const Dart_SnapshotAnalyzerInformation& info_;
86
87
std::vector<std::vector<const Field*>> class_fields_;
87
88
std::vector<std::vector<const Field*>> top_level_class_fields_;
89
+ std::unordered_map<uword, const char *> stub_names_;
88
90
89
91
JSONWriter js_;
90
92
Thread* thread_;
@@ -250,7 +252,7 @@ void SnapshotAnalyzer::DumpClassInstanceSlots(
250
252
251
253
void SnapshotAnalyzer::DumpFunction (const Function& function) {
252
254
js_.PrintProperty (" type" , " Function" );
253
- js_.PrintProperty (" name" , function.ToCString ());
255
+ js_.PrintProperty (" name" , function.QualifiedScrubbedNameCString ());
254
256
255
257
js_.PrintProperty (" signature" ,
256
258
String::Handle (function.InternalSignature ()).ToCString ());
@@ -262,28 +264,108 @@ void SnapshotAnalyzer::DumpFunction(const Function& function) {
262
264
}
263
265
}
264
266
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
+
265
288
void SnapshotAnalyzer::DumpCode (const Code& code) {
266
289
js_.PrintProperty (" type" , " Code" );
267
290
const auto instruction_base =
268
291
reinterpret_cast <uint64_t >(info_.vm_isolate_instructions );
269
292
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
+
270
301
// On different architectures the type of the underlying
271
302
// dart::uword can result in an unsigned long long vs unsigned long
272
303
// mismatch.
273
304
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
+ }
280
340
} 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
+ }
284
352
}
285
353
}
286
354
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
+
287
369
void SnapshotAnalyzer::DumpField (const Field& field) {
288
370
const auto & name = String::Handle (field.name ());
289
371
const auto & type = AbstractType::Handle (field.type ());
@@ -383,6 +465,12 @@ void SnapshotAnalyzer::DumpObjectPool(const ObjectPool& pool) {
383
465
}
384
466
385
467
void 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
+
386
474
Zone* zone = thread_->zone ();
387
475
auto class_table = thread_->isolate_group ()->class_table ();
388
476
class_table->NumCids ();
@@ -426,6 +514,29 @@ void SnapshotAnalyzer::DumpInterestingObjects() {
426
514
object = class_table->At (cid);
427
515
handle_object (object.ptr ());
428
516
}
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);
429
540
}
430
541
431
542
// Sometimes we have [Field] objects for fields but they are not available
@@ -490,9 +601,28 @@ void SnapshotAnalyzer::DumpInterestingObjects() {
490
601
} else if (object->IsInstance ()) {
491
602
DumpInstance (*object);
492
603
}
493
-
494
604
js_.CloseObject ();
495
605
}
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
+
496
626
js_.CloseArray ();
497
627
}
498
628
0 commit comments