Skip to content

Commit 63d17b0

Browse files
rmacnak-googlecommit-bot@chromium.org
authored andcommitted
[vm] Defer object pool entries in instructions bare mode.
dart2js+analyzer product X64 bare: app.so 9289320 -> 8491864 (-8.58%) app.so-2.part.so 12010936 -> 12315880 (2.53%) app.so-3.part.so 7579704 -> 7847768 (3.53%) TEST=ci Bug: #41974 Change-Id: I8e695966bc11c3912a01cd525ca69be6ef8e5ea2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/171102 Commit-Queue: Ryan Macnak <[email protected]> Reviewed-by: Régis Crelier <[email protected]>
1 parent 8d971e1 commit 63d17b0

9 files changed

+172
-74
lines changed

runtime/tests/vm/dart/split_literals_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ main(List<String> args) async {
6565

6666
// Compile kernel to ELF.
6767
await run(genSnapshot, <String>[
68-
"--use_bare_instructions=false",
68+
"--use_bare_instructions=false", //# object: ok
69+
"--use_bare_instructions=true", //# bare: ok
6970
"--snapshot-kind=app-aot-elf",
7071
"--elf=$snapshot",
7172
"--loading-unit-manifest=$manifest",

runtime/tests/vm/dart_2/split_literals_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ main(List<String> args) async {
6565

6666
// Compile kernel to ELF.
6767
await run(genSnapshot, <String>[
68-
"--use_bare_instructions=false",
68+
"--use_bare_instructions=false", //# object: ok
69+
"--use_bare_instructions=true", //# bare: ok
6970
"--snapshot-kind=app-aot-elf",
7071
"--elf=$snapshot",
7172
"--loading-unit-manifest=$manifest",

runtime/vm/clustered_snapshot.cc

Lines changed: 140 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,11 +1403,26 @@ class CodeSerializationCluster : public SerializationCluster {
14031403
objects_.Add(code);
14041404
}
14051405

1406-
if (!(s->kind() == Snapshot::kFullAOT && FLAG_use_bare_instructions)) {
1406+
if (s->kind() == Snapshot::kFullAOT && FLAG_use_bare_instructions) {
1407+
if (FLAG_retain_function_objects) {
1408+
ObjectPoolPtr pool = code->ptr()->object_pool_;
1409+
if ((pool != ObjectPool::null()) && s->InCurrentLoadingUnit(code)) {
1410+
const intptr_t length = pool->ptr()->length_;
1411+
uint8_t* entry_bits = pool->ptr()->entry_bits();
1412+
for (intptr_t i = 0; i < length; i++) {
1413+
auto entry_type = ObjectPool::TypeBits::decode(entry_bits[i]);
1414+
if (entry_type == ObjectPool::EntryType::kTaggedObject) {
1415+
s->Push(pool->ptr()->data()[i].raw_obj_);
1416+
}
1417+
}
1418+
}
1419+
}
1420+
} else {
14071421
if (s->InCurrentLoadingUnit(code->ptr()->object_pool_)) {
14081422
s->Push(code->ptr()->object_pool_);
14091423
}
14101424
}
1425+
14111426
s->Push(code->ptr()->owner_);
14121427
s->Push(code->ptr()->exception_handlers_);
14131428
s->Push(code->ptr()->pc_descriptors_);
@@ -1519,21 +1534,6 @@ class CodeSerializationCluster : public SerializationCluster {
15191534
}
15201535

15211536
void WriteAlloc(Serializer* s) {
1522-
Sort(&objects_);
1523-
auto loading_units = s->loading_units();
1524-
if ((loading_units != nullptr) &&
1525-
(s->current_loading_unit_id() == LoadingUnit::kRootId)) {
1526-
for (intptr_t i = LoadingUnit::kRootId + 1; i < loading_units->length();
1527-
i++) {
1528-
auto unit_objects = loading_units->At(i)->deferred_objects();
1529-
Sort(unit_objects);
1530-
for (intptr_t j = 0; j < unit_objects->length(); j++) {
1531-
deferred_objects_.Add(unit_objects->At(j)->raw());
1532-
}
1533-
}
1534-
}
1535-
s->PrepareInstructions(&objects_);
1536-
15371537
s->WriteCid(kCodeCid);
15381538
const intptr_t count = objects_.length();
15391539
s->WriteUnsigned(count);
@@ -1679,7 +1679,8 @@ class CodeSerializationCluster : public SerializationCluster {
16791679
s->Write<int32_t>(code->ptr()->state_bits_);
16801680
}
16811681

1682-
GrowableArray<CodePtr>* discovered_objects() { return &objects_; }
1682+
GrowableArray<CodePtr>* objects() { return &objects_; }
1683+
GrowableArray<CodePtr>* deferred_objects() { return &deferred_objects_; }
16831684

16841685
// Some code objects would have their owners dropped from the snapshot,
16851686
// which makes it is impossible to recover program structure when
@@ -1843,12 +1844,17 @@ class ObjectPoolSerializationCluster : public SerializationCluster {
18431844
ObjectPoolPtr pool = ObjectPool::RawCast(object);
18441845
objects_.Add(pool);
18451846

1846-
const intptr_t length = pool->ptr()->length_;
1847-
uint8_t* entry_bits = pool->ptr()->entry_bits();
1848-
for (intptr_t i = 0; i < length; i++) {
1849-
auto entry_type = ObjectPool::TypeBits::decode(entry_bits[i]);
1850-
if (entry_type == ObjectPool::EntryType::kTaggedObject) {
1851-
s->Push(pool->ptr()->data()[i].raw_obj_);
1847+
if (s->kind() == Snapshot::kFullAOT && FLAG_use_bare_instructions &&
1848+
FLAG_retain_function_objects) {
1849+
// Treat pool as weak.
1850+
} else {
1851+
const intptr_t length = pool->ptr()->length_;
1852+
uint8_t* entry_bits = pool->ptr()->entry_bits();
1853+
for (intptr_t i = 0; i < length; i++) {
1854+
auto entry_type = ObjectPool::TypeBits::decode(entry_bits[i]);
1855+
if (entry_type == ObjectPool::EntryType::kTaggedObject) {
1856+
s->Push(pool->ptr()->data()[i].raw_obj_);
1857+
}
18521858
}
18531859
}
18541860
}
@@ -1867,6 +1873,9 @@ class ObjectPoolSerializationCluster : public SerializationCluster {
18671873
}
18681874

18691875
void WriteFill(Serializer* s) {
1876+
bool weak = s->kind() == Snapshot::kFullAOT && FLAG_use_bare_instructions &&
1877+
FLAG_retain_function_objects;
1878+
18701879
const intptr_t count = objects_.length();
18711880
for (intptr_t i = 0; i < count; i++) {
18721881
ObjectPoolPtr pool = objects_[i];
@@ -1887,7 +1896,12 @@ class ObjectPoolSerializationCluster : public SerializationCluster {
18871896
s->WriteElementRef(StubCode::CallBootstrapNative().raw(), j);
18881897
break;
18891898
}
1890-
s->WriteElementRef(entry.raw_obj_, j);
1899+
if (weak && !s->HasRef(entry.raw_obj_)) {
1900+
// Any value will do, but null has the shortest id.
1901+
s->WriteElementRef(Object::null(), j);
1902+
} else {
1903+
s->WriteElementRef(entry.raw_obj_, j);
1904+
}
18911905
break;
18921906
}
18931907
case ObjectPool::EntryType::kImmediate: {
@@ -5269,19 +5283,26 @@ class UnitSerializationRoots : public SerializationRoots {
52695283
const Object* deferred_object = (*unit_->deferred_objects())[i];
52705284
ASSERT(deferred_object->IsCode());
52715285
CodePtr code = static_cast<CodePtr>(deferred_object->raw());
5272-
if (!FLAG_use_bare_instructions) {
5286+
if (FLAG_use_bare_instructions) {
5287+
if (FLAG_retain_function_objects) {
5288+
ObjectPoolPtr pool = code->ptr()->object_pool_;
5289+
if (pool != ObjectPool::null()) {
5290+
const intptr_t length = pool->ptr()->length_;
5291+
uint8_t* entry_bits = pool->ptr()->entry_bits();
5292+
for (intptr_t i = 0; i < length; i++) {
5293+
auto entry_type = ObjectPool::TypeBits::decode(entry_bits[i]);
5294+
if (entry_type == ObjectPool::EntryType::kTaggedObject) {
5295+
s->Push(pool->ptr()->data()[i].raw_obj_);
5296+
}
5297+
}
5298+
}
5299+
}
5300+
} else {
52735301
s->Push(code->ptr()->object_pool_);
52745302
}
52755303
s->Push(code->ptr()->compressed_stackmaps_);
52765304
s->Push(code->ptr()->code_source_map_);
52775305
}
5278-
{
5279-
GrowableArray<CodePtr> raw_codes(num_deferred_objects);
5280-
for (intptr_t i = 0; i < num_deferred_objects; i++) {
5281-
raw_codes.Add((*unit_->deferred_objects())[i]->raw());
5282-
}
5283-
s->PrepareInstructions(&raw_codes);
5284-
}
52855306
}
52865307

52875308
void WriteRoots(Serializer* s) {
@@ -5307,6 +5328,27 @@ class UnitSerializationRoots : public SerializationRoots {
53075328
s->WriteRootRef(code->ptr()->compressed_stackmaps_, "deferred-code");
53085329
s->WriteRootRef(code->ptr()->code_source_map_, "deferred-code");
53095330
}
5331+
5332+
if (FLAG_use_bare_instructions && FLAG_retain_function_objects) {
5333+
ObjectPoolPtr pool =
5334+
s->isolate_group()->object_store()->global_object_pool();
5335+
const intptr_t length = pool->ptr()->length_;
5336+
uint8_t* entry_bits = pool->ptr()->entry_bits();
5337+
intptr_t last_write = 0;
5338+
for (intptr_t i = 0; i < length; i++) {
5339+
auto entry_type = ObjectPool::TypeBits::decode(entry_bits[i]);
5340+
if (entry_type == ObjectPool::EntryType::kTaggedObject) {
5341+
if (s->IsWritten(pool->ptr()->data()[i].raw_obj_)) {
5342+
intptr_t skip = i - last_write;
5343+
s->WriteUnsigned(skip);
5344+
s->WriteRootRef(pool->ptr()->data()[i].raw_obj_,
5345+
"deferred-literal");
5346+
last_write = i;
5347+
}
5348+
}
5349+
}
5350+
s->WriteUnsigned(length - last_write);
5351+
}
53105352
#endif
53115353
}
53125354

@@ -5351,6 +5393,20 @@ class UnitDeserializationRoots : public DeserializationRoots {
53515393
static_cast<CodeSourceMapPtr>(d->ReadRef());
53525394
}
53535395

5396+
if (FLAG_use_bare_instructions && FLAG_retain_function_objects) {
5397+
ObjectPoolPtr pool =
5398+
d->isolate_group()->object_store()->global_object_pool();
5399+
const intptr_t length = pool->ptr()->length_;
5400+
uint8_t* entry_bits = pool->ptr()->entry_bits();
5401+
for (intptr_t i = d->ReadUnsigned(); i < length; i += d->ReadUnsigned()) {
5402+
auto entry_type = ObjectPool::TypeBits::decode(entry_bits[i]);
5403+
ASSERT(entry_type == ObjectPool::EntryType::kTaggedObject);
5404+
// The existing entry will usually be null, but it might also be an
5405+
// equivalent object that was duplicated in another loading unit.
5406+
pool->ptr()->data()[i].raw_obj_ = d->ReadRef();
5407+
}
5408+
}
5409+
53545410
// Reinitialize the dispatch table by rereading the table's serialization
53555411
// in the root snapshot.
53565412
IsolateGroup* group = d->thread()->isolate()->group();
@@ -5776,11 +5832,58 @@ bool Serializer::InCurrentLoadingUnit(ObjectPtr obj, bool record) {
57765832
}
57775833

57785834
#if !defined(DART_PRECOMPILED_RUNTIME)
5779-
void Serializer::PrepareInstructions(GrowableArray<CodePtr>* code_objects) {
5835+
void Serializer::PrepareInstructions() {
5836+
if (!Snapshot::IncludesCode(kind())) return;
5837+
5838+
CodeSerializationCluster* cluster =
5839+
static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid]);
5840+
5841+
// Code objects that have identical/duplicate instructions must be adjacent in
5842+
// the order that Code objects are written because the encoding of the
5843+
// reference from the Code to the Instructions assumes monotonically
5844+
// increasing offsets as part of a delta encoding. Also the code order table
5845+
// that allows for mapping return addresses back to Code objects depends on
5846+
// this sorting.
5847+
if (cluster != nullptr) {
5848+
CodeSerializationCluster::Sort(cluster->objects());
5849+
}
5850+
if ((loading_units_ != nullptr) &&
5851+
(current_loading_unit_id_ == LoadingUnit::kRootId)) {
5852+
for (intptr_t i = LoadingUnit::kRootId + 1; i < loading_units_->length();
5853+
i++) {
5854+
auto unit_objects = loading_units_->At(i)->deferred_objects();
5855+
CodeSerializationCluster::Sort(unit_objects);
5856+
for (intptr_t j = 0; j < unit_objects->length(); j++) {
5857+
cluster->deferred_objects()->Add(unit_objects->At(j)->raw());
5858+
}
5859+
}
5860+
}
5861+
57805862
#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
57815863
if ((kind() == Snapshot::kFullAOT) && FLAG_use_bare_instructions) {
5864+
// Group the code objects whose instructions are not being deferred in this
5865+
// snapshot unit in the order they will be written: first the code objects
5866+
// encountered for this first time in this unit being written by the
5867+
// CodeSerializationCluster, then code object previously deferred whose
5868+
// instructions are now written by UnitSerializationRoots. This order needs
5869+
// to be known to finalize bare-instructions-mode's PC-relative calls.
5870+
GrowableArray<CodePtr> code_objects;
5871+
if (cluster != nullptr) {
5872+
auto in = cluster->objects();
5873+
for (intptr_t i = 0; i < in->length(); i++) {
5874+
code_objects.Add(in->At(i));
5875+
}
5876+
}
5877+
if (loading_units_ != nullptr) {
5878+
auto in =
5879+
loading_units_->At(current_loading_unit_id_)->deferred_objects();
5880+
for (intptr_t i = 0; i < in->length(); i++) {
5881+
code_objects.Add(in->At(i)->raw());
5882+
}
5883+
}
5884+
57825885
GrowableArray<ImageWriterCommand> writer_commands;
5783-
RelocateCodeObjects(vm_, code_objects, &writer_commands);
5886+
RelocateCodeObjects(vm_, &code_objects, &writer_commands);
57845887
image_writer_->PrepareForSerialization(&writer_commands);
57855888
}
57865889
#endif // defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
@@ -6030,6 +6133,8 @@ ZoneGrowableArray<Object*>* Serializer::Serialize(SerializationRoots* roots) {
60306133
}
60316134
#endif
60326135

6136+
PrepareInstructions();
6137+
60336138
intptr_t num_objects = num_base_objects_ + num_written_objects_;
60346139
#if defined(ARCH_IS_64_BIT)
60356140
if (!Utils::IsInt(32, num_objects)) {
@@ -6147,8 +6252,7 @@ void Serializer::WriteDispatchTable(const Array& entries) {
61476252
ASSERT(code_cluster != nullptr);
61486253
// Reference IDs in a cluster are allocated sequentially, so we can use the
61496254
// first code object's reference ID to calculate the cluster index.
6150-
const intptr_t first_code_id =
6151-
RefId(code_cluster->discovered_objects()->At(0));
6255+
const intptr_t first_code_id = RefId(code_cluster->objects()->At(0));
61526256
// The first object in the code cluster must have its reference ID allocated.
61536257
ASSERT(IsAllocatedReference(first_code_id));
61546258

runtime/vm/clustered_snapshot.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ class Serializer : public ThreadStackResource {
351351
Write<int32_t>(cid);
352352
}
353353

354-
void PrepareInstructions(GrowableArray<CodePtr>* codes);
354+
void PrepareInstructions();
355355
void WriteInstructions(InstructionsPtr instr,
356356
uint32_t unchecked_offset,
357357
CodePtr code,
@@ -419,6 +419,13 @@ class Serializer : public ThreadStackResource {
419419
FATAL("Missing ref");
420420
}
421421

422+
bool HasRef(ObjectPtr object) const {
423+
return heap_->GetObjectId(object) != kUnreachableReference;
424+
}
425+
bool IsWritten(ObjectPtr object) const {
426+
return heap_->GetObjectId(object) > num_base_objects_;
427+
}
428+
422429
private:
423430
const char* ReadOnlyObjectType(intptr_t cid);
424431

runtime/vm/compiler/relocation.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,15 @@ void CodeRelocator::Relocate(bool is_vm_isolate) {
7171
// We're guaranteed to have all calls resolved, since
7272
// * backwards calls are resolved eagerly
7373
// * forward calls are resolved once the target is written
74-
ASSERT(all_unresolved_calls_.IsEmpty());
75-
ASSERT(unresolved_calls_by_destination_.IsEmpty());
74+
if (!all_unresolved_calls_.IsEmpty()) {
75+
for (auto call : all_unresolved_calls_) {
76+
OS::PrintErr("Unresolved call to %s from %s\n",
77+
Object::Handle(call->callee).ToCString(),
78+
Object::Handle(call->caller).ToCString());
79+
}
80+
}
81+
RELEASE_ASSERT(all_unresolved_calls_.IsEmpty());
82+
RELEASE_ASSERT(unresolved_calls_by_destination_.IsEmpty());
7683

7784
// Any trampolines we created must be patched with the right offsets.
7885
auto it = trampolines_by_destination_.GetIterator();

runtime/vm/compiler/type_testing_stubs_arm.cc

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,8 @@ void TypeTestingStubGenerator::BuildOptimizedTypeTestStub(
2020
const Type& type,
2121
const Class& type_class) {
2222
BuildOptimizedTypeTestStubFastCases(assembler, hi, type, type_class);
23-
if (!compiler::IsSameObject(
24-
compiler::NullObject(),
25-
compiler::CastHandle<Object>(slow_type_test_stub))) {
26-
__ GenerateUnRelocatedPcRelativeTailCall();
27-
unresolved_calls->Add(new compiler::UnresolvedPcRelativeCall(
28-
__ CodeSize(), slow_type_test_stub, /*is_tail_call=*/true));
29-
} else {
30-
__ Branch(compiler::Address(
31-
THR, compiler::target::Thread::slow_type_test_entry_point_offset()));
32-
}
23+
__ Branch(compiler::Address(
24+
THR, compiler::target::Thread::slow_type_test_entry_point_offset()));
3325
}
3426

3527
} // namespace dart

runtime/vm/compiler/type_testing_stubs_arm64.cc

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,11 @@ void TypeTestingStubGenerator::BuildOptimizedTypeTestStub(
2020
const Type& type,
2121
const Class& type_class) {
2222
BuildOptimizedTypeTestStubFastCases(assembler, hi, type, type_class);
23-
if (!compiler::IsSameObject(
24-
compiler::NullObject(),
25-
compiler::CastHandle<Object>(slow_type_test_stub))) {
26-
__ GenerateUnRelocatedPcRelativeTailCall();
27-
unresolved_calls->Add(new compiler::UnresolvedPcRelativeCall(
28-
__ CodeSize(), slow_type_test_stub, /*is_tail_call=*/true));
29-
} else {
30-
__ ldr(TMP,
31-
compiler::Address(
32-
THR,
33-
compiler::target::Thread::slow_type_test_entry_point_offset()));
34-
__ br(TMP);
35-
}
23+
__ ldr(
24+
TMP,
25+
compiler::Address(
26+
THR, compiler::target::Thread::slow_type_test_entry_point_offset()));
27+
__ br(TMP);
3628
}
3729

3830
} // namespace dart

runtime/vm/compiler/type_testing_stubs_x64.cc

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,8 @@ void TypeTestingStubGenerator::BuildOptimizedTypeTestStub(
2020
const Type& type,
2121
const Class& type_class) {
2222
BuildOptimizedTypeTestStubFastCases(assembler, hi, type, type_class);
23-
if (!compiler::IsSameObject(
24-
compiler::NullObject(),
25-
compiler::CastHandle<Object>(slow_type_test_stub))) {
26-
__ GenerateUnRelocatedPcRelativeTailCall();
27-
unresolved_calls->Add(new compiler::UnresolvedPcRelativeCall(
28-
__ CodeSize(), slow_type_test_stub, /*is_tail_call=*/true));
29-
} else {
30-
__ jmp(compiler::Address(
31-
THR, compiler::target::Thread::slow_type_test_entry_point_offset()));
32-
}
23+
__ jmp(compiler::Address(
24+
THR, compiler::target::Thread::slow_type_test_entry_point_offset()));
3325
}
3426

3527
} // namespace dart

0 commit comments

Comments
 (0)