Skip to content

Commit ba68d04

Browse files
sstricklcommit-bot@chromium.org
authored andcommitted
[vm] Treat the dispatch table as a root in the snapshot.
Additional changes: * Only serialize a dispatch table in precompiled snapshots. * Add information in v8 snapshot profiles for the dispatch table. * Fix a typo in a field name. * Print the number of Instructions objects (or payloads, for precompiled bare instructions mode) in the fake cluster for the data section. * Fix v8 snapshots profiles so objects in memory mapped segments and only those are prefixed with "(RO) ". * Add names for Instructions objects in v8 snapshot profiles when we can use the assembly namer. * Add command line flag for old #define'd false flag. Change-Id: I1e3be59c7a6312efd76afca560ba465cc17cb22b Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm_x64-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-precomp-mac-release-simarm64-try,vm-kernel-precomp-win-release-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/138089 Commit-Queue: Teagan Strickland <[email protected]> Reviewed-by: Ryan Macnak <[email protected]> Reviewed-by: Aske Simon Christensen <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent a5bf30c commit ba68d04

File tree

6 files changed

+377
-204
lines changed

6 files changed

+377
-204
lines changed

runtime/vm/clustered_snapshot.cc

Lines changed: 148 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,15 @@
2727
#include "vm/timeline.h"
2828
#include "vm/version.h"
2929

