diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart index 02d7b2a056e..59bedc21f87 100644 --- a/pkg/test_runner/lib/src/compiler_configuration.dart +++ b/pkg/test_runner/lib/src/compiler_configuration.dart @@ -708,10 +708,19 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration var args = [ if (_configuration.useElf) ...[ "--snapshot-kind=app-aot-elf", - "--elf=$tempDir/out.aotsnapshot" + "--elf=$tempDir/out.aotsnapshot", ] else ...[ "--snapshot-kind=app-aot-assembly", - "--assembly=$tempDir/out.S" + "--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-bare-instructions=false", ], if (_isAndroid && _isArm) '--no-sim-use-hardfp', if (_configuration.isMinified) '--obfuscate', diff --git a/runtime/bin/elf_loader.cc b/runtime/bin/elf_loader.cc index b3981bde528..c67f3918bd5 100644 --- a/runtime/bin/elf_loader.cc +++ b/runtime/bin/elf_loader.cc @@ -527,10 +527,6 @@ bool LoadedElf::ResolveSymbols(const uint8_t** vm_data, } } - CHECK_ERROR(vm_data == nullptr || *vm_data != nullptr, - "Could not find VM snapshot data."); - CHECK_ERROR(vm_instrs == nullptr || *vm_instrs != nullptr, - "Could not find VM snapshot instructions."); CHECK_ERROR(isolate_data == nullptr || *isolate_data != nullptr, "Could not find isolate snapshot data."); CHECK_ERROR(isolate_instrs == nullptr || *isolate_instrs != nullptr, diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc index f49defce7a3..916dd525453 100644 --- a/runtime/bin/gen_snapshot.cc +++ b/runtime/bin/gen_snapshot.cc @@ -114,6 +114,7 @@ static const char* kSnapshotKindNames[] = { V(blobs_container_filename, blobs_container_filename) \ V(assembly, assembly_filename) \ V(elf, elf_filename) \ + V(loading_unit_manifest, loading_unit_manifest_filename) \ V(load_compilation_trace, load_compilation_trace_filename) \ V(load_type_feedback, load_type_feedback_filename) \ V(save_debugging_info, debugging_info_filename) \ @@ -286,7 +287,7 @@ static int ParseArguments(int argc, case kAppAOTElf: { if (elf_filename == NULL) { Syslog::PrintErr( - "Building an AOT snapshot as assembly requires specifying " + "Building an AOT snapshot as ELF requires specifying " "an output file for --elf.\n\n"); return -1; } @@ -335,13 +336,21 @@ static int ParseArguments(int argc, return 0; } +PRINTF_ATTRIBUTE(1, 2) static void PrintErrAndExit(const char* format, ...) { + va_list args; + va_start(args, format); + Syslog::VPrintErr(format, args); + va_end(args); + + Dart_ExitScope(); + Dart_ShutdownIsolate(); + exit(kErrorExitCode); +} + static File* OpenFile(const char* filename) { File* file = File::Open(NULL, filename, File::kWriteTruncate); if (file == NULL) { - Syslog::PrintErr("Error: Unable to write file: %s\n\n", filename); - Dart_ExitScope(); - Dart_ShutdownIsolate(); - exit(kErrorExitCode); + PrintErrAndExit("Error: Unable to write file: %s\n\n", filename); } return file; } @@ -352,29 +361,20 @@ static void WriteFile(const char* filename, File* file = OpenFile(filename); RefCntReleaseScope rs(file); if (!file->WriteFully(buffer, size)) { - Syslog::PrintErr("Error: Unable to write file: %s\n\n", filename); - Dart_ExitScope(); - Dart_ShutdownIsolate(); - exit(kErrorExitCode); + PrintErrAndExit("Error: Unable to write file: %s\n\n", filename); } } static void ReadFile(const char* filename, uint8_t** buffer, intptr_t* size) { File* file = File::Open(NULL, filename, File::kRead); if (file == NULL) { - Syslog::PrintErr("Unable to open file %s\n", filename); - Dart_ExitScope(); - Dart_ShutdownIsolate(); - exit(kErrorExitCode); + PrintErrAndExit("Error: Unable to read file: %s\n", filename); } RefCntReleaseScope rs(file); *size = file->Length(); *buffer = reinterpret_cast(malloc(*size)); if (!file->ReadFully(*buffer, *size)) { - Syslog::PrintErr("Unable to read file %s\n", filename); - Dart_ExitScope(); - Dart_ShutdownIsolate(); - exit(kErrorExitCode); + PrintErrAndExit("Error: Unable to read file: %s\n", filename); } } @@ -579,13 +579,93 @@ static void StreamingWriteCallback(void* callback_data, intptr_t size) { File* file = reinterpret_cast(callback_data); if ((file != nullptr) && !file->WriteFully(buffer, size)) { - Syslog::PrintErr("Error: Unable to write snapshot file\n\n"); - Dart_ExitScope(); - Dart_ShutdownIsolate(); - exit(kErrorExitCode); + PrintErrAndExit("Error: Unable to write snapshot file\n\n"); } } +static void StreamingCloseCallback(void* callback_data) { + File* file = reinterpret_cast(callback_data); + file->Release(); +} + +static File* OpenLoadingUnitManifest() { + File* manifest_file = OpenFile(loading_unit_manifest_filename); + if (!manifest_file->Print("{ \"loadingUnits\": [\n")) { + PrintErrAndExit("Error: Unable to write file: %s\n\n", + loading_unit_manifest_filename); + } + return manifest_file; +} + +static void WriteLoadingUnitManifest(File* manifest_file, + intptr_t id, + const char* path) { + bool success = true; + if (id != 1) { + success &= manifest_file->Print(","); + } + success &= + manifest_file->Print("{ \"id\": %" Pd ", \"path\": \"%s\" }\n", id, path); + if (!success) { + PrintErrAndExit("Error: Unable to write file: %s\n\n", + loading_unit_manifest_filename); + } +} + +static void CloseLoadingUnitManifest(File* manifest_file) { + if (!manifest_file->Print("] }\n")) { + PrintErrAndExit("Error: Unable to write file: %s\n\n", + loading_unit_manifest_filename); + } + manifest_file->Release(); +} + +static void NextLoadingUnit(void* callback_data, + intptr_t loading_unit_id, + void** write_callback_data, + void** write_debug_callback_data, + const char* main_filename, + const char* suffix) { + char* filename = loading_unit_id == 1 + ? strdup(main_filename) + : Utils::SCreate("%s-%" Pd ".part.%s", main_filename, + loading_unit_id, suffix); + File* file = OpenFile(filename); + *write_callback_data = file; + + if (debugging_info_filename != nullptr) { + char* debug_filename = + loading_unit_id == 1 + ? strdup(debugging_info_filename) + : Utils::SCreate("%s-%" Pd ".part.so", debugging_info_filename, + loading_unit_id); + File* debug_file = OpenFile(debug_filename); + *write_debug_callback_data = debug_file; + free(debug_filename); + } + + WriteLoadingUnitManifest(reinterpret_cast(callback_data), + loading_unit_id, filename); + + free(filename); +} + +static void NextAsmCallback(void* callback_data, + intptr_t loading_unit_id, + void** write_callback_data, + void** write_debug_callback_data) { + NextLoadingUnit(callback_data, loading_unit_id, write_callback_data, + write_debug_callback_data, assembly_filename, "S"); +} + +static void NextElfCallback(void* callback_data, + intptr_t loading_unit_id, + void** write_callback_data, + void** write_debug_callback_data) { + NextLoadingUnit(callback_data, loading_unit_id, write_callback_data, + write_debug_callback_data, elf_filename, "so"); +} + static void CreateAndWritePrecompiledSnapshot() { ASSERT(IsSnapshottingForPrecompilation()); Dart_Handle result; @@ -596,20 +676,30 @@ static void CreateAndWritePrecompiledSnapshot() { // Create a precompiled snapshot. if (snapshot_kind == kAppAOTAssembly) { - File* file = OpenFile(assembly_filename); - RefCntReleaseScope rs(file); - File* debug_file = nullptr; - if (debugging_info_filename != nullptr) { - debug_file = OpenFile(debugging_info_filename); - } else if (strip) { + if (strip && (debugging_info_filename == nullptr)) { Syslog::PrintErr( "Warning: Generating assembly code without DWARF debugging" " information.\n"); } - result = Dart_CreateAppAOTSnapshotAsAssembly(StreamingWriteCallback, file, - strip, debug_file); - if (debug_file != nullptr) debug_file->Release(); - CHECK_RESULT(result); + if (loading_unit_manifest_filename == nullptr) { + File* file = OpenFile(assembly_filename); + RefCntReleaseScope rs(file); + File* debug_file = nullptr; + if (debugging_info_filename != nullptr) { + debug_file = OpenFile(debugging_info_filename); + } + result = Dart_CreateAppAOTSnapshotAsAssembly(StreamingWriteCallback, file, + strip, debug_file); + if (debug_file != nullptr) debug_file->Release(); + CHECK_RESULT(result); + } else { + File* manifest_file = OpenLoadingUnitManifest(); + result = Dart_CreateAppAOTSnapshotAsAssemblies( + NextAsmCallback, manifest_file, strip, StreamingWriteCallback, + StreamingCloseCallback); + CHECK_RESULT(result); + CloseLoadingUnitManifest(manifest_file); + } if (obfuscate && !strip) { Syslog::PrintErr( "Warning: The generated assembly code contains unobfuscated DWARF " @@ -617,20 +707,30 @@ static void CreateAndWritePrecompiledSnapshot() { " To avoid this, use --strip to remove it.\n"); } } else if (snapshot_kind == kAppAOTElf) { - File* file = OpenFile(elf_filename); - RefCntReleaseScope rs(file); - File* debug_file = nullptr; - if (debugging_info_filename != nullptr) { - debug_file = OpenFile(debugging_info_filename); - } else if (strip) { + if (strip && (debugging_info_filename == nullptr)) { Syslog::PrintErr( "Warning: Generating ELF library without DWARF debugging" " information.\n"); } - result = Dart_CreateAppAOTSnapshotAsElf(StreamingWriteCallback, file, strip, - debug_file); - if (debug_file != nullptr) debug_file->Release(); - CHECK_RESULT(result); + if (loading_unit_manifest_filename == nullptr) { + File* file = OpenFile(elf_filename); + RefCntReleaseScope rs(file); + File* debug_file = nullptr; + if (debugging_info_filename != nullptr) { + debug_file = OpenFile(debugging_info_filename); + } + result = Dart_CreateAppAOTSnapshotAsElf(StreamingWriteCallback, file, + strip, debug_file); + if (debug_file != nullptr) debug_file->Release(); + CHECK_RESULT(result); + } else { + File* manifest_file = OpenLoadingUnitManifest(); + result = Dart_CreateAppAOTSnapshotAsElfs(NextElfCallback, manifest_file, + strip, StreamingWriteCallback, + StreamingCloseCallback); + CHECK_RESULT(result); + CloseLoadingUnitManifest(manifest_file); + } if (obfuscate && !strip) { Syslog::PrintErr( "Warning: The generated ELF library contains unobfuscated DWARF " diff --git a/runtime/bin/isolate_data.cc b/runtime/bin/isolate_data.cc index 1d62d32e118..75bf2f412fe 100644 --- a/runtime/bin/isolate_data.cc +++ b/runtime/bin/isolate_data.cc @@ -25,13 +25,16 @@ IsolateGroupData::IsolateGroupData(const char* url, } IsolateGroupData::~IsolateGroupData() { + for (intptr_t i = 0; i < loading_units_.length(); i++) { + delete loading_units_[i]; + } free(script_url); - script_url = NULL; + script_url = nullptr; free(packages_file_); - packages_file_ = NULL; + packages_file_ = nullptr; free(resolved_packages_config_); - resolved_packages_config_ = NULL; - kernel_buffer_ = NULL; + resolved_packages_config_ = nullptr; + kernel_buffer_ = nullptr; kernel_buffer_size_ = 0; } diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h index 6daf547e67a..bba25d796e9 100644 --- a/runtime/bin/isolate_data.h +++ b/runtime/bin/isolate_data.h @@ -11,6 +11,7 @@ #include "include/dart_api.h" #include "platform/assert.h" #include "platform/globals.h" +#include "platform/growable_array.h" #include "platform/utils.h" namespace dart { @@ -96,10 +97,15 @@ class IsolateGroupData { return app_snapshot_ != nullptr || isolate_run_app_snapshot_; } + void AddLoadingUnit(AppSnapshot* loading_unit) { + loading_units_.Add(loading_unit); + } + private: friend class IsolateData; // For packages_file_ std::unique_ptr app_snapshot_; + MallocGrowableArray loading_units_; char* resolved_packages_config_; std::shared_ptr kernel_buffer_; intptr_t kernel_buffer_size_; diff --git a/runtime/bin/loader.cc b/runtime/bin/loader.cc index 02002b39ea9..e5c869ade1b 100644 --- a/runtime/bin/loader.cc +++ b/runtime/bin/loader.cc @@ -12,6 +12,7 @@ #include "bin/file.h" #include "bin/gzip.h" #include "bin/lockers.h" +#include "bin/snapshot_utils.h" #include "bin/utils.h" #include "include/dart_tools_api.h" #include "platform/growable_array.h" @@ -220,6 +221,44 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag, } #endif // !defined(DART_PRECOMPILED_RUNTIME) +Dart_Handle Loader::DeferredLoadHandler(intptr_t loading_unit_id) { + // A synchronous implementation. An asynchronous implementation would be + // better, but the standalone embedder only implements AOT for testing. + + auto isolate_group_data = + reinterpret_cast(Dart_CurrentIsolateGroupData()); + char* unit_url = Utils::SCreate( + "%s-%" Pd ".part.so", isolate_group_data->script_url, loading_unit_id); + + AppSnapshot* loading_unit_snapshot = Snapshot::TryReadAppSnapshot(unit_url); + Dart_Handle result; + if (loading_unit_snapshot != nullptr) { + isolate_group_data->AddLoadingUnit(loading_unit_snapshot); + const uint8_t* isolate_snapshot_data = nullptr; + const uint8_t* isolate_snapshot_instructions = nullptr; + const uint8_t* ignore_vm_snapshot_data; + const uint8_t* ignore_vm_snapshot_instructions; + loading_unit_snapshot->SetBuffers( + &ignore_vm_snapshot_data, &ignore_vm_snapshot_instructions, + &isolate_snapshot_data, &isolate_snapshot_instructions); + result = Dart_DeferredLoadComplete(loading_unit_id, isolate_snapshot_data, + isolate_snapshot_instructions); + if (Dart_IsApiError(result)) { + result = + Dart_DeferredLoadCompleteError(loading_unit_id, Dart_GetError(result), + /*transient*/ false); + } + } else { + char* error_message = Utils::SCreate("Failed to load %s", unit_url); + result = Dart_DeferredLoadCompleteError(loading_unit_id, error_message, + /*transient*/ false); + free(error_message); + } + + free(unit_url); + return result; +} + void Loader::InitOnce() { } diff --git a/runtime/bin/loader.h b/runtime/bin/loader.h index f4715e91dac..a9f436d7930 100644 --- a/runtime/bin/loader.h +++ b/runtime/bin/loader.h @@ -26,6 +26,7 @@ class Loader { static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library, Dart_Handle url); + static Dart_Handle DeferredLoadHandler(intptr_t loading_unit_id); static void InitOnce(); diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc index 25e7c2b4543..c2303d37948 100644 --- a/runtime/bin/main.cc +++ b/runtime/bin/main.cc @@ -297,6 +297,8 @@ static Dart_Isolate IsolateSetupHelper(Dart_Isolate isolate, // isolates in the group. Dart_Handle result = Dart_SetLibraryTagHandler(Loader::LibraryTagHandler); CHECK_RESULT(result); + result = Dart_SetDeferredLoadHandler(Loader::DeferredLoadHandler); + CHECK_RESULT(result); auto isolate_data = reinterpret_cast(Dart_IsolateData(isolate)); @@ -555,6 +557,8 @@ static Dart_Isolate CreateAndSetupServiceIsolate(const char* script_uri, Dart_Handle result = Dart_SetLibraryTagHandler(Loader::LibraryTagHandler); CHECK_RESULT(result); + result = Dart_SetDeferredLoadHandler(Loader::DeferredLoadHandler); + CHECK_RESULT(result); // Load embedder specific bits and return. if (!VmService::Setup( diff --git a/runtime/bin/snapshot_utils.cc b/runtime/bin/snapshot_utils.cc index 4390d242c34..2adc48ebdd7 100644 --- a/runtime/bin/snapshot_utils.cc +++ b/runtime/bin/snapshot_utils.cc @@ -304,15 +304,9 @@ static AppSnapshot* TryReadAppSnapshotDynamicLibrary(const char* script_name) { const uint8_t* vm_data_buffer = reinterpret_cast( Extensions::ResolveSymbol(library, kVmSnapshotDataCSymbol)); - if (vm_data_buffer == NULL) { - FATAL1("Failed to resolve symbol '%s'\n", kVmSnapshotDataCSymbol); - } const uint8_t* vm_instructions_buffer = reinterpret_cast( Extensions::ResolveSymbol(library, kVmSnapshotInstructionsCSymbol)); - if (vm_instructions_buffer == NULL) { - FATAL1("Failed to resolve symbol '%s'\n", kVmSnapshotInstructionsCSymbol); - } const uint8_t* isolate_data_buffer = reinterpret_cast( Extensions::ResolveSymbol(library, kIsolateSnapshotDataCSymbol)); diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h index db78c769f3a..8c6afd44a72 100644 --- a/runtime/include/dart_api.h +++ b/runtime/include/dart_api.h @@ -3028,6 +3028,59 @@ typedef Dart_Handle (*Dart_LibraryTagHandler)( DART_EXPORT Dart_Handle Dart_SetLibraryTagHandler(Dart_LibraryTagHandler handler); +/** + * Handles deferred loading requests. When this handler is invoked, it should + * eventually load the deferred loading unit with the given id and call + * Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError. It is + * recommended that the loading occur asynchronously, but it is permitted to + * call Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError before the + * handler returns. + * + * If an error is returned, it will be propogated through + * `prefix.loadLibrary()`. This is useful for synchronous + * implementations, which must propogate any unwind errors from + * Dart_DeferredLoadComplete or Dart_DeferredLoadComplete. Otherwise the handler + * should return a non-error such as `Dart_Null()`. + */ +typedef Dart_Handle (*Dart_DeferredLoadHandler)(intptr_t loading_unit_id); + +/** + * Sets the deferred load handler for the current isolate. This handler is + * used to handle loading deferred imports in an AppJIT or AppAOT program. + */ +DART_EXPORT Dart_Handle +Dart_SetDeferredLoadHandler(Dart_DeferredLoadHandler handler); + +/** + * Notifies the VM that a deferred load completed successfully. This function + * will eventually cause the corresponding `prefix.loadLibrary()` futures to + * complete. + * + * Requires the current isolate to be the same current isolate during the + * invocation of the Dart_DeferredLoadHandler. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_DeferredLoadComplete(intptr_t loading_unit_id, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions); + +/** + * Notifies the VM that a deferred load failed. This function + * will eventually cause the corresponding `prefix.loadLibrary()` futures to + * complete with an error. + * + * If `transient` is true, future invocations of `prefix.loadLibrary()` will + * trigger new load requests. If false, futures invocation will complete with + * the same error. + * + * Requires the current isolate to be the same current isolate during the + * invocation of the Dart_DeferredLoadHandler. + */ +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_DeferredLoadCompleteError(intptr_t loading_unit_id, + const char* error_message, + bool transient); + /** * Canonicalizes a url with respect to some library. * @@ -3522,9 +3575,15 @@ Dart_LoadTypeFeedback(uint8_t* buffer, intptr_t buffer_length); */ DART_EXPORT Dart_Handle Dart_Precompile(); +typedef void (*Dart_CreateLoadingUnitCallback)( + void* callback_data, + intptr_t loading_unit_id, + void** write_callback_data, + void** write_debug_callback_data); typedef void (*Dart_StreamingWriteCallback)(void* callback_data, const uint8_t* buffer, intptr_t size); +typedef void (*Dart_StreamingCloseCallback)(void* callback_data); // On Darwin systems, 'dlsym' adds an '_' to the beginning of the symbol name. // Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual @@ -3580,6 +3639,13 @@ Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, void* callback_data, bool stripped, void* debug_callback_data); +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsAssemblies( + Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool stripped, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback); /** * Creates a precompiled snapshot. @@ -3613,6 +3679,12 @@ Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback, void* callback_data, bool stripped, void* debug_callback_data); +DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle +Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool stripped, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback); /** * Like Dart_CreateAppAOTSnapshotAsAssembly, but only includes diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc index 04afec92c9c..7b86301f803 100644 --- a/runtime/lib/object.cc +++ b/runtime/lib/object.cc @@ -10,6 +10,7 @@ #include "vm/heap/heap.h" #include "vm/native_entry.h" #include "vm/object.h" +#include "vm/object_store.h" #include "vm/stack_frame.h" #include "vm/symbols.h" @@ -209,6 +210,36 @@ DEFINE_NATIVE_ENTRY(LibraryPrefix_setLoaded, 0, 1) { return Instance::null(); } +DEFINE_NATIVE_ENTRY(LibraryPrefix_loadingUnit, 0, 1) { + const LibraryPrefix& prefix = + LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0)); + const Library& target = Library::Handle(zone, prefix.GetLibrary(0)); + const LoadingUnit& unit = LoadingUnit::Handle(zone, target.loading_unit()); + return Smi::New(unit.IsNull() ? LoadingUnit::kIllegalId : unit.id()); +} + +DEFINE_NATIVE_ENTRY(LibraryPrefix_issueLoad, 0, 1) { + const Smi& id = Smi::CheckedHandle(zone, arguments->NativeArgAt(0)); + Array& units = Array::Handle(zone, isolate->object_store()->loading_units()); + if (units.IsNull()) { + // Not actually split. + const Library& lib = Library::Handle(zone, Library::CoreLibrary()); + const String& sel = String::Handle(zone, String::New("_completeLoads")); + const Function& func = + Function::Handle(zone, lib.LookupFunctionAllowPrivate(sel)); + ASSERT(!func.IsNull()); + const Array& args = Array::Handle(zone, Array::New(3)); + args.SetAt(0, id); + args.SetAt(1, String::Handle(zone)); + args.SetAt(2, Bool::Get(false)); + return DartEntry::InvokeFunction(func, args); + } + ASSERT(id.Value() != LoadingUnit::kIllegalId); + LoadingUnit& unit = LoadingUnit::Handle(zone); + unit ^= units.At(id.Value()); + return unit.IssueLoad(); +} + DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0, 0) { #if defined(ARCH_IS_64_BIT) return Bool::True().raw(); diff --git a/runtime/tests/vm/dart/incompatible_loading_unit_1.dart b/runtime/tests/vm/dart/incompatible_loading_unit_1.dart new file mode 100644 index 00000000000..35b3947662b --- /dev/null +++ b/runtime/tests/vm/dart/incompatible_loading_unit_1.dart @@ -0,0 +1,10 @@ +// 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. + +import "incompatible_loading_unit_1_deferred.dart" deferred as lib; + +main() async { + await lib.loadLibrary(); + lib.foo(); +} diff --git a/runtime/tests/vm/dart/incompatible_loading_unit_1_deferred.dart b/runtime/tests/vm/dart/incompatible_loading_unit_1_deferred.dart new file mode 100644 index 00000000000..c0b9a034b96 --- /dev/null +++ b/runtime/tests/vm/dart/incompatible_loading_unit_1_deferred.dart @@ -0,0 +1,7 @@ +// 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. + +void foo() { + print("One!"); +} diff --git a/runtime/tests/vm/dart/incompatible_loading_unit_2.dart b/runtime/tests/vm/dart/incompatible_loading_unit_2.dart new file mode 100644 index 00000000000..7a352f6ce5d --- /dev/null +++ b/runtime/tests/vm/dart/incompatible_loading_unit_2.dart @@ -0,0 +1,10 @@ +// 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. + +import "incompatible_loading_unit_2_deferred.dart" deferred as lib; + +main() async { + await lib.loadLibrary(); + lib.foo(); +} diff --git a/runtime/tests/vm/dart/incompatible_loading_unit_2_deferred.dart b/runtime/tests/vm/dart/incompatible_loading_unit_2_deferred.dart new file mode 100644 index 00000000000..2dc3b7a15f6 --- /dev/null +++ b/runtime/tests/vm/dart/incompatible_loading_unit_2_deferred.dart @@ -0,0 +1,7 @@ +// 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. + +void foo() { + print("Two!"); +} diff --git a/runtime/tests/vm/dart/incompatible_loading_unit_test.dart b/runtime/tests/vm/dart/incompatible_loading_unit_test.dart new file mode 100644 index 00000000000..8231f0069e4 --- /dev/null +++ b/runtime/tests/vm/dart/incompatible_loading_unit_test.dart @@ -0,0 +1,97 @@ +// 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. + +import "dart:convert"; +import "dart:io"; + +import "package:expect/expect.dart"; +import "package:path/path.dart" as path; + +import "use_flag_test_helper.dart"; + +main(List args) async { + if (!isAOTRuntime) { + return; // Running in JIT: AOT binaries not available. + } + + if (Platform.isAndroid) { + return; // SDK tree not available on the test device. + } + + // These are the tools we need to be available to run on a given platform: + if (!File(platformDill).existsSync()) { + throw "Cannot run test as $platformDill does not exist"; + } + if (!await testExecutable(genSnapshot)) { + throw "Cannot run test as $genSnapshot not available"; + } + + await withTempDir("incompatible-loading-unit-test", (String tempDir) async { + final source1 = path.join( + sdkDir, "runtime/tests/vm/dart_2/incompatible_loading_unit_1.dart"); + final source2 = path.join( + sdkDir, "runtime/tests/vm/dart_2/incompatible_loading_unit_2.dart"); + final dill1 = path.join(tempDir, "incompatible_loading_unit_1.dart.dill"); + final dill2 = path.join(tempDir, "incompatible_loading_unit_2.dart.dill"); + final snapshot1 = path.join(tempDir, "incompatible_loading_unit_1.so"); + final snapshot2 = path.join(tempDir, "incompatible_loading_unit_2.so"); + final manifest1 = path.join(tempDir, "incompatible_loading_unit_1.txt"); + final manifest2 = path.join(tempDir, "incompatible_loading_unit_2.txt"); + final deferredSnapshot1 = snapshot1 + "-2.part.so"; + final deferredSnapshot2 = snapshot2 + "-2.part.so"; + + // Compile source to kernel. + await run(genKernel, [ + "--aot", + "--platform=$platformDill", + "-o", + dill1, + source1, + ]); + await run(genKernel, [ + "--aot", + "--platform=$platformDill", + "-o", + dill2, + source2, + ]); + + // Compile kernel to ELF. + await run(genSnapshot, [ + "--snapshot-kind=app-aot-elf", + "--use-bare-instructions=false", + "--elf=$snapshot1", + "--loading-unit-manifest=$manifest1", + dill1, + ]); + var manifest = jsonDecode(await new File(manifest1).readAsString()); + Expect.equals(2, manifest["loadingUnits"].length); + Expect.isTrue(await new File(deferredSnapshot1).exists()); + + await run(genSnapshot, [ + "--snapshot-kind=app-aot-elf", + "--use-bare-instructions=false", + "--elf=$snapshot2", + "--loading-unit-manifest=$manifest2", + dill2, + ]); + manifest = jsonDecode(await new File(manifest1).readAsString()); + Expect.equals(2, manifest["loadingUnits"].length); + Expect.isTrue(await new File(deferredSnapshot2).exists()); + + // Works when used normally. + var lines = await runOutput(aotRuntime, [snapshot1]); + Expect.listEquals(["One!"], lines); + + lines = await runOutput(aotRuntime, [snapshot2]); + Expect.listEquals(["Two!"], lines); + + // Fails gracefully when mixing snapshot parts. + await new File(deferredSnapshot2).rename(deferredSnapshot1); + lines = await runError(aotRuntime, [snapshot1]); + Expect.equals( + "DeferredLoadException: 'Deferred loading unit is from a different program than the main loading unit'", + lines[1]); + }); +} diff --git a/runtime/tests/vm/dart/use_flag_test_helper.dart b/runtime/tests/vm/dart/use_flag_test_helper.dart index e9f9737c056..d6854aca139 100644 --- a/runtime/tests/vm/dart/use_flag_test_helper.dart +++ b/runtime/tests/vm/dart/use_flag_test_helper.dart @@ -146,7 +146,7 @@ Future run(String executable, List args) async { } } -Future> runOutput(String executable, List args) async { +Future> runOutput(String executable, List args) async { final result = await runHelper(executable, args); if (result.exitCode != 0) { @@ -160,7 +160,7 @@ Future> runOutput(String executable, List args) async { .toList(); } -Future> runError(String executable, List args) async { +Future> runError(String executable, List args) async { final result = await runHelper(executable, args); if (result.exitCode == 0) { diff --git a/runtime/tests/vm/dart_2/incompatible_loading_unit_1.dart b/runtime/tests/vm/dart_2/incompatible_loading_unit_1.dart new file mode 100644 index 00000000000..35b3947662b --- /dev/null +++ b/runtime/tests/vm/dart_2/incompatible_loading_unit_1.dart @@ -0,0 +1,10 @@ +// 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. + +import "incompatible_loading_unit_1_deferred.dart" deferred as lib; + +main() async { + await lib.loadLibrary(); + lib.foo(); +} diff --git a/runtime/tests/vm/dart_2/incompatible_loading_unit_1_deferred.dart b/runtime/tests/vm/dart_2/incompatible_loading_unit_1_deferred.dart new file mode 100644 index 00000000000..c0b9a034b96 --- /dev/null +++ b/runtime/tests/vm/dart_2/incompatible_loading_unit_1_deferred.dart @@ -0,0 +1,7 @@ +// 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. + +void foo() { + print("One!"); +} diff --git a/runtime/tests/vm/dart_2/incompatible_loading_unit_2.dart b/runtime/tests/vm/dart_2/incompatible_loading_unit_2.dart new file mode 100644 index 00000000000..7a352f6ce5d --- /dev/null +++ b/runtime/tests/vm/dart_2/incompatible_loading_unit_2.dart @@ -0,0 +1,10 @@ +// 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. + +import "incompatible_loading_unit_2_deferred.dart" deferred as lib; + +main() async { + await lib.loadLibrary(); + lib.foo(); +} diff --git a/runtime/tests/vm/dart_2/incompatible_loading_unit_2_deferred.dart b/runtime/tests/vm/dart_2/incompatible_loading_unit_2_deferred.dart new file mode 100644 index 00000000000..2dc3b7a15f6 --- /dev/null +++ b/runtime/tests/vm/dart_2/incompatible_loading_unit_2_deferred.dart @@ -0,0 +1,7 @@ +// 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. + +void foo() { + print("Two!"); +} diff --git a/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart b/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart new file mode 100644 index 00000000000..8231f0069e4 --- /dev/null +++ b/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart @@ -0,0 +1,97 @@ +// 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. + +import "dart:convert"; +import "dart:io"; + +import "package:expect/expect.dart"; +import "package:path/path.dart" as path; + +import "use_flag_test_helper.dart"; + +main(List args) async { + if (!isAOTRuntime) { + return; // Running in JIT: AOT binaries not available. + } + + if (Platform.isAndroid) { + return; // SDK tree not available on the test device. + } + + // These are the tools we need to be available to run on a given platform: + if (!File(platformDill).existsSync()) { + throw "Cannot run test as $platformDill does not exist"; + } + if (!await testExecutable(genSnapshot)) { + throw "Cannot run test as $genSnapshot not available"; + } + + await withTempDir("incompatible-loading-unit-test", (String tempDir) async { + final source1 = path.join( + sdkDir, "runtime/tests/vm/dart_2/incompatible_loading_unit_1.dart"); + final source2 = path.join( + sdkDir, "runtime/tests/vm/dart_2/incompatible_loading_unit_2.dart"); + final dill1 = path.join(tempDir, "incompatible_loading_unit_1.dart.dill"); + final dill2 = path.join(tempDir, "incompatible_loading_unit_2.dart.dill"); + final snapshot1 = path.join(tempDir, "incompatible_loading_unit_1.so"); + final snapshot2 = path.join(tempDir, "incompatible_loading_unit_2.so"); + final manifest1 = path.join(tempDir, "incompatible_loading_unit_1.txt"); + final manifest2 = path.join(tempDir, "incompatible_loading_unit_2.txt"); + final deferredSnapshot1 = snapshot1 + "-2.part.so"; + final deferredSnapshot2 = snapshot2 + "-2.part.so"; + + // Compile source to kernel. + await run(genKernel, [ + "--aot", + "--platform=$platformDill", + "-o", + dill1, + source1, + ]); + await run(genKernel, [ + "--aot", + "--platform=$platformDill", + "-o", + dill2, + source2, + ]); + + // Compile kernel to ELF. + await run(genSnapshot, [ + "--snapshot-kind=app-aot-elf", + "--use-bare-instructions=false", + "--elf=$snapshot1", + "--loading-unit-manifest=$manifest1", + dill1, + ]); + var manifest = jsonDecode(await new File(manifest1).readAsString()); + Expect.equals(2, manifest["loadingUnits"].length); + Expect.isTrue(await new File(deferredSnapshot1).exists()); + + await run(genSnapshot, [ + "--snapshot-kind=app-aot-elf", + "--use-bare-instructions=false", + "--elf=$snapshot2", + "--loading-unit-manifest=$manifest2", + dill2, + ]); + manifest = jsonDecode(await new File(manifest1).readAsString()); + Expect.equals(2, manifest["loadingUnits"].length); + Expect.isTrue(await new File(deferredSnapshot2).exists()); + + // Works when used normally. + var lines = await runOutput(aotRuntime, [snapshot1]); + Expect.listEquals(["One!"], lines); + + lines = await runOutput(aotRuntime, [snapshot2]); + Expect.listEquals(["Two!"], lines); + + // Fails gracefully when mixing snapshot parts. + await new File(deferredSnapshot2).rename(deferredSnapshot1); + lines = await runError(aotRuntime, [snapshot1]); + Expect.equals( + "DeferredLoadException: 'Deferred loading unit is from a different program than the main loading unit'", + lines[1]); + }); +} diff --git a/runtime/tests/vm/dart_2/use_flag_test_helper.dart b/runtime/tests/vm/dart_2/use_flag_test_helper.dart index fe9c511f3bd..24f0687ab73 100644 --- a/runtime/tests/vm/dart_2/use_flag_test_helper.dart +++ b/runtime/tests/vm/dart_2/use_flag_test_helper.dart @@ -144,7 +144,7 @@ Future run(String executable, List args) async { } } -Future> runOutput(String executable, List args) async { +Future> runOutput(String executable, List args) async { final result = await runHelper(executable, args); if (result.exitCode != 0) { @@ -158,7 +158,7 @@ Future> runOutput(String executable, List args) async { .toList(); } -Future> runError(String executable, List args) async { +Future> runError(String executable, List args) async { final result = await runHelper(executable, args); if (result.exitCode == 0) { diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h index a8056290c6a..00f2e1c95ab 100644 --- a/runtime/vm/bootstrap_natives.h +++ b/runtime/vm/bootstrap_natives.h @@ -33,6 +33,8 @@ namespace dart { V(Type_equality, 2) \ V(LibraryPrefix_isLoaded, 1) \ V(LibraryPrefix_setLoaded, 1) \ + V(LibraryPrefix_loadingUnit, 1) \ + V(LibraryPrefix_issueLoad, 1) \ V(Identical_comparison, 2) \ V(Integer_bitAndFromInteger, 2) \ V(Integer_bitOrFromInteger, 2) \ diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc index 0e14e1bb337..637cf2ee4cd 100644 --- a/runtime/vm/clustered_snapshot.cc +++ b/runtime/vm/clustered_snapshot.cc @@ -155,8 +155,10 @@ class ClassSerializationCluster : public SerializationCluster { ClassPtr cls = Class::RawCast(object); intptr_t class_id = cls->ptr()->id_; - // Classes expected to be dropped by the precompiler should not be traced. - ASSERT(class_id != kIllegalCid); + if (class_id == kIllegalCid) { + // Classes expected to be dropped by the precompiler should not be traced. + s->UnexpectedObject(cls, "Class with illegal cid"); + } if (class_id < kNumPredefinedCids) { // These classes are allocated by Object::Init or Object::InitOnce, so the // deserializer must find them in the class table instead of allocating @@ -1522,6 +1524,8 @@ class CodeSerializationCluster : public SerializationCluster { CodePtr code = Code::RawCast(object); objects_.Add(code); + s->InCurrentLoadingUnit(code, /*record*/ true); + if (!(s->kind() == Snapshot::kFullAOT && FLAG_use_bare_instructions)) { s->Push(code->ptr()->object_pool_); } @@ -1529,10 +1533,14 @@ class CodeSerializationCluster : public SerializationCluster { s->Push(code->ptr()->exception_handlers_); s->Push(code->ptr()->pc_descriptors_); s->Push(code->ptr()->catch_entry_); - s->Push(code->ptr()->compressed_stackmaps_); + if (s->InCurrentLoadingUnit(code->ptr()->compressed_stackmaps_)) { + s->Push(code->ptr()->compressed_stackmaps_); + } if (!FLAG_precompiled_mode || !FLAG_dwarf_stack_traces_mode) { s->Push(code->ptr()->inlined_id_to_function_); - s->Push(code->ptr()->code_source_map_); + if (s->InCurrentLoadingUnit(code->ptr()->code_source_map_)) { + s->Push(code->ptr()->code_source_map_); + } } if (s->kind() == Snapshot::kFullJIT) { s->Push(code->ptr()->deopt_info_array_); @@ -1626,13 +1634,21 @@ class CodeSerializationCluster : public SerializationCluster { WriteField(code, exception_handlers_); WriteField(code, pc_descriptors_); WriteField(code, catch_entry_); - WriteField(code, compressed_stackmaps_); + if (s->InCurrentLoadingUnit(code->ptr()->compressed_stackmaps_)) { + WriteField(code, compressed_stackmaps_); + } else { + WriteFieldValue(compressed_stackmaps_, CompressedStackMaps::null()); + } if (FLAG_precompiled_mode && FLAG_dwarf_stack_traces_mode) { WriteFieldValue(inlined_id_to_function_, Array::null()); WriteFieldValue(code_source_map_, CodeSourceMap::null()); } else { WriteField(code, inlined_id_to_function_); - WriteField(code, code_source_map_); + if (s->InCurrentLoadingUnit(code->ptr()->code_source_map_)) { + WriteField(code, code_source_map_); + } else { + WriteFieldValue(code_source_map_, CodeSourceMap::null()); + } } if (kind == Snapshot::kFullJIT) { WriteField(code, deopt_info_array_); @@ -2988,7 +3004,7 @@ class LoadingUnitDeserializationCluster : public DeserializationCluster { unit->ptr()->base_objects_ = Array::null(); unit->ptr()->id_ = d->Read(); unit->ptr()->loaded_ = false; - unit->ptr()->load_issued_ = false; + unit->ptr()->load_outstanding_ = false; } } }; @@ -5181,6 +5197,24 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) { #endif // !DART_PRECOMPILED_RUNTIME } +bool Serializer::InCurrentLoadingUnit(ObjectPtr obj, bool record) { + if (loading_units_ == nullptr) return true; + + intptr_t unit_id = heap_->GetLoadingUnit(obj); + if (unit_id == WeakTable::kNoValue) { + // Not found in early assignment. Conservatively choose the root. + // TODO(41974): Are these always type testing stubs? + unit_id = LoadingUnit::kRootId; + } + if (unit_id != current_loading_unit_id_) { + if (record) { + (*loading_units_)[unit_id]->AddDeferredObject(obj); + } + return false; + } + return true; +} + #if !defined(DART_PRECOMPILED_RUNTIME) void Serializer::WriteInstructions(InstructionsPtr instr, uint32_t unchecked_offset, @@ -5188,6 +5222,11 @@ void Serializer::WriteInstructions(InstructionsPtr instr, intptr_t index) { ASSERT(code != Code::null()); + if (!InCurrentLoadingUnit(code)) { + Write(0); + return; + } + const intptr_t offset = image_writer_->GetTextOffsetFor(instr, code); #if defined(DART_PRECOMPILER) if (profile_writer_ != nullptr) { @@ -5402,44 +5441,6 @@ void Serializer::Serialize() { Trace(stack_.RemoveLast()); } - intptr_t code_order_length = 0; -#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32) - if ((kind_ == Snapshot::kFullAOT) && FLAG_use_bare_instructions) { - auto code_objects = - static_cast(clusters_by_cid_[kCodeCid]) - ->discovered_objects(); - - GrowableArray writer_commands; - RelocateCodeObjects(vm_, code_objects, &writer_commands); - image_writer_->PrepareForSerialization(&writer_commands); - - // We permute the code objects in the [CodeSerializationCluster] so they - // will arrive in the order in which the [Code]'s instructions will be in - // memory at AOT runtime. - GrowableArray code_order; - RawCodeSet code_set; - for (auto& command : writer_commands) { - if (command.op == ImageWriterCommand::InsertInstructionOfCode) { - CodePtr code = command.insert_instruction_of_code.code; - ASSERT(!code_set.HasKey(code)); - code_set.Insert(code); - code_order.Add(code); - code_order_length++; - } - } - for (CodePtr code : *code_objects) { - if (!code_set.HasKey(code)) { - code_set.Insert(code); - code_order.Add(code); - } - } - RELEASE_ASSERT(code_order.length() == code_objects->length()); - for (intptr_t i = 0; i < code_objects->length(); ++i) { - (*code_objects)[i] = code_order[i]; - } - } -#endif // defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32) - intptr_t num_clusters = 0; for (intptr_t cid = 1; cid < num_cids_; cid++) { SerializationCluster* cluster = clusters_by_cid_[cid]; @@ -5448,6 +5449,8 @@ void Serializer::Serialize() { } } + intptr_t code_order_length = PrepareCodeOrder(); + #if defined(DART_PRECOMPILER) // Before we finalize the count of written objects, pick canonical versions // of WSR objects that will be serialized and then remove any non-serialized @@ -5488,6 +5491,12 @@ void Serializer::Serialize() { // We should have assigned a ref to every object we pushed. ASSERT((next_ref_index_ - 1) == num_objects); + if (loading_units_ != nullptr) { + LoadingUnitSerializationData* unit = + (*loading_units_)[current_loading_unit_id_]; + unit->set_num_objects(num_objects); + } + #if defined(DART_PRECOMPILER) // When writing snapshot profile, we want to retain some of the program // structure information (e.g. information about libraries, classes and @@ -5508,6 +5517,48 @@ void Serializer::Serialize() { } } } + +intptr_t Serializer::PrepareCodeOrder() { + intptr_t code_order_length = 0; +#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32) + if ((kind_ == Snapshot::kFullAOT) && FLAG_use_bare_instructions) { + auto code_objects = + static_cast(clusters_by_cid_[kCodeCid]) + ->discovered_objects(); + + GrowableArray writer_commands; + RelocateCodeObjects(vm_, code_objects, &writer_commands); + image_writer_->PrepareForSerialization(&writer_commands); + + // We permute the code objects in the x[CodeSerializationCluster] so they + // will arrive in the order in which the [Code]'s instructions will be in + // memory at AOT runtime. + GrowableArray code_order; + RawCodeSet code_set; + for (auto& command : writer_commands) { + if (command.op == ImageWriterCommand::InsertInstructionOfCode) { + CodePtr code = command.insert_instruction_of_code.code; + ASSERT(!code_set.HasKey(code)); + code_set.Insert(code); + code_order.Add(code); + code_order_length++; + } + } + for (CodePtr code : *code_objects) { + if (!code_set.HasKey(code)) { + code_set.Insert(code); + code_order.Add(code); + } + } + RELEASE_ASSERT(code_order.length() == code_objects->length()); + for (intptr_t i = 0; i < code_objects->length(); ++i) { + (*code_objects)[i] = code_order[i]; + } + } +#endif // defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32) + return code_order_length; +} + #endif // !defined(DART_PRECOMPILED_RUNTIME) #if defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME) @@ -5633,7 +5684,8 @@ void Serializer::WriteDispatchTable(const Array& entries) { void Serializer::PrintSnapshotSizes() { #if !defined(DART_PRECOMPILED_RUNTIME) if (FLAG_print_snapshot_sizes_verbose) { - OS::PrintErr(" Cluster Objs Size Fraction Cumulative\n"); + OS::PrintErr( + " Cluster Objs Size Fraction Cumulative\n"); GrowableArray clusters_by_size; for (intptr_t cid = 1; cid < num_cids_; cid++) { SerializationCluster* cluster = clusters_by_cid_[cid]; @@ -5677,7 +5729,7 @@ void Serializer::PrintSnapshotSizes() { SerializationCluster* cluster = clusters_by_size[i]; double fraction = static_cast(cluster->size()) / total_size; cumulative_fraction += fraction; - OS::PrintErr("%20s %6" Pd " %8" Pd " %lf %lf\n", cluster->name(), + OS::PrintErr("%25s %6" Pd " %8" Pd " %lf %lf\n", cluster->name(), cluster->num_objects(), cluster->size(), fraction, cumulative_fraction); } @@ -5820,8 +5872,8 @@ void Serializer::WriteProgramSnapshot(intptr_t num_base_objects, } } else { // Base objects carried over from WriteVMSnapshot. - num_base_objects_ += num_base_objects; - next_ref_index_ += num_base_objects; + num_base_objects_ = num_base_objects; + next_ref_index_ = num_base_objects + 1; } // Push roots. @@ -5892,7 +5944,56 @@ void Serializer::WriteProgramSnapshot(intptr_t num_base_objects, PrintSnapshotSizes(); - heap_->ResetObjectIdTable(); + // TODO(rmacnak): This also carries over object ids from loading units that + // aren't dominators. It would be more robust to remember the written objects + // in each loading and re-assign objects when setting up the base objects. + // Then a reference to a non-dominating object would produce an error instead + // of corruption. + if (kind() != Snapshot::kFullAOT) { + heap_->ResetObjectIdTable(); + } +} + +void Serializer::WriteUnitSnapshot(LoadingUnitSerializationData* unit, + uint32_t program_hash) { + Write(program_hash); + + NoSafepointScope no_safepoint; + + intptr_t num_base_objects = unit->parent()->num_objects(); + ASSERT(num_base_objects != 0); + num_base_objects_ = num_base_objects; + next_ref_index_ = num_base_objects + 1; + + intptr_t num_deferred_objects = unit->deferred_objects()->length(); + for (intptr_t i = 0; i < num_deferred_objects; i++) { + const Object* deferred_object = (*unit->deferred_objects())[i]; + ASSERT(deferred_object->IsCode()); + CodePtr code = static_cast(deferred_object->raw()); + Push(code->ptr()->compressed_stackmaps_); + Push(code->ptr()->code_source_map_); + } + + Serialize(); + + Write(num_deferred_objects); + for (intptr_t i = 0; i < num_deferred_objects; i++) { + const Object* deferred_object = (*unit->deferred_objects())[i]; + ASSERT(deferred_object->IsCode()); + CodePtr code = static_cast(deferred_object->raw()); + WriteRootRef(code, "deferred-code"); + WriteInstructions(code->ptr()->instructions_, + code->ptr()->unchecked_offset_, code, -1); + WriteRootRef(code->ptr()->compressed_stackmaps_, "deferred-code"); + WriteRootRef(code->ptr()->code_source_map_, "deferred-code"); + } + + FlushBytesWrittenToRoot(); + object_currently_writing_.stream_start_ = stream_.Position(); + +#if defined(DEBUG) + Write(kSectionMarker); +#endif } #endif // !defined(DART_PRECOMPILED_RUNTIME) @@ -6297,8 +6398,15 @@ void Deserializer::ReadInstructions(CodePtr code, #endif const uint32_t offset = Read(); - InstructionsPtr instr = image_reader_->GetInstructionsAt(offset); - uint32_t unchecked_offset = ReadUnsigned(); + InstructionsPtr instr; + uint32_t unchecked_offset; + if (offset == 0) { + instr = StubCode::NotLoaded().instructions(); + unchecked_offset = 0; + } else { + instr = image_reader_->GetInstructionsAt(offset); + unchecked_offset = ReadUnsigned(); + } code->ptr()->instructions_ = instr; #if defined(DART_PRECOMPILED_RUNTIME) @@ -6531,12 +6639,86 @@ void Deserializer::ReadProgramSnapshot(ObjectStore* object_store) { for (intptr_t i = 0; i < num_clusters_; i++) { clusters_[i]->PostLoad(refs, kind_, zone_); } + const Array& units = Array::Handle(isolate->object_store()->loading_units()); + if (!units.IsNull()) { + LoadingUnit& unit = LoadingUnit::Handle(); + unit ^= units.At(LoadingUnit::kRootId); + unit.set_base_objects(refs); + } isolate->isolate_object_store()->PreallocateObjects(); // Setup native resolver for bootstrap impl. Bootstrap::SetupNativeResolver(); } +ApiErrorPtr Deserializer::ReadUnitSnapshot(const LoadingUnit& unit) { + Array& units = + Array::Handle(thread()->isolate()->object_store()->loading_units()); + uint32_t main_program_hash = Smi::Value(Smi::RawCast(units.At(0))); + uint32_t unit_program_hash = Read(); + if (main_program_hash != unit_program_hash) { + return ApiError::New( + String::Handle(String::New("Deferred loading unit is from a different " + "program than the main loading unit"))); + } + + Array& refs = Array::Handle(); + Prepare(); + + { + NoSafepointScope no_safepoint; + HeapLocker hl(thread(), heap_->old_space()); + + // N.B.: Skipping index 0 because ref 0 is illegal. + const Array& base_objects = + Array::Handle(LoadingUnit::Handle(unit.parent()).base_objects()); + for (intptr_t i = 1; i < base_objects.Length(); i++) { + AddBaseObject(base_objects.At(i)); + } + + Deserialize(); + + intptr_t num_deferred = Read(); + for (intptr_t i = 0; i < num_deferred; i++) { + CodePtr code = static_cast(ReadRef()); + ReadInstructions(code, -1, -1); + if (code->ptr()->owner_->IsFunction()) { + FunctionPtr func = static_cast(code->ptr()->owner_); + uword entry_point = code->ptr()->entry_point_; + ASSERT(entry_point != 0); + func->ptr()->entry_point_ = entry_point; + uword unchecked_entry_point = code->ptr()->unchecked_entry_point_; + ASSERT(unchecked_entry_point != 0); + func->ptr()->unchecked_entry_point_ = unchecked_entry_point; + } + code->ptr()->compressed_stackmaps_ = + static_cast(ReadRef()); + code->ptr()->code_source_map_ = static_cast(ReadRef()); + } + +#if defined(DEBUG) + int32_t section_marker = Read(); + ASSERT(section_marker == kSectionMarker); +#endif + + refs = refs_; + refs_ = NULL; + } + +#if defined(DEBUG) + Isolate* isolate = thread()->isolate(); + isolate->ValidateClassTable(); + isolate->heap()->Verify(); +#endif + + for (intptr_t i = 0; i < num_clusters_; i++) { + clusters_[i]->PostLoad(refs, kind_, zone_); + } + unit.set_base_objects(refs); + + return ApiError::null(); +} + #if !defined(DART_PRECOMPILED_RUNTIME) FullSnapshotWriter::FullSnapshotWriter(Snapshot::Kind kind, uint8_t** vm_snapshot_data_buffer, @@ -6611,12 +6793,16 @@ intptr_t FullSnapshotWriter::WriteVMSnapshot() { return num_objects; } -void FullSnapshotWriter::WriteProgramSnapshot(intptr_t num_base_objects) { +void FullSnapshotWriter::WriteProgramSnapshot( + intptr_t num_base_objects, + GrowableArray* units) { TIMELINE_DURATION(thread(), Isolate, "WriteProgramSnapshot"); Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_, kInitialSize, isolate_image_writer_, /*vm=*/false, profile_writer_); + serializer.set_loading_units(units); + serializer.set_current_loading_unit_id(LoadingUnit::kRootId); ObjectStore* object_store = isolate()->object_store(); ASSERT(object_store != NULL); @@ -6652,7 +6838,43 @@ void FullSnapshotWriter::WriteProgramSnapshot(intptr_t num_base_objects) { isolate_snapshot_size_ = serializer.bytes_written(); } -void FullSnapshotWriter::WriteFullSnapshot() { +void FullSnapshotWriter::WriteUnitSnapshot( + GrowableArray* units, + LoadingUnitSerializationData* unit, + uint32_t program_hash) { + TIMELINE_DURATION(thread(), Isolate, "WriteUnitSnapshot"); + + Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_, + kInitialSize, isolate_image_writer_, /*vm=*/false, + profile_writer_); + serializer.set_loading_units(units); + serializer.set_current_loading_unit_id(unit->id()); + + serializer.ReserveHeader(); + serializer.WriteVersionAndFeatures(false); + serializer.WriteUnitSnapshot(unit, program_hash); + serializer.FillHeader(serializer.kind()); + clustered_isolate_size_ = serializer.bytes_written(); + + if (Snapshot::IncludesCode(kind_)) { + isolate_image_writer_->SetProfileWriter(profile_writer_); + isolate_image_writer_->Write(serializer.stream(), false); +#if defined(DART_PRECOMPILER) + isolate_image_writer_->DumpStatistics(); +#endif + + mapped_data_size_ += isolate_image_writer_->data_size(); + mapped_text_size_ += isolate_image_writer_->text_size(); + isolate_image_writer_->ResetOffsets(); + isolate_image_writer_->ClearProfileWriter(); + } + + // The clustered part + the direct mapped data part. + isolate_snapshot_size_ = serializer.bytes_written(); +} + +void FullSnapshotWriter::WriteFullSnapshot( + GrowableArray* data) { intptr_t num_base_objects; if (vm_snapshot_data_buffer() != NULL) { num_base_objects = WriteVMSnapshot(); @@ -6662,7 +6884,7 @@ void FullSnapshotWriter::WriteFullSnapshot() { } if (isolate_snapshot_data_buffer() != NULL) { - WriteProgramSnapshot(num_base_objects); + WriteProgramSnapshot(num_base_objects, data); } if (FLAG_print_snapshot_sizes) { @@ -6921,6 +7143,49 @@ ApiErrorPtr FullSnapshotReader::ReadProgramSnapshot() { auto object_store = thread_->isolate()->object_store(); deserializer.ReadProgramSnapshot(object_store); + PatchGlobalObjectPool(); + InitializeBSS(); + + return ApiError::null(); +} + +ApiErrorPtr FullSnapshotReader::ReadUnitSnapshot(const LoadingUnit& unit) { + SnapshotHeaderReader header_reader(kind_, buffer_, size_); + intptr_t offset = 0; + char* error = + header_reader.VerifyVersionAndFeatures(thread_->isolate(), &offset); + if (error != nullptr) { + return ConvertToApiError(error); + } + + Deserializer deserializer(thread_, kind_, buffer_, size_, data_image_, + instructions_image_, offset); + ApiErrorPtr api_error = deserializer.VerifyImageAlignment(); + if (api_error != ApiError::null()) { + return api_error; + } + + if (Snapshot::IncludesCode(kind_)) { + ASSERT(data_image_ != NULL); + thread_->isolate()->SetupImagePage(data_image_, + /* is_executable */ false); + ASSERT(instructions_image_ != NULL); + thread_->isolate()->SetupImagePage(instructions_image_, + /* is_executable */ true); + } + + api_error = deserializer.ReadUnitSnapshot(unit); + if (api_error != ApiError::null()) { + return api_error; + } + + PatchGlobalObjectPool(); + InitializeBSS(); + + return ApiError::null(); +} + +void FullSnapshotReader::PatchGlobalObjectPool() { #if defined(DART_PRECOMPILED_RUNTIME) if (FLAG_use_bare_instructions) { // By default, every switchable call site will put (ic_data, code) into the @@ -6934,7 +7199,8 @@ ApiErrorPtr FullSnapshotReader::ReadProgramSnapshot() { // existing UnlinkedCall entries in the object pool to be it's entrypoint. auto zone = thread_->zone(); const auto& pool = ObjectPool::Handle( - zone, ObjectPool::RawCast(object_store->global_object_pool())); + zone, ObjectPool::RawCast( + thread_->isolate()->object_store()->global_object_pool())); auto& entry = Object::Handle(zone); auto& smi = Smi::Handle(zone); for (intptr_t i = 0; i < pool.Length(); i++) { @@ -6956,7 +7222,11 @@ ApiErrorPtr FullSnapshotReader::ReadProgramSnapshot() { } } } +#endif // defined(DART_PRECOMPILED_RUNTIME) +} +void FullSnapshotReader::InitializeBSS() { +#if defined(DART_PRECOMPILED_RUNTIME) // Initialize entries in the isolate portion of the BSS segment. ASSERT(Snapshot::IncludesCode(kind_)); Image image(instructions_image_); @@ -6968,8 +7238,6 @@ ApiErrorPtr FullSnapshotReader::ReadProgramSnapshot() { BSS::Initialize(thread_, bss_start, /*vm=*/false); } #endif // defined(DART_PRECOMPILED_RUNTIME) - - return ApiError::null(); } } // namespace dart diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h index bd6740e7eba..252be23394d 100644 --- a/runtime/vm/clustered_snapshot.h +++ b/runtime/vm/clustered_snapshot.h @@ -26,13 +26,6 @@ namespace dart { -// Forward declarations. -class Serializer; -class Deserializer; -class ObjectStore; -class ImageWriter; -class ImageReader; - // For full snapshots, we use a clustered snapshot format that trades longer // serialization time for faster deserialization time and smaller snapshots. // Objects are clustered by class to allow writing type information once per @@ -50,6 +43,37 @@ class ImageReader; // require the graph has been fully loaded, such as rehashing, though most // clusters do not require fixups. +// Forward declarations. +class Serializer; +class Deserializer; +class ObjectStore; +class ImageWriter; +class ImageReader; + +class LoadingUnitSerializationData : public ZoneAllocated { + public: + LoadingUnitSerializationData(intptr_t id, + LoadingUnitSerializationData* parent) + : id_(id), parent_(parent), deferred_objects_(), num_objects_(0) {} + + intptr_t id() const { return id_; } + LoadingUnitSerializationData* parent() const { return parent_; } + intptr_t num_objects() const { return num_objects_; } + void set_num_objects(intptr_t value) { num_objects_ = value; } + void AddDeferredObject(ObjectPtr obj) { + deferred_objects_.Add(&Object::ZoneHandle(obj)); + } + GrowableArray* deferred_objects() { + return &deferred_objects_; + } + + private: + intptr_t id_; + LoadingUnitSerializationData* parent_; + GrowableArray deferred_objects_; + intptr_t num_objects_; +}; + class SerializationCluster : public ZoneAllocated { public: explicit SerializationCluster(const char* name) @@ -142,7 +166,8 @@ class Serializer : public ThreadStackResource { // Reference value for objects that either are not reachable from the roots or // should never have a reference in the snapshot (because they are dropped, // for example). Should be the default value for Heap::GetObjectId. - static const intptr_t kUnreachableReference = 0; + static constexpr intptr_t kUnreachableReference = 0; + COMPILE_ASSERT(kUnreachableReference == WeakTable::kNoValue); static constexpr bool IsReachableReference(intptr_t ref) { return ref == kUnallocatedReference || IsAllocatedReference(ref); @@ -163,6 +188,8 @@ class Serializer : public ThreadStackResource { intptr_t WriteVMSnapshot(const Array& symbols); void WriteProgramSnapshot(intptr_t num_base_objects, ObjectStore* object_store); + void WriteUnitSnapshot(LoadingUnitSerializationData* unit, + uint32_t program_hash); void AddVMIsolateBaseObjects(); @@ -384,6 +411,7 @@ class Serializer : public ThreadStackResource { void TraceDataOffset(uint32_t offset); intptr_t GetDataSize() const; + intptr_t PrepareCodeOrder(); void WriteDispatchTable(const Array& entries); Snapshot::Kind kind() const { return kind_; } @@ -399,6 +427,14 @@ class Serializer : public ThreadStackResource { // Returns true if [obj] has an artificial profile node associated with it. bool CreateArtificalNodeIfNeeded(ObjectPtr obj); + bool InCurrentLoadingUnit(ObjectPtr obj, bool record = false); + void set_loading_units(GrowableArray* units) { + loading_units_ = units; + } + void set_current_loading_unit_id(intptr_t id) { + current_loading_unit_id_ = id; + } + private: static const char* ReadOnlyObjectType(intptr_t cid); @@ -481,6 +517,9 @@ class Serializer : public ThreadStackResource { IntMap deduped_instructions_sources_; #endif + intptr_t current_loading_unit_id_ = 0; + GrowableArray* loading_units_ = nullptr; + DISALLOW_IMPLICIT_CONSTRUCTORS(Serializer); }; @@ -577,6 +616,7 @@ class Deserializer : public ThreadStackResource { ApiErrorPtr VerifyImageAlignment(); void ReadProgramSnapshot(ObjectStore* object_store); + ApiErrorPtr ReadUnitSnapshot(const LoadingUnit& unit); void ReadVMSnapshot(); void AddVMIsolateBaseObjects(); @@ -720,7 +760,11 @@ class FullSnapshotWriter { Heap* heap() const { return isolate()->heap(); } // Writes a full snapshot of the program(VM isolate, regular isolate group). - void WriteFullSnapshot(); + void WriteFullSnapshot( + GrowableArray* data = nullptr); + void WriteUnitSnapshot(GrowableArray* units, + LoadingUnitSerializationData* unit, + uint32_t program_hash); intptr_t VmIsolateSnapshotSize() const { return vm_isolate_snapshot_size_; } intptr_t IsolateSnapshotSize() const { return isolate_snapshot_size_; } @@ -730,7 +774,8 @@ class FullSnapshotWriter { intptr_t WriteVMSnapshot(); // Writes a full snapshot of regular Dart isolate group. - void WriteProgramSnapshot(intptr_t num_base_objects); + void WriteProgramSnapshot(intptr_t num_base_objects, + GrowableArray* data); Thread* thread_; Snapshot::Kind kind_; @@ -762,9 +807,12 @@ class FullSnapshotReader { ApiErrorPtr ReadVMSnapshot(); ApiErrorPtr ReadProgramSnapshot(); + ApiErrorPtr ReadUnitSnapshot(const LoadingUnit& unit); private: ApiErrorPtr ConvertToApiError(char* message); + void PatchGlobalObjectPool(); + void InitializeBSS(); Snapshot::Kind kind_; Thread* thread_; diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc index a57c5d5dd7b..c604a7cc7f8 100644 --- a/runtime/vm/compiler/aot/precompiler.cc +++ b/runtime/vm/compiler/aot/precompiler.cc @@ -900,7 +900,7 @@ void Precompiler::AddConstObject(const class Instance& instance) { return; } - const Class& cls = Class::Handle(Z, instance.clazz()); + Class& cls = Class::Handle(Z, instance.clazz()); AddInstantiatedClass(cls); if (instance.IsClosure()) { @@ -918,6 +918,17 @@ void Precompiler::AddConstObject(const class Instance& instance) { return; } + if (instance.IsLibraryPrefix()) { + const LibraryPrefix& prefix = LibraryPrefix::Cast(instance); + ASSERT(prefix.is_deferred_load()); + const Library& target = Library::Handle(Z, prefix.GetLibrary(0)); + cls = target.toplevel_class(); + if (!classes_to_retain_.HasKey(&cls)) { + classes_to_retain_.Insert(&Class::ZoneHandle(Z, cls.raw())); + } + return; + } + // Can't ask immediate objects if they're canonical. if (instance.IsSmi()) return; diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h index 0b184a2cddd..0f16b0f2cb4 100644 --- a/runtime/vm/compiler/runtime_offsets_extracted.h +++ b/runtime/vm/compiler/runtime_offsets_extracted.h @@ -198,9 +198,9 @@ static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4; static constexpr dart::compiler::target::word Thread_AllocateArray_entry_point_offset = 376; static constexpr dart::compiler::target::word Thread_active_exception_offset = - 712; -static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = 716; +static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = + 720; static constexpr dart::compiler::target::word Thread_array_write_barrier_code_offset = 128; static constexpr dart::compiler::target::word @@ -225,7 +225,7 @@ static constexpr dart::compiler::target::word Thread_allocate_object_slow_entry_point_offset = 292; static constexpr dart::compiler::target::word Thread_allocate_object_slow_stub_offset = 200; -static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 748; +static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 752; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = 96; static constexpr dart::compiler::target::word @@ -238,7 +238,7 @@ static constexpr dart::compiler::target::word Thread_call_to_runtime_entry_point_offset = 272; static constexpr dart::compiler::target::word Thread_call_to_runtime_stub_offset = 148; -static constexpr dart::compiler::target::word Thread_dart_stream_offset = 756; +static constexpr dart::compiler::target::word Thread_dart_stream_offset = 760; static constexpr dart::compiler::target::word Thread_dispatch_table_array_offset = 48; static constexpr dart::compiler::target::word Thread_optimize_entry_offset = @@ -256,7 +256,7 @@ static constexpr dart::compiler::target::word Thread_end_offset = 56; static constexpr dart::compiler::target::word Thread_enter_safepoint_stub_offset = 252; static constexpr dart::compiler::target::word Thread_execution_state_offset = - 732; + 736; static constexpr dart::compiler::target::word Thread_exit_safepoint_stub_offset = 256; static constexpr dart::compiler::target::word @@ -276,7 +276,7 @@ static constexpr dart::compiler::target::word Thread_float_not_address_offset = static constexpr dart::compiler::target::word Thread_float_zerow_address_offset = 372; static constexpr dart::compiler::target::word Thread_global_object_pool_offset = - 720; + 724; static constexpr dart::compiler::target::word Thread_interpret_call_entry_point_offset = 340; static constexpr dart::compiler::target::word @@ -284,7 +284,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_invoke_dart_code_stub_offset = 140; static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset = - 744; + 748; static constexpr dart::compiler::target::word Thread_isolate_offset = 44; static constexpr dart::compiler::target::word Thread_field_table_values_offset = 68; @@ -323,11 +323,11 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_object_null_offset = 112; static constexpr dart::compiler::target::word Thread_predefined_symbols_address_offset = 344; -static constexpr dart::compiler::target::word Thread_resume_pc_offset = 724; +static constexpr dart::compiler::target::word Thread_resume_pc_offset = 728; static constexpr dart::compiler::target::word - Thread_saved_shadow_call_stack_offset = 728; + Thread_saved_shadow_call_stack_offset = 732; static constexpr dart::compiler::target::word Thread_safepoint_state_offset = - 736; + 740; static constexpr dart::compiler::target::word Thread_slow_type_test_stub_offset = 244; static constexpr dart::compiler::target::word @@ -360,7 +360,7 @@ static constexpr dart::compiler::target::word Thread_write_barrier_entry_point_offset = 264; static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset = 40; -static constexpr dart::compiler::target::word Thread_callback_code_offset = 740; +static constexpr dart::compiler::target::word Thread_callback_code_offset = 744; static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8; static constexpr dart::compiler::target::word TwoByteString_data_offset = 12; static constexpr dart::compiler::target::word Type_arguments_offset = 16; @@ -402,7 +402,7 @@ static constexpr dart::compiler::target::word Code_entry_point_offset[] = { 4, 12, 8, 16}; static constexpr dart::compiler::target::word Thread_write_barrier_wrappers_thread_offset[] = { - 680, 684, 688, 692, 696, -1, 700, -1, 704, 708, -1, -1, -1, -1, -1, -1}; + 684, 688, 692, 696, 700, -1, 704, -1, 708, 712, -1, -1, -1, -1, -1, -1}; static constexpr dart::compiler::target::word ApiError_InstanceSize = 8; static constexpr dart::compiler::target::word Array_InstanceSize = 12; static constexpr dart::compiler::target::word Array_header_size = 12; @@ -693,9 +693,9 @@ static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8; static constexpr dart::compiler::target::word Thread_AllocateArray_entry_point_offset = 736; static constexpr dart::compiler::target::word Thread_active_exception_offset = - 1432; -static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = 1440; +static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = + 1448; static constexpr dart::compiler::target::word Thread_array_write_barrier_code_offset = 240; static constexpr dart::compiler::target::word @@ -721,7 +721,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_allocate_object_slow_stub_offset = 384; static constexpr dart::compiler::target::word Thread_api_top_scope_offset = - 1504; + 1512; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = 192; static constexpr dart::compiler::target::word @@ -734,7 +734,7 @@ static constexpr dart::compiler::target::word Thread_call_to_runtime_entry_point_offset = 528; static constexpr dart::compiler::target::word Thread_call_to_runtime_stub_offset = 280; -static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1520; +static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1528; static constexpr dart::compiler::target::word Thread_dispatch_table_array_offset = 96; static constexpr dart::compiler::target::word Thread_optimize_entry_offset = @@ -752,7 +752,7 @@ static constexpr dart::compiler::target::word Thread_end_offset = 112; static constexpr dart::compiler::target::word Thread_enter_safepoint_stub_offset = 488; static constexpr dart::compiler::target::word Thread_execution_state_offset = - 1472; + 1480; static constexpr dart::compiler::target::word Thread_exit_safepoint_stub_offset = 496; static constexpr dart::compiler::target::word @@ -772,7 +772,7 @@ static constexpr dart::compiler::target::word Thread_float_not_address_offset = static constexpr dart::compiler::target::word Thread_float_zerow_address_offset = 728; static constexpr dart::compiler::target::word Thread_global_object_pool_offset = - 1448; + 1456; static constexpr dart::compiler::target::word Thread_interpret_call_entry_point_offset = 664; static constexpr dart::compiler::target::word @@ -780,7 +780,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_invoke_dart_code_stub_offset = 264; static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset = - 1496; + 1504; static constexpr dart::compiler::target::word Thread_isolate_offset = 88; static constexpr dart::compiler::target::word Thread_field_table_values_offset = 136; @@ -819,11 +819,11 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_object_null_offset = 208; static constexpr dart::compiler::target::word Thread_predefined_symbols_address_offset = 672; -static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1456; +static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1464; static constexpr dart::compiler::target::word - Thread_saved_shadow_call_stack_offset = 1464; + Thread_saved_shadow_call_stack_offset = 1472; static constexpr dart::compiler::target::word Thread_safepoint_state_offset = - 1480; + 1488; static constexpr dart::compiler::target::word Thread_slow_type_test_stub_offset = 472; static constexpr dart::compiler::target::word @@ -857,7 +857,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset = 80; static constexpr dart::compiler::target::word Thread_callback_code_offset = - 1488; + 1496; static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 16; static constexpr dart::compiler::target::word TwoByteString_data_offset = 16; @@ -900,8 +900,8 @@ static constexpr dart::compiler::target::word Code_entry_point_offset[] = { 8, 24, 16, 32}; static constexpr dart::compiler::target::word Thread_write_barrier_wrappers_thread_offset[] = { - 1344, 1352, 1360, 1368, -1, -1, 1376, 1384, - 1392, 1400, 1408, -1, 1416, 1424, -1, -1}; + 1352, 1360, 1368, 1376, -1, -1, 1384, 1392, + 1400, 1408, 1416, -1, 1424, 1432, -1, -1}; static constexpr dart::compiler::target::word ApiError_InstanceSize = 16; static constexpr dart::compiler::target::word Array_InstanceSize = 24; static constexpr dart::compiler::target::word Array_header_size = 24; @@ -1190,9 +1190,9 @@ static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4; static constexpr dart::compiler::target::word Thread_AllocateArray_entry_point_offset = 376; static constexpr dart::compiler::target::word Thread_active_exception_offset = - 680; -static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = 684; +static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = + 688; static constexpr dart::compiler::target::word Thread_array_write_barrier_code_offset = 128; static constexpr dart::compiler::target::word @@ -1217,7 +1217,7 @@ static constexpr dart::compiler::target::word Thread_allocate_object_slow_entry_point_offset = 292; static constexpr dart::compiler::target::word Thread_allocate_object_slow_stub_offset = 200; -static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 716; +static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 720; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = 96; static constexpr dart::compiler::target::word @@ -1230,7 +1230,7 @@ static constexpr dart::compiler::target::word Thread_call_to_runtime_entry_point_offset = 272; static constexpr dart::compiler::target::word Thread_call_to_runtime_stub_offset = 148; -static constexpr dart::compiler::target::word Thread_dart_stream_offset = 724; +static constexpr dart::compiler::target::word Thread_dart_stream_offset = 728; static constexpr dart::compiler::target::word Thread_dispatch_table_array_offset = 48; static constexpr dart::compiler::target::word Thread_optimize_entry_offset = @@ -1248,7 +1248,7 @@ static constexpr dart::compiler::target::word Thread_end_offset = 56; static constexpr dart::compiler::target::word Thread_enter_safepoint_stub_offset = 252; static constexpr dart::compiler::target::word Thread_execution_state_offset = - 700; + 704; static constexpr dart::compiler::target::word Thread_exit_safepoint_stub_offset = 256; static constexpr dart::compiler::target::word @@ -1268,7 +1268,7 @@ static constexpr dart::compiler::target::word Thread_float_not_address_offset = static constexpr dart::compiler::target::word Thread_float_zerow_address_offset = 372; static constexpr dart::compiler::target::word Thread_global_object_pool_offset = - 688; + 692; static constexpr dart::compiler::target::word Thread_interpret_call_entry_point_offset = 340; static constexpr dart::compiler::target::word @@ -1276,7 +1276,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_invoke_dart_code_stub_offset = 140; static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset = - 712; + 716; static constexpr dart::compiler::target::word Thread_isolate_offset = 44; static constexpr dart::compiler::target::word Thread_field_table_values_offset = 68; @@ -1315,11 +1315,11 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_object_null_offset = 112; static constexpr dart::compiler::target::word Thread_predefined_symbols_address_offset = 344; -static constexpr dart::compiler::target::word Thread_resume_pc_offset = 692; +static constexpr dart::compiler::target::word Thread_resume_pc_offset = 696; static constexpr dart::compiler::target::word - Thread_saved_shadow_call_stack_offset = 696; + Thread_saved_shadow_call_stack_offset = 700; static constexpr dart::compiler::target::word Thread_safepoint_state_offset = - 704; + 708; static constexpr dart::compiler::target::word Thread_slow_type_test_stub_offset = 244; static constexpr dart::compiler::target::word @@ -1352,7 +1352,7 @@ static constexpr dart::compiler::target::word Thread_write_barrier_entry_point_offset = 264; static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset = 40; -static constexpr dart::compiler::target::word Thread_callback_code_offset = 708; +static constexpr dart::compiler::target::word Thread_callback_code_offset = 712; static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8; static constexpr dart::compiler::target::word TwoByteString_data_offset = 12; static constexpr dart::compiler::target::word Type_arguments_offset = 16; @@ -1682,9 +1682,9 @@ static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8; static constexpr dart::compiler::target::word Thread_AllocateArray_entry_point_offset = 736; static constexpr dart::compiler::target::word Thread_active_exception_offset = - 1504; -static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = 1512; +static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = + 1520; static constexpr dart::compiler::target::word Thread_array_write_barrier_code_offset = 240; static constexpr dart::compiler::target::word @@ -1710,7 +1710,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_allocate_object_slow_stub_offset = 384; static constexpr dart::compiler::target::word Thread_api_top_scope_offset = - 1576; + 1584; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = 192; static constexpr dart::compiler::target::word @@ -1723,7 +1723,7 @@ static constexpr dart::compiler::target::word Thread_call_to_runtime_entry_point_offset = 528; static constexpr dart::compiler::target::word Thread_call_to_runtime_stub_offset = 280; -static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1592; +static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1600; static constexpr dart::compiler::target::word Thread_dispatch_table_array_offset = 96; static constexpr dart::compiler::target::word Thread_optimize_entry_offset = @@ -1741,7 +1741,7 @@ static constexpr dart::compiler::target::word Thread_end_offset = 112; static constexpr dart::compiler::target::word Thread_enter_safepoint_stub_offset = 488; static constexpr dart::compiler::target::word Thread_execution_state_offset = - 1544; + 1552; static constexpr dart::compiler::target::word Thread_exit_safepoint_stub_offset = 496; static constexpr dart::compiler::target::word @@ -1761,7 +1761,7 @@ static constexpr dart::compiler::target::word Thread_float_not_address_offset = static constexpr dart::compiler::target::word Thread_float_zerow_address_offset = 728; static constexpr dart::compiler::target::word Thread_global_object_pool_offset = - 1520; + 1528; static constexpr dart::compiler::target::word Thread_interpret_call_entry_point_offset = 664; static constexpr dart::compiler::target::word @@ -1769,7 +1769,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_invoke_dart_code_stub_offset = 264; static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset = - 1568; + 1576; static constexpr dart::compiler::target::word Thread_isolate_offset = 88; static constexpr dart::compiler::target::word Thread_field_table_values_offset = 136; @@ -1808,11 +1808,11 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_object_null_offset = 208; static constexpr dart::compiler::target::word Thread_predefined_symbols_address_offset = 672; -static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1528; +static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1536; static constexpr dart::compiler::target::word - Thread_saved_shadow_call_stack_offset = 1536; + Thread_saved_shadow_call_stack_offset = 1544; static constexpr dart::compiler::target::word Thread_safepoint_state_offset = - 1552; + 1560; static constexpr dart::compiler::target::word Thread_slow_type_test_stub_offset = 472; static constexpr dart::compiler::target::word @@ -1846,7 +1846,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset = 80; static constexpr dart::compiler::target::word Thread_callback_code_offset = - 1560; + 1568; static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 16; static constexpr dart::compiler::target::word TwoByteString_data_offset = 16; @@ -1889,9 +1889,9 @@ static constexpr dart::compiler::target::word Code_entry_point_offset[] = { 8, 24, 16, 32}; static constexpr dart::compiler::target::word Thread_write_barrier_wrappers_thread_offset[] = { - 1344, 1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, - 1432, 1440, 1448, 1456, -1, -1, -1, -1, 1464, 1472, -1, - -1, 1480, 1488, 1496, -1, -1, -1, -1, -1, -1}; + 1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432, + 1440, 1448, 1456, 1464, -1, -1, -1, -1, 1472, 1480, -1, + -1, 1488, 1496, 1504, -1, -1, -1, -1, -1, -1}; static constexpr dart::compiler::target::word ApiError_InstanceSize = 16; static constexpr dart::compiler::target::word Array_InstanceSize = 24; static constexpr dart::compiler::target::word Array_header_size = 24; @@ -2179,9 +2179,9 @@ static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4; static constexpr dart::compiler::target::word Thread_AllocateArray_entry_point_offset = 376; static constexpr dart::compiler::target::word Thread_active_exception_offset = - 712; -static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = 716; +static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = + 720; static constexpr dart::compiler::target::word Thread_array_write_barrier_code_offset = 128; static constexpr dart::compiler::target::word @@ -2206,7 +2206,7 @@ static constexpr dart::compiler::target::word Thread_allocate_object_slow_entry_point_offset = 292; static constexpr dart::compiler::target::word Thread_allocate_object_slow_stub_offset = 200; -static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 748; +static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 752; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = 96; static constexpr dart::compiler::target::word @@ -2219,7 +2219,7 @@ static constexpr dart::compiler::target::word Thread_call_to_runtime_entry_point_offset = 272; static constexpr dart::compiler::target::word Thread_call_to_runtime_stub_offset = 148; -static constexpr dart::compiler::target::word Thread_dart_stream_offset = 756; +static constexpr dart::compiler::target::word Thread_dart_stream_offset = 760; static constexpr dart::compiler::target::word Thread_dispatch_table_array_offset = 48; static constexpr dart::compiler::target::word Thread_optimize_entry_offset = @@ -2237,7 +2237,7 @@ static constexpr dart::compiler::target::word Thread_end_offset = 56; static constexpr dart::compiler::target::word Thread_enter_safepoint_stub_offset = 252; static constexpr dart::compiler::target::word Thread_execution_state_offset = - 732; + 736; static constexpr dart::compiler::target::word Thread_exit_safepoint_stub_offset = 256; static constexpr dart::compiler::target::word @@ -2257,7 +2257,7 @@ static constexpr dart::compiler::target::word Thread_float_not_address_offset = static constexpr dart::compiler::target::word Thread_float_zerow_address_offset = 372; static constexpr dart::compiler::target::word Thread_global_object_pool_offset = - 720; + 724; static constexpr dart::compiler::target::word Thread_interpret_call_entry_point_offset = 340; static constexpr dart::compiler::target::word @@ -2265,7 +2265,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_invoke_dart_code_stub_offset = 140; static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset = - 744; + 748; static constexpr dart::compiler::target::word Thread_isolate_offset = 44; static constexpr dart::compiler::target::word Thread_field_table_values_offset = 68; @@ -2304,11 +2304,11 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_object_null_offset = 112; static constexpr dart::compiler::target::word Thread_predefined_symbols_address_offset = 344; -static constexpr dart::compiler::target::word Thread_resume_pc_offset = 724; +static constexpr dart::compiler::target::word Thread_resume_pc_offset = 728; static constexpr dart::compiler::target::word - Thread_saved_shadow_call_stack_offset = 728; + Thread_saved_shadow_call_stack_offset = 732; static constexpr dart::compiler::target::word Thread_safepoint_state_offset = - 736; + 740; static constexpr dart::compiler::target::word Thread_slow_type_test_stub_offset = 244; static constexpr dart::compiler::target::word @@ -2341,7 +2341,7 @@ static constexpr dart::compiler::target::word Thread_write_barrier_entry_point_offset = 264; static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset = 40; -static constexpr dart::compiler::target::word Thread_callback_code_offset = 740; +static constexpr dart::compiler::target::word Thread_callback_code_offset = 744; static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8; static constexpr dart::compiler::target::word TwoByteString_data_offset = 12; static constexpr dart::compiler::target::word Type_arguments_offset = 16; @@ -2380,7 +2380,7 @@ static constexpr dart::compiler::target::word Code_entry_point_offset[] = { 4, 12, 8, 16}; static constexpr dart::compiler::target::word Thread_write_barrier_wrappers_thread_offset[] = { - 680, 684, 688, 692, 696, -1, 700, -1, 704, 708, -1, -1, -1, -1, -1, -1}; + 684, 688, 692, 696, 700, -1, 704, -1, 708, 712, -1, -1, -1, -1, -1, -1}; static constexpr dart::compiler::target::word ApiError_InstanceSize = 8; static constexpr dart::compiler::target::word Array_InstanceSize = 12; static constexpr dart::compiler::target::word Array_header_size = 12; @@ -2668,9 +2668,9 @@ static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8; static constexpr dart::compiler::target::word Thread_AllocateArray_entry_point_offset = 736; static constexpr dart::compiler::target::word Thread_active_exception_offset = - 1432; -static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = 1440; +static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = + 1448; static constexpr dart::compiler::target::word Thread_array_write_barrier_code_offset = 240; static constexpr dart::compiler::target::word @@ -2696,7 +2696,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_allocate_object_slow_stub_offset = 384; static constexpr dart::compiler::target::word Thread_api_top_scope_offset = - 1504; + 1512; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = 192; static constexpr dart::compiler::target::word @@ -2709,7 +2709,7 @@ static constexpr dart::compiler::target::word Thread_call_to_runtime_entry_point_offset = 528; static constexpr dart::compiler::target::word Thread_call_to_runtime_stub_offset = 280; -static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1520; +static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1528; static constexpr dart::compiler::target::word Thread_dispatch_table_array_offset = 96; static constexpr dart::compiler::target::word Thread_optimize_entry_offset = @@ -2727,7 +2727,7 @@ static constexpr dart::compiler::target::word Thread_end_offset = 112; static constexpr dart::compiler::target::word Thread_enter_safepoint_stub_offset = 488; static constexpr dart::compiler::target::word Thread_execution_state_offset = - 1472; + 1480; static constexpr dart::compiler::target::word Thread_exit_safepoint_stub_offset = 496; static constexpr dart::compiler::target::word @@ -2747,7 +2747,7 @@ static constexpr dart::compiler::target::word Thread_float_not_address_offset = static constexpr dart::compiler::target::word Thread_float_zerow_address_offset = 728; static constexpr dart::compiler::target::word Thread_global_object_pool_offset = - 1448; + 1456; static constexpr dart::compiler::target::word Thread_interpret_call_entry_point_offset = 664; static constexpr dart::compiler::target::word @@ -2755,7 +2755,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_invoke_dart_code_stub_offset = 264; static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset = - 1496; + 1504; static constexpr dart::compiler::target::word Thread_isolate_offset = 88; static constexpr dart::compiler::target::word Thread_field_table_values_offset = 136; @@ -2794,11 +2794,11 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_object_null_offset = 208; static constexpr dart::compiler::target::word Thread_predefined_symbols_address_offset = 672; -static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1456; +static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1464; static constexpr dart::compiler::target::word - Thread_saved_shadow_call_stack_offset = 1464; + Thread_saved_shadow_call_stack_offset = 1472; static constexpr dart::compiler::target::word Thread_safepoint_state_offset = - 1480; + 1488; static constexpr dart::compiler::target::word Thread_slow_type_test_stub_offset = 472; static constexpr dart::compiler::target::word @@ -2832,7 +2832,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset = 80; static constexpr dart::compiler::target::word Thread_callback_code_offset = - 1488; + 1496; static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 16; static constexpr dart::compiler::target::word TwoByteString_data_offset = 16; @@ -2872,8 +2872,8 @@ static constexpr dart::compiler::target::word Code_entry_point_offset[] = { 8, 24, 16, 32}; static constexpr dart::compiler::target::word Thread_write_barrier_wrappers_thread_offset[] = { - 1344, 1352, 1360, 1368, -1, -1, 1376, 1384, - 1392, 1400, 1408, -1, 1416, 1424, -1, -1}; + 1352, 1360, 1368, 1376, -1, -1, 1384, 1392, + 1400, 1408, 1416, -1, 1424, 1432, -1, -1}; static constexpr dart::compiler::target::word ApiError_InstanceSize = 16; static constexpr dart::compiler::target::word Array_InstanceSize = 24; static constexpr dart::compiler::target::word Array_header_size = 24; @@ -3159,9 +3159,9 @@ static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4; static constexpr dart::compiler::target::word Thread_AllocateArray_entry_point_offset = 376; static constexpr dart::compiler::target::word Thread_active_exception_offset = - 680; -static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = 684; +static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = + 688; static constexpr dart::compiler::target::word Thread_array_write_barrier_code_offset = 128; static constexpr dart::compiler::target::word @@ -3186,7 +3186,7 @@ static constexpr dart::compiler::target::word Thread_allocate_object_slow_entry_point_offset = 292; static constexpr dart::compiler::target::word Thread_allocate_object_slow_stub_offset = 200; -static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 716; +static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 720; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = 96; static constexpr dart::compiler::target::word @@ -3199,7 +3199,7 @@ static constexpr dart::compiler::target::word Thread_call_to_runtime_entry_point_offset = 272; static constexpr dart::compiler::target::word Thread_call_to_runtime_stub_offset = 148; -static constexpr dart::compiler::target::word Thread_dart_stream_offset = 724; +static constexpr dart::compiler::target::word Thread_dart_stream_offset = 728; static constexpr dart::compiler::target::word Thread_dispatch_table_array_offset = 48; static constexpr dart::compiler::target::word Thread_optimize_entry_offset = @@ -3217,7 +3217,7 @@ static constexpr dart::compiler::target::word Thread_end_offset = 56; static constexpr dart::compiler::target::word Thread_enter_safepoint_stub_offset = 252; static constexpr dart::compiler::target::word Thread_execution_state_offset = - 700; + 704; static constexpr dart::compiler::target::word Thread_exit_safepoint_stub_offset = 256; static constexpr dart::compiler::target::word @@ -3237,7 +3237,7 @@ static constexpr dart::compiler::target::word Thread_float_not_address_offset = static constexpr dart::compiler::target::word Thread_float_zerow_address_offset = 372; static constexpr dart::compiler::target::word Thread_global_object_pool_offset = - 688; + 692; static constexpr dart::compiler::target::word Thread_interpret_call_entry_point_offset = 340; static constexpr dart::compiler::target::word @@ -3245,7 +3245,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_invoke_dart_code_stub_offset = 140; static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset = - 712; + 716; static constexpr dart::compiler::target::word Thread_isolate_offset = 44; static constexpr dart::compiler::target::word Thread_field_table_values_offset = 68; @@ -3284,11 +3284,11 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_object_null_offset = 112; static constexpr dart::compiler::target::word Thread_predefined_symbols_address_offset = 344; -static constexpr dart::compiler::target::word Thread_resume_pc_offset = 692; +static constexpr dart::compiler::target::word Thread_resume_pc_offset = 696; static constexpr dart::compiler::target::word - Thread_saved_shadow_call_stack_offset = 696; + Thread_saved_shadow_call_stack_offset = 700; static constexpr dart::compiler::target::word Thread_safepoint_state_offset = - 704; + 708; static constexpr dart::compiler::target::word Thread_slow_type_test_stub_offset = 244; static constexpr dart::compiler::target::word @@ -3321,7 +3321,7 @@ static constexpr dart::compiler::target::word Thread_write_barrier_entry_point_offset = 264; static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset = 40; -static constexpr dart::compiler::target::word Thread_callback_code_offset = 708; +static constexpr dart::compiler::target::word Thread_callback_code_offset = 712; static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8; static constexpr dart::compiler::target::word TwoByteString_data_offset = 12; static constexpr dart::compiler::target::word Type_arguments_offset = 16; @@ -3645,9 +3645,9 @@ static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8; static constexpr dart::compiler::target::word Thread_AllocateArray_entry_point_offset = 736; static constexpr dart::compiler::target::word Thread_active_exception_offset = - 1504; -static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = 1512; +static constexpr dart::compiler::target::word Thread_active_stacktrace_offset = + 1520; static constexpr dart::compiler::target::word Thread_array_write_barrier_code_offset = 240; static constexpr dart::compiler::target::word @@ -3673,7 +3673,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_allocate_object_slow_stub_offset = 384; static constexpr dart::compiler::target::word Thread_api_top_scope_offset = - 1576; + 1584; static constexpr dart::compiler::target::word Thread_async_stack_trace_offset = 192; static constexpr dart::compiler::target::word @@ -3686,7 +3686,7 @@ static constexpr dart::compiler::target::word Thread_call_to_runtime_entry_point_offset = 528; static constexpr dart::compiler::target::word Thread_call_to_runtime_stub_offset = 280; -static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1592; +static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1600; static constexpr dart::compiler::target::word Thread_dispatch_table_array_offset = 96; static constexpr dart::compiler::target::word Thread_optimize_entry_offset = @@ -3704,7 +3704,7 @@ static constexpr dart::compiler::target::word Thread_end_offset = 112; static constexpr dart::compiler::target::word Thread_enter_safepoint_stub_offset = 488; static constexpr dart::compiler::target::word Thread_execution_state_offset = - 1544; + 1552; static constexpr dart::compiler::target::word Thread_exit_safepoint_stub_offset = 496; static constexpr dart::compiler::target::word @@ -3724,7 +3724,7 @@ static constexpr dart::compiler::target::word Thread_float_not_address_offset = static constexpr dart::compiler::target::word Thread_float_zerow_address_offset = 728; static constexpr dart::compiler::target::word Thread_global_object_pool_offset = - 1520; + 1528; static constexpr dart::compiler::target::word Thread_interpret_call_entry_point_offset = 664; static constexpr dart::compiler::target::word @@ -3732,7 +3732,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_invoke_dart_code_stub_offset = 264; static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset = - 1568; + 1576; static constexpr dart::compiler::target::word Thread_isolate_offset = 88; static constexpr dart::compiler::target::word Thread_field_table_values_offset = 136; @@ -3771,11 +3771,11 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_object_null_offset = 208; static constexpr dart::compiler::target::word Thread_predefined_symbols_address_offset = 672; -static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1528; +static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1536; static constexpr dart::compiler::target::word - Thread_saved_shadow_call_stack_offset = 1536; + Thread_saved_shadow_call_stack_offset = 1544; static constexpr dart::compiler::target::word Thread_safepoint_state_offset = - 1552; + 1560; static constexpr dart::compiler::target::word Thread_slow_type_test_stub_offset = 472; static constexpr dart::compiler::target::word @@ -3809,7 +3809,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset = 80; static constexpr dart::compiler::target::word Thread_callback_code_offset = - 1560; + 1568; static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 16; static constexpr dart::compiler::target::word TwoByteString_data_offset = 16; @@ -3849,9 +3849,9 @@ static constexpr dart::compiler::target::word Code_entry_point_offset[] = { 8, 24, 16, 32}; static constexpr dart::compiler::target::word Thread_write_barrier_wrappers_thread_offset[] = { - 1344, 1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, - 1432, 1440, 1448, 1456, -1, -1, -1, -1, 1464, 1472, -1, - -1, 1480, 1488, 1496, -1, -1, -1, -1, -1, -1}; + 1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432, + 1440, 1448, 1456, 1464, -1, -1, -1, -1, 1472, 1480, -1, + -1, 1488, 1496, 1504, -1, -1, -1, -1, -1, -1}; static constexpr dart::compiler::target::word ApiError_InstanceSize = 16; static constexpr dart::compiler::target::word Array_InstanceSize = 24; static constexpr dart::compiler::target::word Array_header_size = 24; @@ -4153,9 +4153,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_AllocateArray_entry_point_offset = 376; static constexpr dart::compiler::target::word - AOT_Thread_active_exception_offset = 712; + AOT_Thread_active_exception_offset = 716; static constexpr dart::compiler::target::word - AOT_Thread_active_stacktrace_offset = 716; + AOT_Thread_active_stacktrace_offset = 720; static constexpr dart::compiler::target::word AOT_Thread_array_write_barrier_code_offset = 128; static constexpr dart::compiler::target::word @@ -4181,7 +4181,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_allocate_object_slow_stub_offset = 200; static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset = - 748; + 752; static constexpr dart::compiler::target::word AOT_Thread_async_stack_trace_offset = 96; static constexpr dart::compiler::target::word @@ -4196,7 +4196,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_call_to_runtime_stub_offset = 148; static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset = - 756; + 760; static constexpr dart::compiler::target::word AOT_Thread_dispatch_table_array_offset = 48; static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset = @@ -4215,7 +4215,7 @@ static constexpr dart::compiler::target::word AOT_Thread_end_offset = 56; static constexpr dart::compiler::target::word AOT_Thread_enter_safepoint_stub_offset = 252; static constexpr dart::compiler::target::word - AOT_Thread_execution_state_offset = 732; + AOT_Thread_execution_state_offset = 736; static constexpr dart::compiler::target::word AOT_Thread_exit_safepoint_stub_offset = 256; static constexpr dart::compiler::target::word @@ -4235,7 +4235,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_float_zerow_address_offset = 372; static constexpr dart::compiler::target::word - AOT_Thread_global_object_pool_offset = 720; + AOT_Thread_global_object_pool_offset = 724; static constexpr dart::compiler::target::word AOT_Thread_interpret_call_entry_point_offset = 340; static constexpr dart::compiler::target::word @@ -4243,7 +4243,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_invoke_dart_code_stub_offset = 140; static constexpr dart::compiler::target::word - AOT_Thread_exit_through_ffi_offset = 744; + AOT_Thread_exit_through_ffi_offset = 748; static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 44; static constexpr dart::compiler::target::word AOT_Thread_field_table_values_offset = 68; @@ -4283,11 +4283,11 @@ static constexpr dart::compiler::target::word AOT_Thread_object_null_offset = 112; static constexpr dart::compiler::target::word AOT_Thread_predefined_symbols_address_offset = 344; -static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 724; +static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 728; static constexpr dart::compiler::target::word - AOT_Thread_saved_shadow_call_stack_offset = 728; + AOT_Thread_saved_shadow_call_stack_offset = 732; static constexpr dart::compiler::target::word - AOT_Thread_safepoint_state_offset = 736; + AOT_Thread_safepoint_state_offset = 740; static constexpr dart::compiler::target::word AOT_Thread_slow_type_test_stub_offset = 244; static constexpr dart::compiler::target::word @@ -4323,7 +4323,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_write_barrier_mask_offset = 40; static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset = - 740; + 744; static constexpr dart::compiler::target::word AOT_TimelineStream_enabled_offset = 8; static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset = @@ -4372,7 +4372,7 @@ static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = { 4, 12, 8, 16}; static constexpr dart::compiler::target::word AOT_Thread_write_barrier_wrappers_thread_offset[] = { - 680, 684, 688, 692, 696, -1, 700, -1, 704, 708, -1, -1, -1, -1, -1, -1}; + 684, 688, 692, 696, 700, -1, 704, -1, 708, 712, -1, -1, -1, -1, -1, -1}; static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 8; static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 12; static constexpr dart::compiler::target::word AOT_Array_header_size = 12; @@ -4690,9 +4690,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_AllocateArray_entry_point_offset = 736; static constexpr dart::compiler::target::word - AOT_Thread_active_exception_offset = 1432; + AOT_Thread_active_exception_offset = 1440; static constexpr dart::compiler::target::word - AOT_Thread_active_stacktrace_offset = 1440; + AOT_Thread_active_stacktrace_offset = 1448; static constexpr dart::compiler::target::word AOT_Thread_array_write_barrier_code_offset = 240; static constexpr dart::compiler::target::word @@ -4718,7 +4718,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_allocate_object_slow_stub_offset = 384; static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset = - 1504; + 1512; static constexpr dart::compiler::target::word AOT_Thread_async_stack_trace_offset = 192; static constexpr dart::compiler::target::word @@ -4733,7 +4733,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_call_to_runtime_stub_offset = 280; static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset = - 1520; + 1528; static constexpr dart::compiler::target::word AOT_Thread_dispatch_table_array_offset = 96; static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset = @@ -4752,7 +4752,7 @@ static constexpr dart::compiler::target::word AOT_Thread_end_offset = 112; static constexpr dart::compiler::target::word AOT_Thread_enter_safepoint_stub_offset = 488; static constexpr dart::compiler::target::word - AOT_Thread_execution_state_offset = 1472; + AOT_Thread_execution_state_offset = 1480; static constexpr dart::compiler::target::word AOT_Thread_exit_safepoint_stub_offset = 496; static constexpr dart::compiler::target::word @@ -4772,7 +4772,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_float_zerow_address_offset = 728; static constexpr dart::compiler::target::word - AOT_Thread_global_object_pool_offset = 1448; + AOT_Thread_global_object_pool_offset = 1456; static constexpr dart::compiler::target::word AOT_Thread_interpret_call_entry_point_offset = 664; static constexpr dart::compiler::target::word @@ -4780,7 +4780,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_invoke_dart_code_stub_offset = 264; static constexpr dart::compiler::target::word - AOT_Thread_exit_through_ffi_offset = 1496; + AOT_Thread_exit_through_ffi_offset = 1504; static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88; static constexpr dart::compiler::target::word AOT_Thread_field_table_values_offset = 136; @@ -4821,11 +4821,11 @@ static constexpr dart::compiler::target::word AOT_Thread_object_null_offset = static constexpr dart::compiler::target::word AOT_Thread_predefined_symbols_address_offset = 672; static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = - 1456; + 1464; static constexpr dart::compiler::target::word - AOT_Thread_saved_shadow_call_stack_offset = 1464; + AOT_Thread_saved_shadow_call_stack_offset = 1472; static constexpr dart::compiler::target::word - AOT_Thread_safepoint_state_offset = 1480; + AOT_Thread_safepoint_state_offset = 1488; static constexpr dart::compiler::target::word AOT_Thread_slow_type_test_stub_offset = 472; static constexpr dart::compiler::target::word @@ -4861,7 +4861,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_write_barrier_mask_offset = 80; static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset = - 1488; + 1496; static constexpr dart::compiler::target::word AOT_TimelineStream_enabled_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset = @@ -4910,8 +4910,8 @@ static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = { 8, 24, 16, 32}; static constexpr dart::compiler::target::word AOT_Thread_write_barrier_wrappers_thread_offset[] = { - 1344, 1352, 1360, 1368, -1, -1, 1376, 1384, - 1392, 1400, 1408, -1, 1416, 1424, -1, -1}; + 1352, 1360, 1368, 1376, -1, -1, 1384, 1392, + 1400, 1408, 1416, -1, 1424, 1432, -1, -1}; static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16; static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Array_header_size = 24; @@ -5233,9 +5233,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_AllocateArray_entry_point_offset = 736; static constexpr dart::compiler::target::word - AOT_Thread_active_exception_offset = 1504; + AOT_Thread_active_exception_offset = 1512; static constexpr dart::compiler::target::word - AOT_Thread_active_stacktrace_offset = 1512; + AOT_Thread_active_stacktrace_offset = 1520; static constexpr dart::compiler::target::word AOT_Thread_array_write_barrier_code_offset = 240; static constexpr dart::compiler::target::word @@ -5261,7 +5261,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_allocate_object_slow_stub_offset = 384; static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset = - 1576; + 1584; static constexpr dart::compiler::target::word AOT_Thread_async_stack_trace_offset = 192; static constexpr dart::compiler::target::word @@ -5276,7 +5276,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_call_to_runtime_stub_offset = 280; static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset = - 1592; + 1600; static constexpr dart::compiler::target::word AOT_Thread_dispatch_table_array_offset = 96; static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset = @@ -5295,7 +5295,7 @@ static constexpr dart::compiler::target::word AOT_Thread_end_offset = 112; static constexpr dart::compiler::target::word AOT_Thread_enter_safepoint_stub_offset = 488; static constexpr dart::compiler::target::word - AOT_Thread_execution_state_offset = 1544; + AOT_Thread_execution_state_offset = 1552; static constexpr dart::compiler::target::word AOT_Thread_exit_safepoint_stub_offset = 496; static constexpr dart::compiler::target::word @@ -5315,7 +5315,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_float_zerow_address_offset = 728; static constexpr dart::compiler::target::word - AOT_Thread_global_object_pool_offset = 1520; + AOT_Thread_global_object_pool_offset = 1528; static constexpr dart::compiler::target::word AOT_Thread_interpret_call_entry_point_offset = 664; static constexpr dart::compiler::target::word @@ -5323,7 +5323,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_invoke_dart_code_stub_offset = 264; static constexpr dart::compiler::target::word - AOT_Thread_exit_through_ffi_offset = 1568; + AOT_Thread_exit_through_ffi_offset = 1576; static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88; static constexpr dart::compiler::target::word AOT_Thread_field_table_values_offset = 136; @@ -5364,11 +5364,11 @@ static constexpr dart::compiler::target::word AOT_Thread_object_null_offset = static constexpr dart::compiler::target::word AOT_Thread_predefined_symbols_address_offset = 672; static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = - 1528; + 1536; static constexpr dart::compiler::target::word - AOT_Thread_saved_shadow_call_stack_offset = 1536; + AOT_Thread_saved_shadow_call_stack_offset = 1544; static constexpr dart::compiler::target::word - AOT_Thread_safepoint_state_offset = 1552; + AOT_Thread_safepoint_state_offset = 1560; static constexpr dart::compiler::target::word AOT_Thread_slow_type_test_stub_offset = 472; static constexpr dart::compiler::target::word @@ -5404,7 +5404,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_write_barrier_mask_offset = 80; static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset = - 1560; + 1568; static constexpr dart::compiler::target::word AOT_TimelineStream_enabled_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset = @@ -5453,9 +5453,9 @@ static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = { 8, 24, 16, 32}; static constexpr dart::compiler::target::word AOT_Thread_write_barrier_wrappers_thread_offset[] = { - 1344, 1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, - 1432, 1440, 1448, 1456, -1, -1, -1, -1, 1464, 1472, -1, - -1, 1480, 1488, 1496, -1, -1, -1, -1, -1, -1}; + 1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432, + 1440, 1448, 1456, 1464, -1, -1, -1, -1, 1472, 1480, -1, + -1, 1488, 1496, 1504, -1, -1, -1, -1, -1, -1}; static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16; static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Array_header_size = 24; @@ -5771,9 +5771,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_AllocateArray_entry_point_offset = 376; static constexpr dart::compiler::target::word - AOT_Thread_active_exception_offset = 712; + AOT_Thread_active_exception_offset = 716; static constexpr dart::compiler::target::word - AOT_Thread_active_stacktrace_offset = 716; + AOT_Thread_active_stacktrace_offset = 720; static constexpr dart::compiler::target::word AOT_Thread_array_write_barrier_code_offset = 128; static constexpr dart::compiler::target::word @@ -5799,7 +5799,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_allocate_object_slow_stub_offset = 200; static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset = - 748; + 752; static constexpr dart::compiler::target::word AOT_Thread_async_stack_trace_offset = 96; static constexpr dart::compiler::target::word @@ -5814,7 +5814,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_call_to_runtime_stub_offset = 148; static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset = - 756; + 760; static constexpr dart::compiler::target::word AOT_Thread_dispatch_table_array_offset = 48; static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset = @@ -5833,7 +5833,7 @@ static constexpr dart::compiler::target::word AOT_Thread_end_offset = 56; static constexpr dart::compiler::target::word AOT_Thread_enter_safepoint_stub_offset = 252; static constexpr dart::compiler::target::word - AOT_Thread_execution_state_offset = 732; + AOT_Thread_execution_state_offset = 736; static constexpr dart::compiler::target::word AOT_Thread_exit_safepoint_stub_offset = 256; static constexpr dart::compiler::target::word @@ -5853,7 +5853,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_float_zerow_address_offset = 372; static constexpr dart::compiler::target::word - AOT_Thread_global_object_pool_offset = 720; + AOT_Thread_global_object_pool_offset = 724; static constexpr dart::compiler::target::word AOT_Thread_interpret_call_entry_point_offset = 340; static constexpr dart::compiler::target::word @@ -5861,7 +5861,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_invoke_dart_code_stub_offset = 140; static constexpr dart::compiler::target::word - AOT_Thread_exit_through_ffi_offset = 744; + AOT_Thread_exit_through_ffi_offset = 748; static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 44; static constexpr dart::compiler::target::word AOT_Thread_field_table_values_offset = 68; @@ -5901,11 +5901,11 @@ static constexpr dart::compiler::target::word AOT_Thread_object_null_offset = 112; static constexpr dart::compiler::target::word AOT_Thread_predefined_symbols_address_offset = 344; -static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 724; +static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 728; static constexpr dart::compiler::target::word - AOT_Thread_saved_shadow_call_stack_offset = 728; + AOT_Thread_saved_shadow_call_stack_offset = 732; static constexpr dart::compiler::target::word - AOT_Thread_safepoint_state_offset = 736; + AOT_Thread_safepoint_state_offset = 740; static constexpr dart::compiler::target::word AOT_Thread_slow_type_test_stub_offset = 244; static constexpr dart::compiler::target::word @@ -5941,7 +5941,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_write_barrier_mask_offset = 40; static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset = - 740; + 744; static constexpr dart::compiler::target::word AOT_TimelineStream_enabled_offset = 8; static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset = @@ -5987,7 +5987,7 @@ static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = { 4, 12, 8, 16}; static constexpr dart::compiler::target::word AOT_Thread_write_barrier_wrappers_thread_offset[] = { - 680, 684, 688, 692, 696, -1, 700, -1, 704, 708, -1, -1, -1, -1, -1, -1}; + 684, 688, 692, 696, 700, -1, 704, -1, 708, 712, -1, -1, -1, -1, -1, -1}; static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 8; static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 12; static constexpr dart::compiler::target::word AOT_Array_header_size = 12; @@ -6301,9 +6301,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_AllocateArray_entry_point_offset = 736; static constexpr dart::compiler::target::word - AOT_Thread_active_exception_offset = 1432; + AOT_Thread_active_exception_offset = 1440; static constexpr dart::compiler::target::word - AOT_Thread_active_stacktrace_offset = 1440; + AOT_Thread_active_stacktrace_offset = 1448; static constexpr dart::compiler::target::word AOT_Thread_array_write_barrier_code_offset = 240; static constexpr dart::compiler::target::word @@ -6329,7 +6329,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_allocate_object_slow_stub_offset = 384; static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset = - 1504; + 1512; static constexpr dart::compiler::target::word AOT_Thread_async_stack_trace_offset = 192; static constexpr dart::compiler::target::word @@ -6344,7 +6344,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_call_to_runtime_stub_offset = 280; static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset = - 1520; + 1528; static constexpr dart::compiler::target::word AOT_Thread_dispatch_table_array_offset = 96; static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset = @@ -6363,7 +6363,7 @@ static constexpr dart::compiler::target::word AOT_Thread_end_offset = 112; static constexpr dart::compiler::target::word AOT_Thread_enter_safepoint_stub_offset = 488; static constexpr dart::compiler::target::word - AOT_Thread_execution_state_offset = 1472; + AOT_Thread_execution_state_offset = 1480; static constexpr dart::compiler::target::word AOT_Thread_exit_safepoint_stub_offset = 496; static constexpr dart::compiler::target::word @@ -6383,7 +6383,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_float_zerow_address_offset = 728; static constexpr dart::compiler::target::word - AOT_Thread_global_object_pool_offset = 1448; + AOT_Thread_global_object_pool_offset = 1456; static constexpr dart::compiler::target::word AOT_Thread_interpret_call_entry_point_offset = 664; static constexpr dart::compiler::target::word @@ -6391,7 +6391,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_invoke_dart_code_stub_offset = 264; static constexpr dart::compiler::target::word - AOT_Thread_exit_through_ffi_offset = 1496; + AOT_Thread_exit_through_ffi_offset = 1504; static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88; static constexpr dart::compiler::target::word AOT_Thread_field_table_values_offset = 136; @@ -6432,11 +6432,11 @@ static constexpr dart::compiler::target::word AOT_Thread_object_null_offset = static constexpr dart::compiler::target::word AOT_Thread_predefined_symbols_address_offset = 672; static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = - 1456; + 1464; static constexpr dart::compiler::target::word - AOT_Thread_saved_shadow_call_stack_offset = 1464; + AOT_Thread_saved_shadow_call_stack_offset = 1472; static constexpr dart::compiler::target::word - AOT_Thread_safepoint_state_offset = 1480; + AOT_Thread_safepoint_state_offset = 1488; static constexpr dart::compiler::target::word AOT_Thread_slow_type_test_stub_offset = 472; static constexpr dart::compiler::target::word @@ -6472,7 +6472,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_write_barrier_mask_offset = 80; static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset = - 1488; + 1496; static constexpr dart::compiler::target::word AOT_TimelineStream_enabled_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset = @@ -6518,8 +6518,8 @@ static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = { 8, 24, 16, 32}; static constexpr dart::compiler::target::word AOT_Thread_write_barrier_wrappers_thread_offset[] = { - 1344, 1352, 1360, 1368, -1, -1, 1376, 1384, - 1392, 1400, 1408, -1, 1416, 1424, -1, -1}; + 1352, 1360, 1368, 1376, -1, -1, 1384, 1392, + 1400, 1408, 1416, -1, 1424, 1432, -1, -1}; static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16; static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Array_header_size = 24; @@ -6837,9 +6837,9 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_AllocateArray_entry_point_offset = 736; static constexpr dart::compiler::target::word - AOT_Thread_active_exception_offset = 1504; + AOT_Thread_active_exception_offset = 1512; static constexpr dart::compiler::target::word - AOT_Thread_active_stacktrace_offset = 1512; + AOT_Thread_active_stacktrace_offset = 1520; static constexpr dart::compiler::target::word AOT_Thread_array_write_barrier_code_offset = 240; static constexpr dart::compiler::target::word @@ -6865,7 +6865,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_allocate_object_slow_stub_offset = 384; static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset = - 1576; + 1584; static constexpr dart::compiler::target::word AOT_Thread_async_stack_trace_offset = 192; static constexpr dart::compiler::target::word @@ -6880,7 +6880,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_call_to_runtime_stub_offset = 280; static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset = - 1592; + 1600; static constexpr dart::compiler::target::word AOT_Thread_dispatch_table_array_offset = 96; static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset = @@ -6899,7 +6899,7 @@ static constexpr dart::compiler::target::word AOT_Thread_end_offset = 112; static constexpr dart::compiler::target::word AOT_Thread_enter_safepoint_stub_offset = 488; static constexpr dart::compiler::target::word - AOT_Thread_execution_state_offset = 1544; + AOT_Thread_execution_state_offset = 1552; static constexpr dart::compiler::target::word AOT_Thread_exit_safepoint_stub_offset = 496; static constexpr dart::compiler::target::word @@ -6919,7 +6919,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_float_zerow_address_offset = 728; static constexpr dart::compiler::target::word - AOT_Thread_global_object_pool_offset = 1520; + AOT_Thread_global_object_pool_offset = 1528; static constexpr dart::compiler::target::word AOT_Thread_interpret_call_entry_point_offset = 664; static constexpr dart::compiler::target::word @@ -6927,7 +6927,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_invoke_dart_code_stub_offset = 264; static constexpr dart::compiler::target::word - AOT_Thread_exit_through_ffi_offset = 1568; + AOT_Thread_exit_through_ffi_offset = 1576; static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88; static constexpr dart::compiler::target::word AOT_Thread_field_table_values_offset = 136; @@ -6968,11 +6968,11 @@ static constexpr dart::compiler::target::word AOT_Thread_object_null_offset = static constexpr dart::compiler::target::word AOT_Thread_predefined_symbols_address_offset = 672; static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = - 1528; + 1536; static constexpr dart::compiler::target::word - AOT_Thread_saved_shadow_call_stack_offset = 1536; + AOT_Thread_saved_shadow_call_stack_offset = 1544; static constexpr dart::compiler::target::word - AOT_Thread_safepoint_state_offset = 1552; + AOT_Thread_safepoint_state_offset = 1560; static constexpr dart::compiler::target::word AOT_Thread_slow_type_test_stub_offset = 472; static constexpr dart::compiler::target::word @@ -7008,7 +7008,7 @@ static constexpr dart::compiler::target::word static constexpr dart::compiler::target::word AOT_Thread_write_barrier_mask_offset = 80; static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset = - 1560; + 1568; static constexpr dart::compiler::target::word AOT_TimelineStream_enabled_offset = 16; static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset = @@ -7054,9 +7054,9 @@ static constexpr dart::compiler::target::word AOT_Code_entry_point_offset[] = { 8, 24, 16, 32}; static constexpr dart::compiler::target::word AOT_Thread_write_barrier_wrappers_thread_offset[] = { - 1344, 1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, - 1432, 1440, 1448, 1456, -1, -1, -1, -1, 1464, 1472, -1, - -1, 1480, 1488, 1496, -1, -1, -1, -1, -1, -1}; + 1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432, + 1440, 1448, 1456, 1464, -1, -1, -1, -1, 1472, 1480, -1, + -1, 1488, 1496, 1504, -1, -1, -1, -1, -1, -1}; static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16; static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Array_header_size = 24; diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc index e858c7d7a36..2ef0df4fe6b 100644 --- a/runtime/vm/compiler/stub_code_compiler_arm.cc +++ b/runtime/vm/compiler/stub_code_compiler_arm.cc @@ -3716,6 +3716,12 @@ void StubCodeCompiler::GenerateAsynchronousGapMarkerStub(Assembler* assembler) { __ bkpt(0); } +void StubCodeCompiler::GenerateNotLoadedStub(Assembler* assembler) { + __ EnterStubFrame(); + __ CallRuntime(kNotLoadedRuntimeEntry, 0); + __ bkpt(0); +} + // Instantiate type arguments from instantiator and function type args. // R3 uninstantiated type arguments. // R2 instantiator type arguments. diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc index 20eb97029cb..8050974922c 100644 --- a/runtime/vm/compiler/stub_code_compiler_arm64.cc +++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc @@ -3900,6 +3900,12 @@ void StubCodeCompiler::GenerateAsynchronousGapMarkerStub(Assembler* assembler) { __ brk(0); } +void StubCodeCompiler::GenerateNotLoadedStub(Assembler* assembler) { + __ EnterStubFrame(); + __ CallRuntime(kNotLoadedRuntimeEntry, 0); + __ brk(0); +} + // Instantiate type arguments from instantiator and function type args. // R3 uninstantiated type arguments. // R2 instantiator type arguments. diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc index 6649df4f2e4..96bf0ff9b17 100644 --- a/runtime/vm/compiler/stub_code_compiler_ia32.cc +++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc @@ -2965,6 +2965,12 @@ void StubCodeCompiler::GenerateAsynchronousGapMarkerStub(Assembler* assembler) { __ int3(); // Marker stub. } +void StubCodeCompiler::GenerateNotLoadedStub(Assembler* assembler) { + __ EnterStubFrame(); + __ CallRuntime(kNotLoadedRuntimeEntry, 0); + __ int3(); +} + // Instantiate type arguments from instantiator and function type args. // EBX: uninstantiated type arguments. // EDX: instantiator type arguments. diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc index 23ec342d030..7096c77029b 100644 --- a/runtime/vm/compiler/stub_code_compiler_x64.cc +++ b/runtime/vm/compiler/stub_code_compiler_x64.cc @@ -3793,6 +3793,12 @@ void StubCodeCompiler::GenerateAsynchronousGapMarkerStub(Assembler* assembler) { __ int3(); } +void StubCodeCompiler::GenerateNotLoadedStub(Assembler* assembler) { + __ EnterStubFrame(); + __ CallRuntime(kNotLoadedRuntimeEntry, 0); + __ int3(); +} + // Instantiate type arguments from instantiator and function type args. // RBX: uninstantiated type arguments. // RDX: instantiator type arguments. diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc index 94c36ccbcdc..99aa048576d 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -657,14 +657,6 @@ Isolate* Dart::CreateIsolate(const char* name_prefix, return isolate; } -static bool IsSnapshotCompatible(Snapshot::Kind vm_kind, - Snapshot::Kind isolate_kind) { - if (vm_kind == isolate_kind) return true; - if (vm_kind == Snapshot::kFull && isolate_kind == Snapshot::kFullJIT) - return true; - return Snapshot::IsFull(isolate_kind); -} - #if defined(DART_PRECOMPILED_RUNTIME) static bool CloneIntoChildIsolateAOT(Thread* T, Isolate* I, diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index 35bc83bf76f..39a93cc7fb7 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -5402,6 +5402,14 @@ DART_EXPORT Dart_Handle Dart_DefaultCanonicalizeUrl(Dart_Handle base_url, return Api::NewHandle(T, String::New(resolved_uri)); } +DART_EXPORT Dart_Handle +Dart_SetDeferredLoadHandler(Dart_DeferredLoadHandler handler) { + Isolate* isolate = Isolate::Current(); + CHECK_ISOLATE(isolate); + isolate->group()->set_deferred_load_handler(handler); + return Api::Success(); +} + DART_EXPORT Dart_Handle Dart_LoadScriptFromKernel(const uint8_t* buffer, intptr_t buffer_size) { #if defined(DART_PRECOMPILED_RUNTIME) @@ -5844,6 +5852,78 @@ DART_EXPORT Dart_Handle Dart_FinalizeLoading(bool complete_futures) { return Api::Success(); } +static Dart_Handle DeferredLoadComplete(intptr_t loading_unit_id, + bool error, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions, + const char* error_message, + bool transient_error) { + DARTSCOPE(Thread::Current()); + API_TIMELINE_DURATION(T); + Isolate* I = T->isolate(); + CHECK_CALLBACK_STATE(T); + + const Array& loading_units = + Array::Handle(I->object_store()->loading_units()); + if (loading_units.IsNull() || (loading_unit_id < LoadingUnit::kRootId) || + (loading_unit_id >= loading_units.Length())) { + return Api::NewError("Invalid loading unit"); + } + LoadingUnit& unit = LoadingUnit::Handle(); + unit ^= loading_units.At(loading_unit_id); + if (unit.loaded()) { + return Api::NewError("Unit already loaded"); + } + + if (error) { + CHECK_NULL(error_message); + unit.CompleteLoad(String::Handle(String::New(error_message)), + transient_error); + } else { +#if defined(SUPPORT_TIMELINE) + TimelineBeginEndScope tbes(T, Timeline::GetIsolateStream(), + "ReadUnitSnapshot"); +#endif // defined(SUPPORT_TIMELINE) + const Snapshot* snapshot = Snapshot::SetupFromBuffer(snapshot_data); + if (snapshot == NULL) { + return Api::NewError("Invalid snapshot"); + } + if (!IsSnapshotCompatible(Dart::vm_snapshot_kind(), snapshot->kind())) { + const String& message = String::Handle(String::NewFormatted( + "Incompatible snapshot kinds: vm '%s', isolate '%s'", + Snapshot::KindToCString(Dart::vm_snapshot_kind()), + Snapshot::KindToCString(snapshot->kind()))); + return Api::NewHandle(T, ApiError::New(message)); + } + + FullSnapshotReader reader(snapshot, snapshot_instructions, T); + const Error& error = Error::Handle(reader.ReadUnitSnapshot(unit)); + if (!error.IsNull()) { + return Api::NewHandle(T, error.raw()); + } + + unit.CompleteLoad(String::Handle(), false); + } + + return Api::Success(); +} + +DART_EXPORT Dart_Handle +Dart_DeferredLoadComplete(intptr_t loading_unit_id, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions) { + return DeferredLoadComplete(loading_unit_id, false, snapshot_data, + snapshot_instructions, nullptr, false); +} + +DART_EXPORT Dart_Handle +Dart_DeferredLoadCompleteError(intptr_t loading_unit_id, + const char* error_message, + bool transient) { + return DeferredLoadComplete(loading_unit_id, true, nullptr, nullptr, + error_message, transient); +} + DART_EXPORT Dart_Handle Dart_SetNativeResolver(Dart_Handle library, Dart_NativeEntryResolver resolver, @@ -6409,6 +6489,127 @@ DART_EXPORT Dart_Handle Dart_Precompile() { #if !defined(TARGET_ARCH_IA32) && defined(DART_PRECOMPILER) static const intptr_t kInitialSize = 2 * MB; static const intptr_t kInitialDebugSize = 1 * MB; + +static void CreateAppAOTSnapshot( + Dart_StreamingWriteCallback callback, + void* callback_data, + bool strip, + bool as_elf, + void* debug_callback_data, + GrowableArray* units, + LoadingUnitSerializationData* unit, + uint32_t program_hash) { + Thread* T = Thread::Current(); + + NOT_IN_PRODUCT(TimelineBeginEndScope tbes2(T, Timeline::GetIsolateStream(), + "WriteAppAOTSnapshot")); + + uint8_t* vm_snapshot_data_buffer = nullptr; + uint8_t* vm_snapshot_instructions_buffer = nullptr; + uint8_t* isolate_snapshot_data_buffer = nullptr; + uint8_t* isolate_snapshot_instructions_buffer = nullptr; + + const bool generate_debug = debug_callback_data != nullptr; + + if (as_elf) { + StreamingWriteStream elf_stream(kInitialSize, callback, callback_data); + StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0, + callback, debug_callback_data); + + auto const dwarf = strip ? nullptr : new (Z) Dwarf(Z); + auto const elf = new (Z) Elf(Z, &elf_stream, Elf::Type::Snapshot, dwarf); + // Re-use the same DWARF object if the snapshot is unstripped. + auto const debug_elf = + generate_debug ? new (Z) Elf(Z, &debug_stream, Elf::Type::DebugInfo, + strip ? new (Z) Dwarf(Z) : dwarf) + : nullptr; + + BlobImageWriter vm_image_writer(T, &vm_snapshot_instructions_buffer, + ApiReallocate, kInitialSize, debug_elf, + elf); + BlobImageWriter isolate_image_writer( + T, &isolate_snapshot_instructions_buffer, ApiReallocate, kInitialSize, + debug_elf, elf); + FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer, + &isolate_snapshot_data_buffer, ApiReallocate, + &vm_image_writer, &isolate_image_writer); + + if (unit == nullptr || unit->id() == LoadingUnit::kRootId) { + writer.WriteFullSnapshot(units); + } else { + writer.WriteUnitSnapshot(units, unit, program_hash); + } + + elf->Finalize(); + if (debug_elf != nullptr) { + debug_elf->Finalize(); + } + } else { + StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0, + callback, debug_callback_data); + + auto const elf = generate_debug + ? new (Z) Elf(Z, &debug_stream, Elf::Type::DebugInfo, + new (Z) Dwarf(Z)) + : nullptr; + + AssemblyImageWriter image_writer(T, callback, callback_data, strip, elf); + uint8_t* vm_snapshot_data_buffer = NULL; + uint8_t* isolate_snapshot_data_buffer = NULL; + FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer, + &isolate_snapshot_data_buffer, ApiReallocate, + &image_writer, &image_writer); + + if (unit == nullptr || unit->id() == LoadingUnit::kRootId) { + writer.WriteFullSnapshot(units); + } else { + writer.WriteUnitSnapshot(units, unit, program_hash); + } + image_writer.Finalize(); + } +} + +static void Split(Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool strip, + bool as_elf, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback) { + Thread* T = Thread::Current(); + ProgramVisitor::AssignUnits(T); + + const Array& loading_units = + Array::Handle(T->isolate()->object_store()->loading_units()); + const uint32_t program_hash = ProgramVisitor::Hash(T); + loading_units.SetAt(0, Smi::Handle(Z, Smi::New(program_hash))); + GrowableArray data; + data.SetLength(loading_units.Length()); + data[0] = nullptr; + + LoadingUnit& loading_unit = LoadingUnit::Handle(); + LoadingUnit& parent = LoadingUnit::Handle(); + for (intptr_t id = 1; id < loading_units.Length(); id++) { + loading_unit ^= loading_units.At(id); + parent = loading_unit.parent(); + LoadingUnitSerializationData* parent_data = + parent.IsNull() ? nullptr : data[parent.id()]; + data[id] = new LoadingUnitSerializationData(id, parent_data); + } + + for (intptr_t id = 1; id < loading_units.Length(); id++) { + void* write_callback_data = nullptr; + void* write_debug_callback_data = nullptr; + next_callback(next_callback_data, id, &write_callback_data, + &write_debug_callback_data); + CreateAppAOTSnapshot(write_callback, write_callback_data, strip, as_elf, + write_debug_callback_data, &data, data[id], + program_hash); + close_callback(write_callback_data); + if (write_debug_callback_data != nullptr) { + close_callback(write_debug_callback_data); + } + } +} #endif DART_EXPORT Dart_Handle @@ -6428,26 +6629,43 @@ Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback, API_TIMELINE_DURATION(T); CHECK_NULL(callback); - TIMELINE_DURATION(T, Isolate, "WriteAppAOTSnapshot"); - const bool generate_debug = debug_callback_data != nullptr; + // Mark as not split. + T->isolate()->object_store()->set_loading_units(Object::null_array()); - StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0, - callback, debug_callback_data); + CreateAppAOTSnapshot(callback, callback_data, strip, /*as_elf*/ false, + debug_callback_data, nullptr, nullptr, 0); - auto const elf = generate_debug - ? new (Z) Elf(Z, &debug_stream, Elf::Type::DebugInfo, - new (Z) Dwarf(Z)) - : nullptr; + return Api::Success(); +#endif +} - AssemblyImageWriter image_writer(T, callback, callback_data, strip, elf); - uint8_t* vm_snapshot_data_buffer = NULL; - uint8_t* isolate_snapshot_data_buffer = NULL; - FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer, - &isolate_snapshot_data_buffer, ApiReallocate, - &image_writer, &image_writer); +DART_EXPORT Dart_Handle Dart_CreateAppAOTSnapshotAsAssemblies( + Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool strip, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback) { +#if defined(TARGET_ARCH_IA32) + return Api::NewError("AOT compilation is not supported on IA32."); +#elif defined(TARGET_OS_WINDOWS) + return Api::NewError("Assembly generation is not implemented for Windows."); +#elif !defined(DART_PRECOMPILER) + return Api::NewError( + "This VM was built without support for AOT compilation."); +#else + if (FLAG_use_bare_instructions) { + return Api::NewError( + "Splitting is not compatible with --use_bare_instructions."); + } - writer.WriteFullSnapshot(); - image_writer.Finalize(); + DARTSCOPE(Thread::Current()); + API_TIMELINE_DURATION(T); + CHECK_NULL(next_callback); + CHECK_NULL(write_callback); + CHECK_NULL(close_callback); + + Split(next_callback, next_callback_data, strip, /*as_elf*/ false, + write_callback, close_callback); return Api::Success(); #endif @@ -6493,45 +6711,44 @@ Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback, #else DARTSCOPE(Thread::Current()); API_TIMELINE_DURATION(T); + CHECK_NULL(callback); - NOT_IN_PRODUCT(TimelineBeginEndScope tbes2(T, Timeline::GetIsolateStream(), - "WriteAppAOTSnapshot")); + // Mark as not split. + T->isolate()->object_store()->set_loading_units(Object::null_array()); - uint8_t* vm_snapshot_data_buffer = nullptr; - uint8_t* vm_snapshot_instructions_buffer = nullptr; - uint8_t* isolate_snapshot_data_buffer = nullptr; - uint8_t* isolate_snapshot_instructions_buffer = nullptr; + CreateAppAOTSnapshot(callback, callback_data, strip, /*as_elf*/ true, + debug_callback_data, nullptr, nullptr, 0); - const bool generate_debug = debug_callback_data != nullptr; + return Api::Success(); +#endif +} - StreamingWriteStream elf_stream(kInitialSize, callback, callback_data); - StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0, - callback, debug_callback_data); - - auto const dwarf = strip ? nullptr : new (Z) Dwarf(Z); - auto const elf = new (Z) Elf(Z, &elf_stream, Elf::Type::Snapshot, dwarf); - // Re-use the same DWARF object if the snapshot is unstripped. - auto const debug_elf = - generate_debug ? new (Z) Elf(Z, &debug_stream, Elf::Type::DebugInfo, - strip ? new (Z) Dwarf(Z) : dwarf) - : nullptr; - - BlobImageWriter vm_image_writer(T, &vm_snapshot_instructions_buffer, - ApiReallocate, kInitialSize, debug_elf, elf); - BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instructions_buffer, - ApiReallocate, kInitialSize, debug_elf, - elf); - FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer, - &isolate_snapshot_data_buffer, ApiReallocate, - &vm_image_writer, &isolate_image_writer); - - writer.WriteFullSnapshot(); - - elf->Finalize(); - if (debug_elf != nullptr) { - debug_elf->Finalize(); +DART_EXPORT Dart_Handle +Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback, + void* next_callback_data, + bool strip, + Dart_StreamingWriteCallback write_callback, + Dart_StreamingCloseCallback close_callback) { +#if defined(TARGET_ARCH_IA32) + return Api::NewError("AOT compilation is not supported on IA32."); +#elif !defined(DART_PRECOMPILER) + return Api::NewError( + "This VM was built without support for AOT compilation."); +#else + if (FLAG_use_bare_instructions) { + return Api::NewError( + "Splitting is not compatible with --use_bare_instructions."); } + DARTSCOPE(Thread::Current()); + API_TIMELINE_DURATION(T); + CHECK_NULL(next_callback); + CHECK_NULL(write_callback); + CHECK_NULL(close_callback); + + Split(next_callback, next_callback_data, strip, /*as_elf*/ true, + write_callback, close_callback); + return Api::Success(); #endif } diff --git a/runtime/vm/dwarf.cc b/runtime/vm/dwarf.cc index db73b08d983..8b927ec7928 100644 --- a/runtime/vm/dwarf.cc +++ b/runtime/vm/dwarf.cc @@ -727,15 +727,23 @@ void Dwarf::WriteLineNumberProgram(DwarfWriteStream* stream) { } // Advance pc to end of the compilation unit if not already there. - const intptr_t last_code_index = codes_.length() - 1; - const Code& last_code = *(codes_[last_code_index]); - const intptr_t last_pc_offset = last_code.Size(); - const char* last_asm_name = namer.SnapshotNameFor(last_code_index, last_code); + if (codes_.length() != 0) { + const intptr_t last_code_index = codes_.length() - 1; + const Code& last_code = *(codes_[last_code_index]); + const intptr_t last_pc_offset = last_code.Size(); + const char* last_asm_name = + namer.SnapshotNameFor(last_code_index, last_code); - stream->u1(DW_LNS_advance_pc); - ASSERT(previous_asm_name != nullptr); - stream->DistanceBetweenSymbolOffsets(last_asm_name, last_pc_offset, - previous_asm_name, previous_pc_offset); + stream->u1(DW_LNS_advance_pc); + if (previous_asm_name != nullptr) { + stream->DistanceBetweenSymbolOffsets( + last_asm_name, last_pc_offset, previous_asm_name, previous_pc_offset); + } else { + // No LNP entries (e.g., only stub code). + ASSERT(previous_pc_offset == 0); + stream->uleb128(last_pc_offset); + } + } // End of contiguous machine code. stream->u1(0); // This is an extended opcode diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc index 2ce45e3070f..606ef610c55 100644 --- a/runtime/vm/elf.cc +++ b/runtime/vm/elf.cc @@ -1125,17 +1125,20 @@ void Elf::FinalizeDwarfSections() { // Need these to turn offsets into relocated addresses. auto const vm_start = symbol_to_address_map.LookupValue(kVmSnapshotInstructionsAsmSymbol); - ASSERT(vm_start > 0); + // vm_start is absent in deferred loading peices. auto const isolate_start = symbol_to_address_map.LookupValue(kIsolateSnapshotInstructionsAsmSymbol); ASSERT(isolate_start > 0); auto const vm_text = FindSectionForAddress(vm_start); - ASSERT(vm_text != nullptr); + // vm_text is absent in deferred loading peices. auto const isolate_text = FindSectionForAddress(isolate_start); ASSERT(isolate_text != nullptr); SnapshotTextObjectNamer namer(zone_); const auto& codes = dwarf_->codes(); + if (codes.length() == 0) { + return; + } for (intptr_t i = 0; i < codes.length(); i++) { const auto& code = *codes[i]; auto const name = namer.SnapshotNameFor(i, code); @@ -1300,7 +1303,8 @@ Section* Elf::GenerateBuildId() { auto const name = kBuildIdSegmentNames[i]; auto const symbol = LookupSymbol(dynstrtab_, dynsym_, name); if (symbol == nullptr) { - FATAL1("No symbol %s found for expected segment\n", name); + stream.WriteFixed(static_cast(0)); + continue; } auto const bits = sections_[symbol->section_index]->AsBitsContainer(); if (bits == nullptr) { diff --git a/runtime/vm/hash.h b/runtime/vm/hash.h index cbd4c83690b..7365500cd81 100644 --- a/runtime/vm/hash.h +++ b/runtime/vm/hash.h @@ -27,6 +27,16 @@ inline uint32_t FinalizeHash(uint32_t hash, intptr_t hashbits) { return (hash == 0) ? 1 : hash; } +inline uint32_t HashBytes(const uint8_t* bytes, intptr_t size) { + uint32_t hash = size; + while (size > 0) { + hash = CombineHashes(hash, *bytes); + bytes++; + size--; + } + return hash; +} + } // namespace dart #endif // RUNTIME_VM_HASH_H_ diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h index fb57895bda1..841edb133a7 100644 --- a/runtime/vm/heap/heap.h +++ b/runtime/vm/heap/heap.h @@ -45,6 +45,7 @@ class Heap { #endif kCanonicalHashes, kObjectIds, + kLoadingUnits, kNumWeakSelectors }; @@ -234,6 +235,15 @@ class Heap { } void ResetObjectIdTable(); + void SetLoadingUnit(ObjectPtr raw_obj, intptr_t object_id) { + ASSERT(Thread::Current()->IsMutatorThread()); + SetWeakEntry(raw_obj, kLoadingUnits, object_id); + } + intptr_t GetLoadingUnit(ObjectPtr raw_obj) const { + ASSERT(Thread::Current()->IsMutatorThread()); + return GetWeakEntry(raw_obj, kLoadingUnits); + } + // Used by the GC algorithms to propagate weak entries. intptr_t GetWeakEntry(ObjectPtr raw_obj, WeakSelector sel) const; void SetWeakEntry(ObjectPtr raw_obj, WeakSelector sel, intptr_t val); diff --git a/runtime/vm/heap/weak_table.h b/runtime/vm/heap/weak_table.h index 1a81be4b833..f145dfef78a 100644 --- a/runtime/vm/heap/weak_table.h +++ b/runtime/vm/heap/weak_table.h @@ -15,6 +15,8 @@ namespace dart { class WeakTable { public: + static constexpr intptr_t kNoValue = 0; + WeakTable() : size_(kMinSize), used_(0), count_(0) { ASSERT(Utils::IsPowerOfTwo(size_)); data_ = reinterpret_cast(calloc(size_, kEntrySize * kWordSize)); @@ -104,7 +106,7 @@ class WeakTable { obj = ObjectAtExclusive(idx); } ASSERT(ValueAtExclusive(idx) == 0); - return 0; + return kNoValue; } // Removes and returns the value associated with |key|. Returns 0 if there is @@ -123,7 +125,7 @@ class WeakTable { obj = ObjectAtExclusive(idx); } ASSERT(ValueAtExclusive(idx) == 0); - return 0; + return kNoValue; } void Forward(ObjectPointerVisitor* visitor); diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc index d1c8505daf6..8108270f73c 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc @@ -1878,6 +1878,18 @@ ObjectPtr Isolate::CallTagHandler(Dart_LibraryTag tag, return Api::UnwrapHandle(api_result); } +ObjectPtr Isolate::CallDeferredLoadHandler(intptr_t id) { + Thread* thread = Thread::Current(); + Api::Scope api_scope(thread); + Dart_Handle api_result; + { + TransitionVMToNative transition(thread); + RELEASE_ASSERT(HasDeferredLoadHandler()); + api_result = group()->deferred_load_handler()(id); + } + return Api::UnwrapHandle(api_result); +} + void Isolate::SetupImagePage(const uint8_t* image_buffer, bool is_executable) { Image image(image_buffer); heap()->SetupImagePage(image.object_start(), image.object_size(), diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h index 3dcdb2beeea..eb8d5cc4637 100644 --- a/runtime/vm/isolate.h +++ b/runtime/vm/isolate.h @@ -410,6 +410,12 @@ class IsolateGroup : public IntrusiveDListEntry { void set_library_tag_handler(Dart_LibraryTagHandler handler) { library_tag_handler_ = handler; } + Dart_DeferredLoadHandler deferred_load_handler() const { + return deferred_load_handler_; + } + void set_deferred_load_handler(Dart_DeferredLoadHandler handler) { + deferred_load_handler_ = handler; + } intptr_t GetClassSizeForHeapWalkAt(intptr_t cid); @@ -605,6 +611,7 @@ class IsolateGroup : public IntrusiveDListEntry { intptr_t isolate_count_ = 0; bool initial_spawn_successful_ = false; Dart_LibraryTagHandler library_tag_handler_ = nullptr; + Dart_DeferredLoadHandler deferred_load_handler_ = nullptr; int64_t start_time_micros_; #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) @@ -846,6 +853,10 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry { ObjectPtr CallTagHandler(Dart_LibraryTag tag, const Object& arg1, const Object& arg2); + bool HasDeferredLoadHandler() const { + return group()->deferred_load_handler() != nullptr; + } + ObjectPtr CallDeferredLoadHandler(intptr_t id); void SetupImagePage(const uint8_t* snapshot_buffer, bool is_executable); diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 6bca37cef1e..b5a6778ad38 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -17239,7 +17239,7 @@ LoadingUnitPtr LoadingUnit::New() { } result.set_id(kIllegalId); result.set_loaded(false); - result.set_load_issued(false); + result.set_load_outstanding(false); return result.raw(); } @@ -17261,6 +17261,36 @@ const char* LoadingUnit::ToCString() const { return "LoadingUnit"; } +ObjectPtr LoadingUnit::IssueLoad() const { + ASSERT(!loaded()); + ASSERT(!load_outstanding()); + set_load_outstanding(true); + return Isolate::Current()->CallDeferredLoadHandler(id()); +} + +void LoadingUnit::CompleteLoad(const String& error_message, + bool transient_error) const { + ASSERT(!loaded()); + ASSERT(load_outstanding()); + set_loaded(error_message.IsNull()); + set_load_outstanding(false); + + const Library& lib = Library::Handle(Library::CoreLibrary()); + const String& sel = String::Handle(String::New("_completeLoads")); + const Function& func = Function::Handle(lib.LookupFunctionAllowPrivate(sel)); + ASSERT(!func.IsNull()); + const Array& args = Array::Handle(Array::New(3)); + args.SetAt(0, Smi::Handle(Smi::New(id()))); + args.SetAt(1, error_message); + args.SetAt(2, Bool::Get(transient_error)); + const Object& result = Object::Handle(DartEntry::InvokeFunction(func, args)); + if (result.IsUnwindError()) { + Thread::Current()->set_sticky_error(Error::Cast(result)); + } else if (result.IsError()) { + UNREACHABLE(); + } +} + const char* Error::ToErrorCString() const { if (IsNull()) { return "Error: null"; diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 8a9ec199563..c11e056a51b 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -5448,6 +5448,10 @@ class Instructions : public Object { return memcmp(a->ptr(), b->ptr(), InstanceSize(Size(a))) == 0; } + uint32_t Hash() const { + return HashBytes(reinterpret_cast(PayloadStart()), Size()); + } + CodeStatistics* stats() const; void set_stats(CodeStatistics* stats) const; @@ -7015,8 +7019,9 @@ class SubtypeTestCache : public Object { class LoadingUnit : public Object { public: - static const intptr_t kIllegalId = 0; - static const intptr_t kRootId = 1; + static constexpr intptr_t kIllegalId = 0; + COMPILE_ASSERT(kIllegalId == WeakTable::kNoValue); + static constexpr intptr_t kRootId = 1; static LoadingUnitPtr New(); @@ -7031,18 +7036,24 @@ class LoadingUnit : public Object { void set_base_objects(const Array& value) const; intptr_t id() const { return raw_ptr()->id_; } - void set_id(intptr_t id) { StoreNonPointer(&raw_ptr()->id_, id); } + void set_id(intptr_t id) const { StoreNonPointer(&raw_ptr()->id_, id); } // True once the VM deserializes this unit's snapshot. bool loaded() const { return raw_ptr()->loaded_; } - void set_loaded(bool value) { StoreNonPointer(&raw_ptr()->loaded_, value); } - - // True once the VM invokes the embedder's deferred load callback. - bool load_issued() const { return raw_ptr()->load_issued_; } - void set_load_issued(bool value) { - StoreNonPointer(&raw_ptr()->load_issued_, value); + void set_loaded(bool value) const { + StoreNonPointer(&raw_ptr()->loaded_, value); } + // True once the VM invokes the embedder's deferred load callback until the + // embedder calls Dart_DeferredLoadComplete[Error]. + bool load_outstanding() const { return raw_ptr()->load_outstanding_; } + void set_load_outstanding(bool value) const { + StoreNonPointer(&raw_ptr()->load_outstanding_, value); + } + + ObjectPtr IssueLoad() const; + void CompleteLoad(const String& error_message, bool transient_error) const; + private: FINAL_HEAP_OBJECT_IMPLEMENTATION(LoadingUnit, Object); friend class Class; diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc index 9e45c7ddf80..3231fda5b47 100644 --- a/runtime/vm/object_service.cc +++ b/runtime/vm/object_service.cc @@ -1041,7 +1041,7 @@ void LoadingUnit::PrintJSONImpl(JSONStream* stream, bool ref) const { jsobj.AddProperty("_baseObjects", Array::Handle(base_objects())); jsobj.AddProperty("_id", static_cast(id())); jsobj.AddProperty("_loaded", loaded()); - jsobj.AddProperty("_load_united", load_issued()); + jsobj.AddProperty("_loadOutstanding", load_outstanding()); } void Error::PrintJSONImpl(JSONStream* stream, bool ref) const { diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h index f19bccb78e5..5d7a535d527 100644 --- a/runtime/vm/object_store.h +++ b/runtime/vm/object_store.h @@ -460,6 +460,7 @@ class ObjectStore { friend class Serializer; friend class Deserializer; + friend class ProgramVisitor; DISALLOW_COPY_AND_ASSIGN(ObjectStore); }; diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc index 41582a37a95..14708e382e4 100644 --- a/runtime/vm/program_visitor.cc +++ b/runtime/vm/program_visitor.cc @@ -1092,7 +1092,7 @@ class InstructionsKeyValueTrait { static Value ValueOf(Pair kv) { return kv; } - static inline intptr_t Hashcode(Key key) { return key->Size(); } + static inline intptr_t Hashcode(Key key) { return key->Hash(); } static inline bool IsKeyEqual(Pair pair, Key key) { return pair->Equals(*key); @@ -1300,4 +1300,154 @@ void ProgramVisitor::Dedup(Thread* thread) { #endif // !defined(DART_PRECOMPILED_RUNTIME) } +#if defined(DART_PRECOMPILER) +class AssignLoadingUnitsCodeVisitor : public CodeVisitor { + public: + explicit AssignLoadingUnitsCodeVisitor(Zone* zone) + : heap_(Thread::Current()->heap()), + func_(Function::Handle(zone)), + cls_(Class::Handle(zone)), + lib_(Library::Handle(zone)), + unit_(LoadingUnit::Handle(zone)), + obj_(Object::Handle(zone)) {} + + void VisitCode(const Code& code) { + intptr_t id; + if (code.IsFunctionCode()) { + func_ ^= code.owner(); + cls_ = func_.Owner(); + lib_ = cls_.library(); + unit_ = lib_.loading_unit(); + id = unit_.id(); + } else if (code.IsAllocationStubCode()) { + cls_ ^= code.owner(); + lib_ = cls_.library(); + unit_ = lib_.loading_unit(); + id = unit_.id(); + } else if (code.IsStubCode()) { + id = LoadingUnit::kRootId; + } else { + UNREACHABLE(); + } + + ASSERT(heap_->GetLoadingUnit(code.raw()) == WeakTable::kNoValue); + heap_->SetLoadingUnit(code.raw(), id); + + obj_ = code.code_source_map(); + MergeAssignment(obj_, id); + obj_ = code.compressed_stackmaps(); + MergeAssignment(obj_, id); + } + + void MergeAssignment(const Object& obj, intptr_t id) { + intptr_t old_id = heap_->GetLoadingUnit(obj_.raw()); + if (old_id == WeakTable::kNoValue) { + heap_->SetLoadingUnit(obj_.raw(), id); + } else if (old_id == id) { + // Shared with another code in the same loading unit. + } else { + // Shared with another code in a different loading unit. + // Could assign to dominating loading unit. + heap_->SetLoadingUnit(obj_.raw(), LoadingUnit::kRootId); + } + } + + private: + Heap* heap_; + Function& func_; + Class& cls_; + Library& lib_; + LoadingUnit& unit_; + Object& obj_; +}; + +void ProgramVisitor::AssignUnits(Thread* thread) { + StackZone stack_zone(thread); + HANDLESCOPE(thread); + Zone* zone = thread->zone(); + + // VM stubs. + Instructions& inst = Instructions::Handle(zone); + Code& code = Code::Handle(zone); + for (intptr_t i = 0; i < StubCode::NumEntries(); i++) { + inst = StubCode::EntryAt(i).instructions(); + thread->heap()->SetLoadingUnit(inst.raw(), LoadingUnit::kRootId); + } + + // Isolate stubs. + ObjectStore* object_store = thread->isolate()->object_store(); + ObjectPtr* from = object_store->from(); + ObjectPtr* to = object_store->to_snapshot(Snapshot::kFullAOT); + for (ObjectPtr* p = from; p <= to; p++) { + if ((*p)->IsCode()) { + code ^= *p; + inst = code.instructions(); + thread->heap()->SetLoadingUnit(inst.raw(), LoadingUnit::kRootId); + } + } + + // Function code / allocation stubs. + AssignLoadingUnitsCodeVisitor visitor(zone); + WalkProgram(zone, thread->isolate(), &visitor); +} + +class ProgramHashVisitor : public CodeVisitor { + public: + explicit ProgramHashVisitor(Zone* zone) + : str_(String::Handle(zone)), + pool_(ObjectPool::Handle(zone)), + obj_(Object::Handle(zone)), + instr_(Instructions::Handle(zone)), + hash_(0) {} + + void VisitClass(const Class& cls) { + str_ = cls.Name(); + Hash(str_); + } + + void VisitFunction(const Function& function) { + str_ = function.name(); + Hash(str_); + } + + void VisitCode(const Code& code) { + pool_ = code.object_pool(); + for (intptr_t i = 0; i < pool_.Length(); i++) { + if (pool_.TypeAt(i) == ObjectPool::EntryType::kTaggedObject) { + obj_ = pool_.ObjectAt(i); + if (obj_.IsInstance()) { + Hash(Instance::Cast(obj_)); + } + } + } + instr_ = code.instructions(); + hash_ = CombineHashes(hash_, instr_.Hash()); + } + + void Hash(const Instance& instance) { + hash_ = CombineHashes(hash_, instance.CanonicalizeHash()); + } + + uint32_t hash() const { return FinalizeHash(hash_, String::kHashBits); } + + private: + String& str_; + ObjectPool& pool_; + Object& obj_; + Instructions& instr_; + uint32_t hash_; +}; + +uint32_t ProgramVisitor::Hash(Thread* thread) { + StackZone stack_zone(thread); + HANDLESCOPE(thread); + Zone* zone = thread->zone(); + + ProgramHashVisitor visitor(zone); + WalkProgram(zone, thread->isolate(), &visitor); + return visitor.hash(); +} + +#endif // defined(DART_PRECOMPILED_RUNTIME) + } // namespace dart diff --git a/runtime/vm/program_visitor.h b/runtime/vm/program_visitor.h index e10ffd210c2..d535f1f9ca6 100644 --- a/runtime/vm/program_visitor.h +++ b/runtime/vm/program_visitor.h @@ -96,6 +96,10 @@ class ProgramVisitor : public AllStatic { static void WalkProgram(Zone* zone, Isolate* isolate, ClassVisitor* visitor); static void Dedup(Thread* thread); +#if defined(DART_PRECOMPILER) + static void AssignUnits(Thread* thread); + static uint32_t Hash(Thread* thread); +#endif private: #if !defined(DART_PRECOMPILED_RUNTIME) diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 53386fc978a..3e634e4ebdb 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -2074,7 +2074,7 @@ class LoadingUnitLayout : public ObjectLayout { ArrayPtr base_objects_; VISIT_TO(ObjectPtr, base_objects_); int32_t id_; - bool load_issued_; + bool load_outstanding_; bool loaded_; }; @@ -2141,9 +2141,8 @@ class LibraryPrefixLayout : public InstanceLayout { switch (kind) { case Snapshot::kFull: case Snapshot::kFullJIT: - return reinterpret_cast(&imports_); case Snapshot::kFullAOT: - return reinterpret_cast(&importer_); + return reinterpret_cast(&imports_); case Snapshot::kMessage: case Snapshot::kNone: case Snapshot::kInvalid: diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc index 9ba859e035e..e66fde6f623 100644 --- a/runtime/vm/runtime_entry.cc +++ b/runtime/vm/runtime_entry.cc @@ -3287,6 +3287,12 @@ DEFINE_RUNTIME_ENTRY(LateInitializationError, 1) { Exceptions::ThrowLateInitializationError(String::Handle(field.name())); } +DEFINE_RUNTIME_ENTRY(NotLoaded, 0) { + // We could just use a trap instruction in the stub, but we get better stack + // traces when there is an exit frame. + FATAL("Not loaded"); +} + // Use expected function signatures to help MSVC compiler resolve overloading. typedef double (*UnaryMathCFunction)(double x); typedef double (*BinaryMathCFunction)(double x, double y); diff --git a/runtime/vm/runtime_entry_list.h b/runtime/vm/runtime_entry_list.h index 5b83f13513d..8945038fa1b 100644 --- a/runtime/vm/runtime_entry_list.h +++ b/runtime/vm/runtime_entry_list.h @@ -57,7 +57,8 @@ namespace dart { V(LateInitializationError) \ V(CompileFunction) \ V(CompileInterpretedFunction) \ - V(SwitchableCallMiss) + V(SwitchableCallMiss) \ + V(NotLoaded) // Note: Leaf runtime function have C linkage, so they cannot pass C++ struct // values like ObjectPtr. diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h index e78bd6ab003..db0775cbbf1 100644 --- a/runtime/vm/snapshot.h +++ b/runtime/vm/snapshot.h @@ -168,6 +168,14 @@ class Snapshot { DISALLOW_COPY_AND_ASSIGN(Snapshot); }; +inline static bool IsSnapshotCompatible(Snapshot::Kind vm_kind, + Snapshot::Kind isolate_kind) { + if (vm_kind == isolate_kind) return true; + if (vm_kind == Snapshot::kFull && isolate_kind == Snapshot::kFullJIT) + return true; + return Snapshot::IsFull(isolate_kind); +} + class BaseReader { public: BaseReader(const uint8_t* buffer, intptr_t size) : stream_(buffer, size) {} diff --git a/runtime/vm/stub_code_list.h b/runtime/vm/stub_code_list.h index 834357259b7..f759ea8cf32 100644 --- a/runtime/vm/stub_code_list.h +++ b/runtime/vm/stub_code_list.h @@ -76,6 +76,7 @@ namespace dart { V(CallClosureNoSuchMethod) \ V(FrameAwaitingMaterialization) \ V(AsynchronousGapMarker) \ + V(NotLoaded) \ V(DispatchTableNullError) \ V(NullErrorSharedWithFPURegs) \ V(NullErrorSharedWithoutFPURegs) \ diff --git a/sdk/lib/_internal/vm/lib/core_patch.dart b/sdk/lib/_internal/vm/lib/core_patch.dart index 21337633c94..b4bbd570aff 100644 --- a/sdk/lib/_internal/vm/lib/core_patch.dart +++ b/sdk/lib/_internal/vm/lib/core_patch.dart @@ -32,7 +32,7 @@ import "dart:_internal" writeIntoOneByteString, writeIntoTwoByteString; -import "dart:async" show Completer, Future, Timer; +import "dart:async" show Completer, DeferredLoadException, Future, Timer; import "dart:collection" show diff --git a/sdk/lib/_internal/vm/lib/lib_prefix.dart b/sdk/lib/_internal/vm/lib/lib_prefix.dart index d8e52fdb3e0..d0be767d172 100644 --- a/sdk/lib/_internal/vm/lib/lib_prefix.dart +++ b/sdk/lib/_internal/vm/lib/lib_prefix.dart @@ -13,6 +13,10 @@ class _LibraryPrefix { bool _isLoaded() native "LibraryPrefix_isLoaded"; void _setLoaded() native "LibraryPrefix_setLoaded"; + Object _loadingUnit() native "LibraryPrefix_loadingUnit"; + static void _issueLoad(Object unit) native "LibraryPrefix_issueLoad"; + + static final _loads = new Map>(); } class _DeferredNotLoadedError extends Error implements NoSuchMethodError { @@ -25,12 +29,42 @@ class _DeferredNotLoadedError extends Error implements NoSuchMethodError { } } +@pragma("vm:entry-point") +void _completeLoads(Object unit, String? errorMessage, bool transientError) { + Completer load = _LibraryPrefix._loads[unit]!; + if (errorMessage == null) { + load.complete(null); + } else { + if (transientError) { + _LibraryPrefix._loads.remove(unit); + } + load.completeError(new DeferredLoadException(errorMessage)); + } +} + @pragma("vm:entry-point") @pragma("vm:never-inline") // Don't duplicate prefix checking code. -Future _loadLibrary(_LibraryPrefix prefix) { - return new Future(() { - prefix._setLoaded(); - }); +Future _loadLibrary(_LibraryPrefix prefix) async { + if (!prefix._isLoaded()) { + Object unit = prefix._loadingUnit(); + // Don't issue a load request for the root unit. A deferred prefix can + // point to a library in the root unit if there is also an immediate import + // of that library. + if (unit != 1) { + Completer? load = _LibraryPrefix._loads[unit]; + if (load == null) { + _LibraryPrefix._loads[unit] = load = new Completer(); + _LibraryPrefix._issueLoad(unit); + } + await load.future; + } + // Ensure the prefix's future does not complete until the next Turn even + // when loading is a no-op or synchronous. Helps applications avoid writing + // code that only works when loading isn't really deferred. + await new Future(() { + prefix._setLoaded(); + }); + } } @pragma("vm:entry-point") diff --git a/tests/language/deferred/deferred_and_immediate_import_lib.dart b/tests/language/deferred/deferred_and_immediate_import_lib.dart new file mode 100644 index 00000000000..61eeb089e86 --- /dev/null +++ b/tests/language/deferred/deferred_and_immediate_import_lib.dart @@ -0,0 +1,7 @@ +// 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. + +foo() { + print("Foo!"); +} diff --git a/tests/language/deferred/deferred_and_immediate_import_test.dart b/tests/language/deferred/deferred_and_immediate_import_test.dart new file mode 100644 index 00000000000..d54ca7e3bef --- /dev/null +++ b/tests/language/deferred/deferred_and_immediate_import_test.dart @@ -0,0 +1,19 @@ +// 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. + +import "package:expect/expect.dart"; + +import "deferred_and_immediate_import_lib.dart" as immediatePrefix; +import "deferred_and_immediate_import_lib.dart" deferred as deferredPrefix; + +main() async { + immediatePrefix.foo(); + + Expect.throws(() { + deferredPrefix.foo(); + }); + + await deferredPrefix.loadLibrary(); + deferredPrefix.foo(); +} diff --git a/tests/language/deferred/unreachable_loading_unit_deferred.dart b/tests/language/deferred/unreachable_loading_unit_deferred.dart new file mode 100644 index 00000000000..ca5f8bdc923 --- /dev/null +++ b/tests/language/deferred/unreachable_loading_unit_deferred.dart @@ -0,0 +1,7 @@ +// 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. + +foo() { + print("Foo"); +} diff --git a/tests/language/deferred/unreachable_loading_unit_immediate.dart b/tests/language/deferred/unreachable_loading_unit_immediate.dart new file mode 100644 index 00000000000..a320045407e --- /dev/null +++ b/tests/language/deferred/unreachable_loading_unit_immediate.dart @@ -0,0 +1,10 @@ +// 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. + +import "unreachable_loading_unit_deferred.dart" deferred as lib; + +unreachable() async { + await lib.loadLibrary(); + lib.foo(); +} diff --git a/tests/language/deferred/unreachable_loading_unit_test.dart b/tests/language/deferred/unreachable_loading_unit_test.dart new file mode 100644 index 00000000000..8a663429e92 --- /dev/null +++ b/tests/language/deferred/unreachable_loading_unit_test.dart @@ -0,0 +1,9 @@ +// 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. + +import "unreachable_loading_unit_immediate.dart"; + +main() { + print("Okay"); +} diff --git a/tests/language_2/deferred/deferred_and_immediate_import_lib.dart b/tests/language_2/deferred/deferred_and_immediate_import_lib.dart new file mode 100644 index 00000000000..61eeb089e86 --- /dev/null +++ b/tests/language_2/deferred/deferred_and_immediate_import_lib.dart @@ -0,0 +1,7 @@ +// 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. + +foo() { + print("Foo!"); +} diff --git a/tests/language_2/deferred/deferred_and_immediate_import_test.dart b/tests/language_2/deferred/deferred_and_immediate_import_test.dart new file mode 100644 index 00000000000..d54ca7e3bef --- /dev/null +++ b/tests/language_2/deferred/deferred_and_immediate_import_test.dart @@ -0,0 +1,19 @@ +// 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. + +import "package:expect/expect.dart"; + +import "deferred_and_immediate_import_lib.dart" as immediatePrefix; +import "deferred_and_immediate_import_lib.dart" deferred as deferredPrefix; + +main() async { + immediatePrefix.foo(); + + Expect.throws(() { + deferredPrefix.foo(); + }); + + await deferredPrefix.loadLibrary(); + deferredPrefix.foo(); +} diff --git a/tests/language_2/deferred/unreachable_loading_unit_deferred.dart b/tests/language_2/deferred/unreachable_loading_unit_deferred.dart new file mode 100644 index 00000000000..ca5f8bdc923 --- /dev/null +++ b/tests/language_2/deferred/unreachable_loading_unit_deferred.dart @@ -0,0 +1,7 @@ +// 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. + +foo() { + print("Foo"); +} diff --git a/tests/language_2/deferred/unreachable_loading_unit_immediate.dart b/tests/language_2/deferred/unreachable_loading_unit_immediate.dart new file mode 100644 index 00000000000..a320045407e --- /dev/null +++ b/tests/language_2/deferred/unreachable_loading_unit_immediate.dart @@ -0,0 +1,10 @@ +// 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. + +import "unreachable_loading_unit_deferred.dart" deferred as lib; + +unreachable() async { + await lib.loadLibrary(); + lib.foo(); +} diff --git a/tests/language_2/deferred/unreachable_loading_unit_test.dart b/tests/language_2/deferred/unreachable_loading_unit_test.dart new file mode 100644 index 00000000000..8a663429e92 --- /dev/null +++ b/tests/language_2/deferred/unreachable_loading_unit_test.dart @@ -0,0 +1,9 @@ +// 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. + +import "unreachable_loading_unit_immediate.dart"; + +main() { + print("Okay"); +}