From 56a4d7c5f85dbc493194e51d8187bd4aa2c318e5 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Tue, 18 Aug 2020 16:46:50 +0000 Subject: [PATCH] [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 Commit-Queue: Ryan Macnak --- .../lib/src/compiler_configuration.dart | 12 +++------- .../deferred_loading_call_modes_test.dart | 14 +++++++++++ .../dart/incompatible_loading_unit_test.dart | 2 -- .../deferred_loading_call_modes_test.dart | 14 +++++++++++ .../incompatible_loading_unit_test.dart | 2 -- runtime/vm/clustered_snapshot.cc | 24 +++++++++++++++---- runtime/vm/clustered_snapshot.h | 2 +- runtime/vm/dart_api_impl.cc | 10 -------- runtime/vm/isolate.h | 14 +++++++++++ 9 files changed, 65 insertions(+), 29 deletions(-) create mode 100644 runtime/tests/vm/dart/deferred_loading_call_modes_test.dart create mode 100644 runtime/tests/vm/dart_2/deferred_loading_call_modes_test.dart diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart index 4ddeafca8e3..935a63719ca 100644 --- a/pkg/test_runner/lib/src/compiler_configuration.dart +++ b/pkg/test_runner/lib/src/compiler_configuration.dart @@ -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 diff --git a/runtime/tests/vm/dart/deferred_loading_call_modes_test.dart b/runtime/tests/vm/dart/deferred_loading_call_modes_test.dart new file mode 100644 index 00000000000..8fa1e4541c4 --- /dev/null +++ b/runtime/tests/vm/dart/deferred_loading_call_modes_test.dart @@ -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(); +} diff --git a/runtime/tests/vm/dart/incompatible_loading_unit_test.dart b/runtime/tests/vm/dart/incompatible_loading_unit_test.dart index 5facc47e40b..9adf6e802a6 100644 --- a/runtime/tests/vm/dart/incompatible_loading_unit_test.dart +++ b/runtime/tests/vm/dart/incompatible_loading_unit_test.dart @@ -79,7 +79,6 @@ main(List args) async { // Compile kernel to ELF. await run(genSnapshot, [ "--snapshot-kind=app-aot-elf", - "--use-table-dispatch=false", "--elf=$snapshot1", "--loading-unit-manifest=$manifest1", dill1, @@ -95,7 +94,6 @@ main(List args) async { await run(genSnapshot, [ "--snapshot-kind=app-aot-elf", - "--use-table-dispatch=false", "--elf=$snapshot2", "--loading-unit-manifest=$manifest2", dill2, diff --git a/runtime/tests/vm/dart_2/deferred_loading_call_modes_test.dart b/runtime/tests/vm/dart_2/deferred_loading_call_modes_test.dart new file mode 100644 index 00000000000..8fa1e4541c4 --- /dev/null +++ b/runtime/tests/vm/dart_2/deferred_loading_call_modes_test.dart @@ -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(); +} diff --git a/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart b/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart index 5facc47e40b..9adf6e802a6 100644 --- a/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart +++ b/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart @@ -79,7 +79,6 @@ main(List args) async { // Compile kernel to ELF. await run(genSnapshot, [ "--snapshot-kind=app-aot-elf", - "--use-table-dispatch=false", "--elf=$snapshot1", "--loading-unit-manifest=$manifest1", dill1, @@ -95,7 +94,6 @@ main(List args) async { await run(genSnapshot, [ "--snapshot-kind=app-aot-elf", - "--use-table-dispatch=false", "--elf=$snapshot2", "--loading-unit-manifest=$manifest2", dill2, diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc index f02d4689b64..ba76ca6d9e7 100644 --- a/runtime/vm/clustered_snapshot.cc +++ b/runtime/vm/clustered_snapshot.cc @@ -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(); + auto const encoded = stream->Read(); 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(); @@ -6758,6 +6763,15 @@ ApiErrorPtr Deserializer::ReadUnitSnapshot(const LoadingUnit& unit) { code->ptr()->code_source_map_ = static_cast(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(); ASSERT(section_marker == kSectionMarker); diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h index 47103728f4b..26e3f38482d 100644 --- a/runtime/vm/clustered_snapshot.h +++ b/runtime/vm/clustered_snapshot.h @@ -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_; } diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index a7882d75c2b..6e327e2dad9 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -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); diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h index b8b23a16c57..0e175bd1335 100644 --- a/runtime/vm/isolate.h +++ b/runtime/vm/isolate.h @@ -380,6 +380,18 @@ class IsolateGroup : public IntrusiveDListEntry { 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 { std::unique_ptr store_buffer_; std::unique_ptr heap_; std::unique_ptr dispatch_table_; + const uint8_t* dispatch_table_snapshot_ = nullptr; + intptr_t dispatch_table_snapshot_size_ = 0; ArrayPtr saved_unlinked_calls_; std::shared_ptr saved_initial_field_table_; uint32_t isolate_group_flags_ = 0;