30-
#define LOG_SECTION_BOUNDARIES false
31-
3230
namespace dart {
3331

32+
#if !defined(DART_PRECOMPILED_RUNTIME)
33+
DEFINE_FLAG(bool,
34+
print_cluster_information,
35+
false,
36+
"Print information about clusters written to snapshot");
37+
#endif
38+
3439
#if defined(DART_PRECOMPILER)
3540
DEFINE_FLAG(charp,
3641
write_v8_snapshot_profile_to,
@@ -101,27 +106,34 @@ void Deserializer::InitializeHeader(RawObject* raw,
101106

102107
#if !defined(DART_PRECOMPILED_RUNTIME)
103108
void SerializationCluster::WriteAndMeasureAlloc(Serializer* serializer) {
104-
if (LOG_SECTION_BOUNDARIES) {
105-
OS::PrintErr("Data + %" Px ": Alloc %s\n", serializer->bytes_written(),
106-
name_);
107-
}
108-
intptr_t start_size = serializer->bytes_written() + serializer->GetDataSize();
109+
intptr_t start_size = serializer->bytes_written();
110+
intptr_t start_data = serializer->GetDataSize();
109111
intptr_t start_objects = serializer->next_ref_index();
110112
WriteAlloc(serializer);
111-
intptr_t stop_size = serializer->bytes_written() + serializer->GetDataSize();
113+
intptr_t stop_size = serializer->bytes_written();
114+
intptr_t stop_data = serializer->GetDataSize();
112115
intptr_t stop_objects = serializer->next_ref_index();
113-
size_ += (stop_size - start_size);
116+
if (FLAG_print_cluster_information) {
117+
const int hex_size = kWordSize * 2;
118+
OS::PrintErr("Snapshot 0x%0*.*" Px " (%" Pd "), ", hex_size, hex_size,
119+
start_size, stop_size - start_size);
120+
OS::PrintErr("Data 0x%0*.*" Px " (%" Pd "): ", hex_size, hex_size,
121+
start_data, stop_data - start_data);
122+
OS::PrintErr("Alloc %s (%" Pd ")\n", name(), stop_objects - start_objects);
123+
}
124+
size_ += (stop_size - start_size) + (stop_data - start_data);
114125
num_objects_ += (stop_objects - start_objects);
115126
}
116127

117128
void SerializationCluster::WriteAndMeasureFill(Serializer* serializer) {
118-
if (LOG_SECTION_BOUNDARIES) {
119-
OS::PrintErr("Data + %" Px ": Fill %s\n", serializer->bytes_written(),
120-
name_);
121-
}
122129
intptr_t start = serializer->bytes_written();
123130
WriteFill(serializer);
124131
intptr_t stop = serializer->bytes_written();
132+
if (FLAG_print_cluster_information) {
133+
const int hex_size = kWordSize * 2;
134+
OS::PrintErr("Snapshot 0x%0*.*" Px " (%" Pd "): Fill %s\n", hex_size,
135+
hex_size, start, stop - start, name());
136+
}
125137
size_ += (stop - start);
126138
}
127139

@@ -2008,8 +2020,11 @@ class PcDescriptorsDeserializationCluster : public DeserializationCluster {
20082020
// PcDescriptor, CompressedStackMaps, OneByteString, TwoByteString
20092021
class RODataSerializationCluster : public SerializationCluster {
20102022
public:
2011-
RODataSerializationCluster(const char* name, intptr_t cid)
2012-
: SerializationCluster(name), cid_(cid) {}
2023+
RODataSerializationCluster(Zone* zone, const char* type, intptr_t cid)
2024+
: SerializationCluster(ImageWriter::TagObjectTypeAsReadOnly(zone, type)),
2025+
cid_(cid),
2026+
objects_(),
2027+
type_(type) {}
20132028
~RODataSerializationCluster() {}
20142029

20152030
void Trace(Serializer* s, RawObject* object) {
@@ -2037,9 +2052,9 @@ class RODataSerializationCluster : public SerializationCluster {
20372052
RawObject* object = objects_[i];
20382053
s->AssignRef(object);
20392054
if (cid_ == kOneByteStringCid || cid_ == kTwoByteStringCid) {
2040-
s->TraceStartWritingObject(name(), object, String::RawCast(object));
2055+
s->TraceStartWritingObject(type_, object, String::RawCast(object));
20412056
} else {
2042-
s->TraceStartWritingObject(name(), object, nullptr);
2057+
s->TraceStartWritingObject(type_, object, nullptr);
20432058
}
20442059
uint32_t offset = s->GetDataOffset(object);
20452060
s->TraceDataOffset(offset);
@@ -2060,6 +2075,7 @@ class RODataSerializationCluster : public SerializationCluster {
20602075
private:
20612076
const intptr_t cid_;
20622077
GrowableArray<RawObject*> objects_;
2078+
const char* const type_;
20632079
};
20642080
#endif // !DART_PRECOMPILED_RUNTIME
20652081

@@ -4565,6 +4581,23 @@ void Serializer::TraceEndWritingObject() {
45654581
}
45664582
}
45674583

4584+
const char* Serializer::ReadOnlyObjectType(intptr_t cid) {
4585+
switch (cid) {
4586+
case kPcDescriptorsCid:
4587+
return "PcDescriptors";
4588+
case kCodeSourceMapCid:
4589+
return "CodeSourceMap";
4590+
case kCompressedStackMapsCid:
4591+
return "CompressedStackMaps";
4592+
case kOneByteStringCid:
4593+
return "OneByteString";
4594+
case kTwoByteStringCid:
4595+
return "TwoByteString";
4596+
default:
4597+
return nullptr;
4598+
}
4599+
}
4600+
45684601
SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
45694602
#if defined(DART_PRECOMPILED_RUNTIME)
45704603
UNREACHABLE();
@@ -4586,18 +4619,8 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
45864619
}
45874620

45884621
if (Snapshot::IncludesCode(kind_)) {
4589-
switch (cid) {
4590-
case kPcDescriptorsCid:
4591-
return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
4592-
case kCodeSourceMapCid:
4593-
return new (Z) RODataSerializationCluster("(RO)CodeSourceMap", cid);
4594-
case kCompressedStackMapsCid:
4595-
return new (Z)
4596-
RODataSerializationCluster("(RO)CompressedStackMaps", cid);
4597-
case kOneByteStringCid:
4598-
return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
4599-
case kTwoByteStringCid:
4600-
return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
4622+
if (auto const type = ReadOnlyObjectType(cid)) {
4623+
return new (Z) RODataSerializationCluster(Z, type, cid);
46014624
}
46024625
}
46034626

@@ -4792,13 +4815,6 @@ intptr_t Serializer::GetDataSize() const {
47924815
return image_writer_->data_size();
47934816
}
47944817

4795-
intptr_t Serializer::GetTextSize() const {
4796-
if (image_writer_ == NULL) {
4797-
return 0;
4798-
}
4799-
return image_writer_->text_size();
4800-
}
4801-
48024818
void Serializer::Push(RawObject* object) {
48034819
if (!object->IsHeapObject()) {
48044820
RawSmi* smi = Smi::RawCast(object);
@@ -5030,19 +5046,36 @@ void Serializer::PrintSnapshotSizes() {
50305046
clusters_by_size.Add(cluster);
50315047
}
50325048
}
5033-
if (GetTextSize() != 0) {
5049+
intptr_t text_size = 0;
5050+
if (image_writer_ != nullptr) {
5051+
auto const text_object_count = image_writer_->GetTextObjectCount();
5052+
text_size = image_writer_->text_size();
5053+
intptr_t trampoline_count, trampoline_size;
5054+
image_writer_->GetTrampolineInfo(&trampoline_count, &trampoline_size);
5055+
auto const instructions_count = text_object_count - trampoline_count;
5056+
auto const instructions_size = text_size - trampoline_size;
50345057
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
5035-
"(RO)Instructions", 0, GetTextSize()));
5058+
ImageWriter::TagObjectTypeAsReadOnly(zone_, "Instructions"),
5059+
instructions_count, instructions_size));
5060+
if (trampoline_size > 0) {
5061+
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
5062+
ImageWriter::TagObjectTypeAsReadOnly(zone_, "Trampoline"),
5063+
trampoline_count, trampoline_size));
5064+
}
50365065
}
5037-
// An null dispatch table will serialize to a single byte.
5038-
if (dispatch_table_size_ > 1) {
5066+
// The dispatch_table_size_ will be 0 if the snapshot did not include a
5067+
// dispatch table (i.e., the VM snapshot). For a precompiled isolate
5068+
// snapshot, we always serialize at least _one_ byte for the DispatchTable.
5069+
if (dispatch_table_size_ > 0) {
5070+
auto const dispatch_table = isolate()->dispatch_table();
5071+
auto const entry_count =
5072+
dispatch_table != nullptr ? dispatch_table->length() : 0;
50395073
clusters_by_size.Add(new (zone_) FakeSerializationCluster(
5040-
"(RO)DispatchTable", isolate()->dispatch_table()->length(),
5041-
dispatch_table_size_));
5074+
"DispatchTable", entry_count, dispatch_table_size_));
50425075
}
50435076
clusters_by_size.Sort(CompareClusters);
50445077
double total_size =
5045-
static_cast<double>(bytes_written() + GetDataSize() + GetTextSize());
5078+
static_cast<double>(bytes_written() + GetDataSize() + text_size);
50465079
double cumulative_fraction = 0.0;
50475080
for (intptr_t i = 0; i < clusters_by_size.length(); i++) {
50485081
SerializationCluster* cluster = clusters_by_size[i];
@@ -5178,6 +5211,36 @@ static const char* kObjectStoreFieldNames[] = {
51785211

51795212
void Serializer::WriteIsolateSnapshot(intptr_t num_base_objects,
51805213
ObjectStore* object_store) {
5214+
#if defined(DART_PRECOMPILER)
5215+
// We should treat the dispatch table as a root object and trace the
5216+
// Code objects it references via entry points. Otherwise, an non-empty
5217+
// entry could be invalid on deserialization if the corresponding Code
5218+
// object was not reachable from the existing snapshot roots.
5219+
//
5220+
// Since the dispatch table only stores entry points, we have to find the
5221+
// Code objects before entering the NoSafepointScope, since looking up a
5222+
// Code object from the entry point cannot be done during one.
5223+
auto const dispatch_table = isolate()->dispatch_table();
5224+
// Check that we only have dispatch tables in precompiled mode, so we can
5225+
// elide them from the snapshot when not creating a precompiled snapshot.
5226+
ASSERT(dispatch_table == nullptr || kind() == Snapshot::kFullAOT);
5227+
// We collect the Code objects for each entry, storing null if there is none.
5228+
auto const dispatch_table_length =
5229+
dispatch_table != nullptr ? dispatch_table->length() : 0;
5230+
GrowableHandlePtrArray<const Code> dispatch_table_roots(
5231+
zone_, dispatch_table_length);
5232+
if (dispatch_table != nullptr) {
5233+
auto& code = Code::Handle(zone_);
5234+
auto const entries = dispatch_table->array();
5235+
for (intptr_t i = 0; i < dispatch_table_length; i++) {
5236+
auto const entry = entries[i];
5237+
code = entry != 0 ? Code::LookupCode(entry) : Code::null();
5238+
ASSERT(entry == 0 || !code.IsNull());
5239+
dispatch_table_roots.Add(code);
5240+
}
5241+
}
5242+
#endif
5243+
51815244
NoSafepointScope no_safepoint;
51825245

51835246
if (num_base_objects == 0) {
@@ -5199,19 +5262,53 @@ void Serializer::WriteIsolateSnapshot(intptr_t num_base_objects,
51995262
Push(*p);
52005263
}
52015264

5265+
#if defined(DART_PRECOMPILER)
5266+
// Push the Code objects collected from the dispatch table.
5267+
for (intptr_t i = 0; i < dispatch_table_length; i++) {
5268+
const auto& code = dispatch_table_roots.At(i);
5269+
if (code.IsNull()) continue;
5270+
Push(code.raw());
5271+
}
5272+
#endif
5273+
52025274
Serialize();
52035275

52045276
// Write roots.
52055277
for (RawObject** p = from; p <= to; p++) {
52065278
WriteRootRef(*p, kObjectStoreFieldNames[p - from]);
52075279
}
52085280

5209-
// Serialize dispatch table.
5210-
GrowableArray<RawCode*>* code_objects =
5211-
static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid])
5212-
->discovered_objects();
5213-
dispatch_table_size_ = DispatchTable::Serialize(
5214-
this, isolate()->dispatch_table(), *code_objects);
5281+
#if defined(DART_PRECOMPILER)
5282+
// Serialize dispatch table for precompiled snapshots only.
5283+
if (kind() == Snapshot::kFullAOT) {
5284+
GrowableArray<RawCode*>* code_objects =
5285+
static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid])
5286+
->discovered_objects();
5287+
dispatch_table_size_ = DispatchTable::Serialize(
5288+
this, isolate()->dispatch_table(), *code_objects);
5289+
ASSERT(dispatch_table_length == 0 || dispatch_table_size_ > 1);
5290+
5291+
if (profile_writer_ != nullptr) {
5292+
// Grab an unused ref index for a unique object id for the dispatch table.
5293+
const auto dispatch_table_id = next_ref_index_++;
5294+
const V8SnapshotProfileWriter::ObjectId dispatch_table_snapshot_id(
5295+
V8SnapshotProfileWriter::kSnapshot, dispatch_table_id);
5296+
profile_writer_->AddRoot(dispatch_table_snapshot_id, "dispatch_table");
5297+
profile_writer_->SetObjectTypeAndName(dispatch_table_snapshot_id,
5298+
"DispatchTable", nullptr);
5299+
profile_writer_->AttributeBytesTo(dispatch_table_snapshot_id,
5300+
dispatch_table_size_);
5301+
for (intptr_t i = 0; i < dispatch_table_length; i++) {
5302+
const auto& code = dispatch_table_roots.At(i);
5303+
const V8SnapshotProfileWriter::ObjectId code_id(
5304+
V8SnapshotProfileWriter::kSnapshot, WriteRefId(code.raw()));
5305+
profile_writer_->AttributeReferenceTo(
5306+
dispatch_table_snapshot_id,
5307+
{code_id, V8SnapshotProfileWriter::Reference::kElement, i});
5308+
}
5309+
}
5310+
}
5311+
#endif
52155312

52165313
#if defined(DEBUG)
52175314
Write<int32_t>(kSectionMarker);
@@ -5776,11 +5873,13 @@ void Deserializer::ReadIsolateSnapshot(ObjectStore* object_store) {
57765873
*p = ReadRef();
57775874
}
57785875

5876+
#if defined(DART_PRECOMPILED_RUNTIME)
57795877
// Deserialize dispatch table
57805878
const Array& code_array =
57815879
Array::Handle(zone_, object_store->code_order_table());
57825880
thread()->isolate()->set_dispatch_table(
57835881
DispatchTable::Deserialize(this, code_array));
5882+
#endif
57845883

57855884
#if defined(DEBUG)
57865885
int32_t section_marker = Read<int32_t>();

runtime/vm/clustered_snapshot.h

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -246,36 +246,6 @@ class Serializer : public ThreadStackResource {
246246
}
247247
void Align(intptr_t alignment) { stream_.Align(alignment); }
248248

249-
private:
250-
intptr_t WriteRefId(RawObject* object) {
251-
intptr_t id = 0;
252-
if (!object->IsHeapObject()) {
253-
RawSmi* smi = Smi::RawCast(object);
254-
id = smi_ids_.Lookup(smi)->id_;
255-
if (id == 0) {
256-
FATAL("Missing ref");
257-
}
258-
} else {
259-
// The object id weak table holds image offsets for Instructions instead
260-
// of ref indices.
261-
ASSERT(!object->IsInstructions());
262-
id = heap_->GetObjectId(object);
263-
if (id == 0) {
264-
if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
265-
return WriteRefId(Object::null());
266-
}
267-
#if !defined(DART_PRECOMPILED_RUNTIME)
268-
if (object->IsBytecode() && !Snapshot::IncludesBytecode(kind_)) {
269-
return WriteRefId(Object::null());
270-
}
271-
#endif // !DART_PRECOMPILED_RUNTIME
272-
FATAL("Missing ref");
273-
}
274-
}
275-
return id;
276-
}
277-
278-
public:
279249
void WriteRootRef(RawObject* object, const char* name = nullptr) {
280250
intptr_t id = WriteRefId(object);
281251
WriteUnsigned(id);
@@ -382,14 +352,43 @@ class Serializer : public ThreadStackResource {
382352
uint32_t GetDataOffset(RawObject* object) const;
383353
void TraceDataOffset(uint32_t offset);
384354
intptr_t GetDataSize() const;
385-
intptr_t GetTextSize() const;
386355

387356
Snapshot::Kind kind() const { return kind_; }
388357
intptr_t next_ref_index() const { return next_ref_index_; }
389358

390359
void DumpCombinedCodeStatistics();
391360

392361
private:
362+
static const char* ReadOnlyObjectType(intptr_t cid);
363+
364+
intptr_t WriteRefId(RawObject* object) {
365+
intptr_t id = 0;
366+
if (!object->IsHeapObject()) {
367+
RawSmi* smi = Smi::RawCast(object);
368+
id = smi_ids_.Lookup(smi)->id_;
369+
if (id == 0) {
370+
FATAL("Missing ref");
371+
}
372+
} else {
373+
// The object id weak table holds image offsets for Instructions instead
374+
// of ref indices.
375+
ASSERT(!object->IsInstructions());
376+
id = heap_->GetObjectId(object);
377+
if (id == 0) {
378+
if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
379+
return WriteRefId(Object::null());
380+
}
381+
#if !defined(DART_PRECOMPILED_RUNTIME)
382+
if (object->IsBytecode() && !Snapshot::IncludesBytecode(kind_)) {
383+
return WriteRefId(Object::null());
384+
}
385+
#endif // !DART_PRECOMPILED_RUNTIME
386+
FATAL("Missing ref");
387+
}
388+
}
389+
return id;
390+
}
391+
393392
Heap* heap_;
394393
Zone* zone_;
395394
Snapshot::Kind kind_;

0 commit comments

Comments
 (0)