[vm] Support --use_table_dispatch when splitting snapshots.

When reading a secondary snapshot, re-run the dispatch table initialization found in the root snapshot. Since each loading unit's contribution to the dispatch table is scattered, it would take more snapshot size to try to serialize their contributions separately. We'll revisit this when we can defer Class, Function and Code, which will prevent the root snapshot from referencing all Codes.

Bug: https://github.com/dart-lang/sdk/issues/41974
Change-Id: Iefd2b98647b96ae59a7efe92897538f5cf8c2426
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158923
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2020-08-18 16:46:50 +00:00 committed by commit-bot@chromium.org
parent 41953c8835
commit 56a4d7c5f8
9 changed files with 65 additions and 29 deletions

View file

@ -705,19 +705,13 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration
if (_configuration.useElf) ...[
"--snapshot-kind=app-aot-elf",
"--elf=$tempDir/out.aotsnapshot",
// Only splitting with a ELF to avoid having to setup compilation of
// multiple assembly files in the test harness.
"--loading-unit-manifest=$tempDir/ignored.json",
] else ...[
"--snapshot-kind=app-aot-assembly",
"--assembly=$tempDir/out.S",
],
// Only splitting with a ELF to avoid having to setup compilation of
// multiple assembly files in the test harness. Only splitting tests of
// deferred imports because splitting currently requires disable bare
// instructions mode, and we want to continue testing bare instructions
// mode.
if (_configuration.useElf && arguments.last.contains("deferred")) ...[
"--loading-unit-manifest=$tempDir/ignored.json",
"--use-table-dispatch=false",
],
if (_isAndroid && _isArm) '--no-sim-use-hardfp',
if (_configuration.isMinified) '--obfuscate',
// The SIMARM precompiler assumes support for integer division, but the

View file

@ -0,0 +1,14 @@
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--use_bare_instructions=false
// VMOptions=--use_bare_instructions=true --use_table_dispatch=false
// VMOptions=--use_bare_instructions=true --use_table_dispatch=true
import "splay_test.dart" deferred as splay; // Some non-trivial code.
main() async {
await splay.loadLibrary();
splay.main();
}

View file

@ -79,7 +79,6 @@ main(List<String> args) async {
// Compile kernel to ELF.
await run(genSnapshot, <String>[
"--snapshot-kind=app-aot-elf",
"--use-table-dispatch=false",
"--elf=$snapshot1",
"--loading-unit-manifest=$manifest1",
dill1,
@ -95,7 +94,6 @@ main(List<String> args) async {
await run(genSnapshot, <String>[
"--snapshot-kind=app-aot-elf",
"--use-table-dispatch=false",
"--elf=$snapshot2",
"--loading-unit-manifest=$manifest2",
dill2,

View file

@ -0,0 +1,14 @@
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--use_bare_instructions=false
// VMOptions=--use_bare_instructions=true --use_table_dispatch=false
// VMOptions=--use_bare_instructions=true --use_table_dispatch=true
import "splay_test.dart" deferred as splay; // Some non-trivial code.
main() async {
await splay.loadLibrary();
splay.main();
}

View file

@ -79,7 +79,6 @@ main(List<String> args) async {
// Compile kernel to ELF.
await run(genSnapshot, <String>[
"--snapshot-kind=app-aot-elf",
"--use-table-dispatch=false",
"--elf=$snapshot1",
"--loading-unit-manifest=$manifest1",
dill1,
@ -95,7 +94,6 @@ main(List<String> args) async {
await run(genSnapshot, <String>[
"--snapshot-kind=app-aot-elf",
"--use-table-dispatch=false",
"--elf=$snapshot2",
"--loading-unit-manifest=$manifest2",
dill2,

View file

@ -6206,15 +6206,16 @@ DeserializationCluster* Deserializer::ReadCluster() {
return NULL;
}
void Deserializer::ReadDispatchTable() {
void Deserializer::ReadDispatchTable(ReadStream* stream) {
#if defined(DART_PRECOMPILED_RUNTIME)
const intptr_t length = ReadUnsigned();
const uint8_t* table_snapshot_start = stream->AddressOfCurrentPosition();
const intptr_t length = stream->ReadUnsigned();
if (length == 0) return;
// Not all Code objects may be in the code_order_table when instructions can
// be deduplicated. Thus, we serialize the reference ID of the first code
// object, from which we can get the reference ID for any code object.
const intptr_t first_code_id = ReadUnsigned();
const intptr_t first_code_id = stream->ReadUnsigned();
auto const I = isolate();
auto code = I->object_store()->dispatch_table_null_error_stub();
@ -6233,7 +6234,7 @@ void Deserializer::ReadDispatchTable() {
repeat_count--;
continue;
}
auto const encoded = Read<intptr_t>();
auto const encoded = stream->Read<intptr_t>();
if (encoded == 0) {
value = null_entry;
} else if (encoded < 0) {
@ -6254,6 +6255,10 @@ void Deserializer::ReadDispatchTable() {
ASSERT(repeat_count == 0);
I->group()->set_dispatch_table(table);
intptr_t table_snapshot_size =
stream->AddressOfCurrentPosition() - table_snapshot_start;
I->group()->set_dispatch_table_snapshot(table_snapshot_start);
I->group()->set_dispatch_table_snapshot_size(table_snapshot_size);
#endif
}
@ -6674,7 +6679,7 @@ void Deserializer::ReadProgramSnapshot(ObjectStore* object_store) {
}
// Deserialize dispatch table (when applicable)
ReadDispatchTable();
ReadDispatchTable(&stream_);
#if defined(DEBUG)
int32_t section_marker = Read<int32_t>();
@ -6758,6 +6763,15 @@ ApiErrorPtr Deserializer::ReadUnitSnapshot(const LoadingUnit& unit) {
code->ptr()->code_source_map_ = static_cast<CodeSourceMapPtr>(ReadRef());
}
// Reinitialize the dispatch table by rereading the table's serialization
// in the root snapshot.
IsolateGroup* group = thread()->isolate()->group();
if (group->dispatch_table_snapshot() != nullptr) {
ReadStream stream(group->dispatch_table_snapshot(),
group->dispatch_table_snapshot_size());
ReadDispatchTable(&stream);
}
#if defined(DEBUG)
int32_t section_marker = Read<int32_t>();
ASSERT(section_marker == kSectionMarker);

View file

@ -704,7 +704,7 @@ class Deserializer : public ThreadStackResource {
DeserializationCluster* ReadCluster();
void ReadDispatchTable();
void ReadDispatchTable(ReadStream* stream);
intptr_t next_index() const { return next_ref_index_; }
Heap* heap() const { return heap_; }

View file

@ -6805,11 +6805,6 @@ DART_EXPORT Dart_Handle Dart_CreateAppAOTSnapshotAsAssemblies(
return Api::NewError(
"This VM was built without support for AOT compilation.");
#else
if (FLAG_use_bare_instructions && FLAG_use_table_dispatch) {
return Api::NewError(
"Splitting is not compatible with --use_table_dispatch.");
}
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
CHECK_NULL(next_callback);
@ -6887,11 +6882,6 @@ Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback,
return Api::NewError(
"This VM was built without support for AOT compilation.");
#else
if (FLAG_use_bare_instructions && FLAG_use_table_dispatch) {
return Api::NewError(
"Splitting is not compatible with --use_table_dispatch.");
}
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
CHECK_NULL(next_callback);

View file

@ -380,6 +380,18 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
void set_dispatch_table(DispatchTable* table) {
dispatch_table_.reset(table);
}
const uint8_t* dispatch_table_snapshot() const {
return dispatch_table_snapshot_;
}
void set_dispatch_table_snapshot(const uint8_t* snapshot) {
dispatch_table_snapshot_ = snapshot;
}
intptr_t dispatch_table_snapshot_size() const {
return dispatch_table_snapshot_size_;
}
void set_dispatch_table_snapshot_size(intptr_t size) {
dispatch_table_snapshot_size_ = size;
}
SharedClassTable* shared_class_table() const {
return shared_class_table_.get();
@ -672,6 +684,8 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
std::unique_ptr<StoreBuffer> store_buffer_;
std::unique_ptr<Heap> heap_;
std::unique_ptr<DispatchTable> dispatch_table_;
const uint8_t* dispatch_table_snapshot_ = nullptr;
intptr_t dispatch_table_snapshot_size_ = 0;
ArrayPtr saved_unlinked_calls_;
std::shared_ptr<FieldTable> saved_initial_field_table_;
uint32_t isolate_group_flags_ = 0;