From b75057b6876cfa03696309c7a9ca3e2788896f34 Mon Sep 17 00:00:00 2001 From: Martin Kustermann Date: Wed, 26 Jun 2019 11:34:48 +0000 Subject: [PATCH] [vm/concurrency] Introduce concept of Isolate Groups An Isolate Group (IG) is a collection of isolates which were spawned from the same source. This allows the VM to: * have a guarantee that all isolates within one IG can safely exchange structured objects (currently we rely on embedder for this guarantee) * hot-reload all isolates together (currently we only reload one isolate, leaving same-source isolates in inconsistent state) * make a shared heap for all isolates from the same IG, which paves the way for faster communication and sharing of immutable objects. All isolates within one IG will share the same IsolateGroupSource. **Embedder changes** This change makes breaking embedder API changes to support this new concept of Isolate Groups: The existing isolate lifecycle callbacks given to Dart_Initialize will become Isolate Group lifecycle callbacks. A new callback `initialize_isolate` callback will be added which can initialize a new isolate within an existing IG. Existing embedders can be updated by performing the following renames Dart_CreateIsolate -> Dart_CreateIsolateGroup Dart_IsolateCreateCallback -> Dart_IsolateGroupCreateCallback Dart_IsolateCleanupCallback -> Dart_IsolateGroupShutdownCallback Dart_CreateIsolateFromKernel -> Dart_CreateIsolateGroupFromKernel Dart_CurrentIsolateData -> Dart_CurrentIsolateGroupData Dart_IsolateData -> Dart_IsolateGroupData Dart_GetNativeIsolateData -> Dart_GetNativeIsolateGroupData Dart_InitializeParams.create -> Dart_InitializeParams.create_group Dart_InitializeParams.cleanup -> Dart_InitializeParams.shutdown_group Dart_InitializeParams.shutdown -> Dart_InitializeParams.shutdown_isolate By default `Isolate.spawn` will cause the creation of a new IG. Though an embedder can opt-into supporting multiple isolates within one IG by providing a callback to the newly added `Dart_InitializeParams.initialize_isolate`. The responsibility of this new callback is to initialize an existing isolate (which was setup by re-using source code from the spawning isolate - i.e. the one which used `Isolate.spawn`) by setting native resolvers, initializing global state, etc. Issue https://github.com/dart-lang/sdk/issues/36648 Issue https://github.com/dart-lang/sdk/issues/36097 Change-Id: I82437ac017ca33018d45e02f353b0672db155f6a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105241 Commit-Queue: Martin Kustermann Reviewed-by: Ryan Macnak Reviewed-by: Alexander Aprelev --- runtime/bin/dart_embedder_api_impl.cc | 8 +- runtime/bin/gen_snapshot.cc | 23 +- runtime/bin/isolate_data.cc | 13 +- runtime/bin/isolate_data.h | 28 +- runtime/bin/loader.cc | 83 ++--- runtime/bin/loader.h | 12 +- runtime/bin/main.cc | 320 +++++++++++------- runtime/bin/run_vm_tests.cc | 56 +-- runtime/include/dart_api.h | 188 ++++++---- runtime/include/dart_embedder_api.h | 9 +- runtime/lib/isolate.cc | 81 ++++- .../tests/service/get_source_report_test.dart | 2 +- .../service/get_vm_timeline_rpc_test.dart | 2 +- runtime/vm/dart.cc | 19 +- runtime/vm/dart.h | 4 +- runtime/vm/dart_api_impl.cc | 226 +++++++++---- runtime/vm/dart_api_impl.h | 12 +- runtime/vm/dart_api_impl_test.cc | 113 +++++-- runtime/vm/isolate.cc | 41 ++- runtime/vm/isolate.h | 115 ++++++- runtime/vm/kernel_isolate.cc | 16 +- runtime/vm/kernel_isolate.h | 6 +- runtime/vm/service_isolate.cc | 15 +- runtime/vm/service_isolate.h | 6 +- runtime/vm/unit_test.cc | 24 +- runtime/vm/unit_test.h | 12 +- ...a569caac6431d8698dc3788579b57ffcf0c6.patch | 147 ++++++++ 27 files changed, 1122 insertions(+), 459 deletions(-) create mode 100644 tools/patches/flutter-engine/7340a569caac6431d8698dc3788579b57ffcf0c6.patch diff --git a/runtime/bin/dart_embedder_api_impl.cc b/runtime/bin/dart_embedder_api_impl.cc index 492aab89b211..cf2116aec218 100644 --- a/runtime/bin/dart_embedder_api_impl.cc +++ b/runtime/bin/dart_embedder_api_impl.cc @@ -45,9 +45,9 @@ Dart_Isolate CreateKernelServiceIsolate(const IsolateCreationData& data, const uint8_t* buffer, intptr_t buffer_size, char** error) { - Dart_Isolate kernel_isolate = Dart_CreateIsolateFromKernel( + Dart_Isolate kernel_isolate = Dart_CreateIsolateGroupFromKernel( data.script_uri, data.main, buffer, buffer_size, data.flags, - data.callback_data, error); + data.isolate_group_data, data.isolate_data, error); if (kernel_isolate == nullptr) { return nullptr; } @@ -78,9 +78,9 @@ Dart_Isolate CreateVmServiceIsolate(const IsolateCreationData& data, } data.flags->load_vmservice_library = true; - Dart_Isolate service_isolate = Dart_CreateIsolateFromKernel( + Dart_Isolate service_isolate = Dart_CreateIsolateGroupFromKernel( data.script_uri, data.main, kernel_buffer, kernel_buffer_size, data.flags, - data.callback_data, error); + data.isolate_group_data, data.isolate_data, error); if (service_isolate == nullptr) { return nullptr; } diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc index fbd41ce413f7..f4203b6bfd16 100644 --- a/runtime/bin/gen_snapshot.cc +++ b/runtime/bin/gen_snapshot.cc @@ -745,23 +745,24 @@ static int CreateIsolateAndSnapshot(const CommandLineOptions& inputs) { isolate_flags.entry_points = no_entry_points; } - IsolateData* isolate_data = new IsolateData(NULL, NULL, NULL, NULL); + auto isolate_group_data = new IsolateGroupData(NULL, NULL, NULL, NULL); Dart_Isolate isolate; char* error = NULL; if (isolate_snapshot_data == NULL) { // We need to capture the vmservice library in the core snapshot, so load it // in the main isolate as well. isolate_flags.load_vmservice_library = true; - isolate = Dart_CreateIsolateFromKernel(NULL, NULL, kernel_buffer, - kernel_buffer_size, &isolate_flags, - isolate_data, &error); + isolate = Dart_CreateIsolateGroupFromKernel( + NULL, NULL, kernel_buffer, kernel_buffer_size, &isolate_flags, + isolate_group_data, /*isolate_data=*/nullptr, &error); } else { - isolate = Dart_CreateIsolate(NULL, NULL, isolate_snapshot_data, - isolate_snapshot_instructions, NULL, NULL, - &isolate_flags, isolate_data, &error); + isolate = Dart_CreateIsolateGroup(NULL, NULL, isolate_snapshot_data, + isolate_snapshot_instructions, NULL, NULL, + &isolate_flags, isolate_group_data, + /*isolate_data=*/nullptr, &error); } if (isolate == NULL) { - delete isolate_data; + delete isolate_group_data; Syslog::PrintErr("%s\n", error); free(error); return kErrorExitCode; @@ -783,9 +784,9 @@ static int CreateIsolateAndSnapshot(const CommandLineOptions& inputs) { // If the input dill file does not have a root library, then // Dart_LoadScript will error. // - // TODO(kernel): Dart_CreateIsolateFromKernel should respect the root library - // in the kernel file, though this requires auditing the other loading paths - // in the embedders that had to work around this. + // TODO(kernel): Dart_CreateIsolateGroupFromKernel should respect the root + // library in the kernel file, though this requires auditing the other + // loading paths in the embedders that had to work around this. result = Dart_SetRootLibrary( Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size)); CHECK_RESULT(result); diff --git a/runtime/bin/isolate_data.cc b/runtime/bin/isolate_data.cc index 54b10507b4b1..bb270a311390 100644 --- a/runtime/bin/isolate_data.cc +++ b/runtime/bin/isolate_data.cc @@ -9,10 +9,10 @@ namespace dart { namespace bin { -IsolateData::IsolateData(const char* url, - const char* package_root, - const char* packages_file, - AppSnapshot* app_snapshot) +IsolateGroupData::IsolateGroupData(const char* url, + const char* package_root, + const char* packages_file, + AppSnapshot* app_snapshot) : script_url((url != NULL) ? strdup(url) : NULL), package_root(NULL), packages_file(NULL), @@ -30,10 +30,7 @@ IsolateData::IsolateData(const char* url, } } -void IsolateData::OnIsolateShutdown() { -} - -IsolateData::~IsolateData() { +IsolateGroupData::~IsolateGroupData() { free(script_url); script_url = NULL; free(package_root); diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h index 528f39709cca..07445df2aaeb 100644 --- a/runtime/bin/isolate_data.h +++ b/runtime/bin/isolate_data.h @@ -31,13 +31,13 @@ class Loader; // Data associated with every isolate in the standalone VM // embedding. This is used to free external resources for each isolate // when the isolate shuts down. -class IsolateData { +class IsolateGroupData { public: - IsolateData(const char* url, - const char* package_root, - const char* packages_file, - AppSnapshot* app_snapshot); - ~IsolateData(); + IsolateGroupData(const char* url, + const char* package_root, + const char* packages_file, + AppSnapshot* app_snapshot); + ~IsolateGroupData(); char* script_url; char* package_root; @@ -49,16 +49,16 @@ class IsolateData { intptr_t kernel_buffer_size() const { return kernel_buffer_size_; } - // Associate the given kernel buffer with this IsolateData without giving it - // ownership of the buffer. + // Associate the given kernel buffer with this IsolateGroupData without + // giving it ownership of the buffer. void SetKernelBufferUnowned(uint8_t* buffer, intptr_t size) { ASSERT(kernel_buffer_.get() == NULL); kernel_buffer_ = std::shared_ptr(buffer, FreeUnownedKernelBuffer); kernel_buffer_size_ = size; } - // Associate the given kernel buffer with this IsolateData and give it - // ownership of the buffer. This IsolateData is the first one to own the + // Associate the given kernel buffer with this IsolateGroupData and give it + // ownership of the buffer. This IsolateGroupData is the first one to own the // buffer. void SetKernelBufferNewlyOwned(uint8_t* buffer, intptr_t size) { ASSERT(kernel_buffer_.get() == NULL); @@ -66,9 +66,9 @@ class IsolateData { kernel_buffer_size_ = size; } - // Associate the given kernel buffer with this IsolateData and give it + // Associate the given kernel buffer with this IsolateGroupData and give it // ownership of the buffer. The buffer is already owned by another - // IsolateData. + // IsolateGroupData. void SetKernelBufferAlreadyOwned(std::shared_ptr buffer, intptr_t size) { ASSERT(kernel_buffer_.get() == NULL); @@ -111,7 +111,7 @@ class IsolateData { dependencies_ = deps; } - void OnIsolateShutdown(); + bool RunFromAppSnapshot() const { return app_snapshot_ != nullptr; } private: Loader* loader_; @@ -123,7 +123,7 @@ class IsolateData { static void FreeUnownedKernelBuffer(uint8_t*) {} - DISALLOW_COPY_AND_ASSIGN(IsolateData); + DISALLOW_COPY_AND_ASSIGN(IsolateGroupData); }; } // namespace bin diff --git a/runtime/bin/loader.cc b/runtime/bin/loader.cc index a56cdc2f7d16..9467fa60c769 100644 --- a/runtime/bin/loader.cc +++ b/runtime/bin/loader.cc @@ -29,9 +29,9 @@ extern DFE dfe; static const intptr_t _Dart_kImportExtension = 9; static const intptr_t _Dart_kResolveAsFilePath = 10; -Loader::Loader(IsolateData* isolate_data) +Loader::Loader(IsolateGroupData* isolate_group_data) : port_(ILLEGAL_PORT), - isolate_data_(isolate_data), + isolate_group_data_(isolate_group_data), error_(Dart_Null()), monitor_(), pending_operations_(0), @@ -40,10 +40,10 @@ Loader::Loader(IsolateData* isolate_data) results_capacity_(0), payload_(NULL), payload_length_(0) { - ASSERT(isolate_data_ != NULL); + ASSERT(isolate_group_data_ != NULL); port_ = Dart_NewNativePort("Loader", Loader::NativeMessageHandler, false); - isolate_data_->set_loader(this); - AddLoader(port_, isolate_data_); + isolate_group_data_->set_loader(this); + AddLoader(port_, isolate_group_data_); } Loader::~Loader() { @@ -55,8 +55,8 @@ Loader::~Loader() { monitor_.Exit(); RemoveLoader(port_); port_ = ILLEGAL_PORT; - isolate_data_->set_loader(NULL); - isolate_data_ = NULL; + isolate_group_data_->set_loader(NULL); + isolate_group_data_ = NULL; for (intptr_t i = 0; i < results_length_; i++) { results_[i].Cleanup(); } @@ -263,7 +263,7 @@ static bool PathContainsSeparator(const char* path) { void Loader::AddDependencyLocked(Loader* loader, const char* resolved_uri) { MallocGrowableArray* dependencies = - loader->isolate_data_->dependencies(); + loader->isolate_group_data_->dependencies(); if (dependencies == NULL) { return; } @@ -271,10 +271,10 @@ void Loader::AddDependencyLocked(Loader* loader, const char* resolved_uri) { } void Loader::ResolveDependenciesAsFilePaths() { - IsolateData* isolate_data = - reinterpret_cast(Dart_CurrentIsolateData()); - ASSERT(isolate_data != NULL); - MallocGrowableArray* dependencies = isolate_data->dependencies(); + IsolateGroupData* isolate_group_data = + reinterpret_cast(Dart_CurrentIsolateGroupData()); + ASSERT(isolate_group_data != NULL); + MallocGrowableArray* dependencies = isolate_group_data->dependencies(); if (dependencies == NULL) { return; } @@ -455,14 +455,15 @@ bool Loader::ProcessQueueLocked(ProcessResult process_result) { } void Loader::InitForSnapshot(const char* snapshot_uri) { - IsolateData* isolate_data = - reinterpret_cast(Dart_CurrentIsolateData()); - ASSERT(isolate_data != NULL); - ASSERT(!isolate_data->HasLoader()); + IsolateGroupData* isolate_group_data = + reinterpret_cast(Dart_CurrentIsolateGroupData()); + ASSERT(isolate_group_data != NULL); + ASSERT(!isolate_group_data->HasLoader()); // Setup a loader. The constructor does a bunch of leg work. - Loader* loader = new Loader(isolate_data); + Loader* loader = new Loader(isolate_group_data); // Send the init message. - loader->Init(isolate_data->package_root, isolate_data->packages_file, + loader->Init(isolate_group_data->package_root, + isolate_group_data->packages_file, DartUtils::original_working_directory, snapshot_uri); // Destroy the loader. The destructor does a bunch of leg work. delete loader; @@ -516,18 +517,19 @@ Dart_Handle Loader::SendAndProcessReply(intptr_t tag, Dart_Handle url, uint8_t** payload, intptr_t* payload_length) { - IsolateData* isolate_data = - reinterpret_cast(Dart_CurrentIsolateData()); - ASSERT(isolate_data != NULL); - ASSERT(!isolate_data->HasLoader()); + IsolateGroupData* isolate_group_data = + reinterpret_cast(Dart_CurrentIsolateGroupData()); + ASSERT(isolate_group_data != NULL); + ASSERT(!isolate_group_data->HasLoader()); Loader* loader = NULL; // Setup the loader. The constructor does a bunch of leg work. - loader = new Loader(isolate_data); - loader->Init(isolate_data->package_root, isolate_data->packages_file, + loader = new Loader(isolate_group_data); + loader->Init(isolate_group_data->package_root, + isolate_group_data->packages_file, DartUtils::original_working_directory, NULL); ASSERT(loader != NULL); - ASSERT(isolate_data->HasLoader()); + ASSERT(isolate_group_data->HasLoader()); // Now send a load request to the service isolate. loader->SendRequest(tag, url, Dart_Null()); @@ -679,9 +681,9 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag, } } - IsolateData* isolate_data = - reinterpret_cast(Dart_CurrentIsolateData()); - ASSERT(isolate_data != NULL); + IsolateGroupData* isolate_group_data = + reinterpret_cast(Dart_CurrentIsolateGroupData()); + ASSERT(isolate_group_data != NULL); if ((tag == Dart_kScriptTag) && Dart_IsString(library)) { // Update packages file for isolate. const char* packages_file = NULL; @@ -689,25 +691,26 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag, if (Dart_IsError(result)) { return result; } - isolate_data->UpdatePackagesFile(packages_file); + isolate_group_data->UpdatePackagesFile(packages_file); } // Grab this isolate's loader. Loader* loader = NULL; // The outer invocation of the tag handler for this isolate. We make the outer // invocation block and allow any nested invocations to operate in parallel. - const bool blocking_call = !isolate_data->HasLoader(); + const bool blocking_call = !isolate_group_data->HasLoader(); // If we are the outer invocation of the tag handler and the tag is an import // this means that we are starting a deferred library load. const bool is_deferred_import = blocking_call && (tag == Dart_kImportTag); - if (!isolate_data->HasLoader()) { + if (!isolate_group_data->HasLoader()) { // The isolate doesn't have a loader -- this is the outer invocation which // will block. // Setup the loader. The constructor does a bunch of leg work. - loader = new Loader(isolate_data); - loader->Init(isolate_data->package_root, isolate_data->packages_file, + loader = new Loader(isolate_group_data); + loader->Init(isolate_group_data->package_root, + isolate_group_data->packages_file, DartUtils::original_working_directory, (tag == Dart_kScriptTag) ? url_string : NULL); } else { @@ -715,10 +718,10 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag, // The isolate has a loader -- this is an inner invocation that will queue // work with the service isolate. // Use the existing loader. - loader = isolate_data->loader(); + loader = isolate_group_data->loader(); } ASSERT(loader != NULL); - ASSERT(isolate_data->HasLoader()); + ASSERT(isolate_group_data->HasLoader()); if (DartUtils::IsDartExtensionSchemeURL(url_string)) { loader->SendImportExtensionRequest(url, Dart_LibraryUrl(library)); @@ -815,11 +818,11 @@ Loader::LoaderInfo* Loader::loader_infos_ = NULL; intptr_t Loader::loader_infos_length_ = 0; intptr_t Loader::loader_infos_capacity_ = 0; -// Add a mapping from |port| to |isolate_data| (really the loader). When a +// Add a mapping from |port| to |isolate_group_data| (really the loader). When a // native message arrives, we use this map to report the I/O result to the // correct loader. // This happens whenever an isolate begins loading. -void Loader::AddLoader(Dart_Port port, IsolateData* isolate_data) { +void Loader::AddLoader(Dart_Port port, IsolateGroupData* isolate_group_data) { MutexLocker ml(loader_infos_lock_); ASSERT(LoaderForLocked(port) == NULL); if (loader_infos_length_ == loader_infos_capacity_) { @@ -832,12 +835,12 @@ void Loader::AddLoader(Dart_Port port, IsolateData* isolate_data) { // Initialize new entries. for (intptr_t i = loader_infos_length_; i < loader_infos_capacity_; i++) { loader_infos_[i].port = ILLEGAL_PORT; - loader_infos_[i].isolate_data = NULL; + loader_infos_[i].isolate_group_data = NULL; } } ASSERT(loader_infos_length_ < loader_infos_capacity_); loader_infos_[loader_infos_length_].port = port; - loader_infos_[loader_infos_length_].isolate_data = isolate_data; + loader_infos_[loader_infos_length_].isolate_group_data = isolate_group_data; loader_infos_length_++; ASSERT(LoaderForLocked(port) != NULL); } @@ -871,7 +874,7 @@ Loader* Loader::LoaderForLocked(Dart_Port port) { if (index < 0) { return NULL; } - return loader_infos_[index].isolate_data->loader(); + return loader_infos_[index].isolate_group_data->loader(); } Loader* Loader::LoaderFor(Dart_Port port) { diff --git a/runtime/bin/loader.h b/runtime/bin/loader.h index 4142c897bc2f..d2f950af1bf8 100644 --- a/runtime/bin/loader.h +++ b/runtime/bin/loader.h @@ -17,7 +17,7 @@ namespace bin { class Loader { public: - explicit Loader(IsolateData* isolate_data); + explicit Loader(IsolateGroupData* isolate_group_data); ~Loader(); static void InitForSnapshot(const char* snapshot_uri); @@ -43,8 +43,8 @@ class Loader { private: // The port assigned to our native message handler. Dart_Port port_; - // Each Loader is associated with an Isolate via its IsolateData. - IsolateData* isolate_data_; + // Each Loader is associated with an Isolate via its IsolateGroupData. + IsolateGroupData* isolate_group_data_; // Remember the first error that occurs during loading. Dart_Handle error_; // This monitor is used to protect the pending operations count and the @@ -128,12 +128,12 @@ class Loader { // We use one native message handler callback for N loaders. The native // message handler callback provides us with the Dart_Port which we use as a - // key into our map of active loaders from |port| to |isolate_data|. + // key into our map of active loaders from |port| to |isolate_group_data|. // Static information to map Dart_Port back to the isolate in question. struct LoaderInfo { Dart_Port port; - IsolateData* isolate_data; + IsolateGroupData* isolate_group_data; }; // The map of active loaders. @@ -142,7 +142,7 @@ class Loader { static intptr_t loader_infos_length_; static intptr_t loader_infos_capacity_; - static void AddLoader(Dart_Port port, IsolateData* data); + static void AddLoader(Dart_Port port, IsolateGroupData* data); static void RemoveLoader(Dart_Port port); static intptr_t LoaderIndexFor(Dart_Port port); static Loader* LoaderFor(Dart_Port port); diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc index c9edf664e3cd..222c09205124 100644 --- a/runtime/bin/main.cc +++ b/runtime/bin/main.cc @@ -133,10 +133,10 @@ static void WriteDepsFile(Dart_Isolate isolate) { return; } Loader::ResolveDependenciesAsFilePaths(); - IsolateData* isolate_data = - reinterpret_cast(Dart_IsolateData(isolate)); - ASSERT(isolate_data != NULL); - MallocGrowableArray* dependencies = isolate_data->dependencies(); + auto isolate_group_data = + reinterpret_cast(Dart_IsolateGroupData(isolate)); + ASSERT(isolate_group_data != NULL); + MallocGrowableArray* dependencies = isolate_group_data->dependencies(); ASSERT(dependencies != NULL); File* file = File::Open(NULL, Options::depfile(), File::kWriteTruncate); @@ -191,57 +191,145 @@ static void OnExitHook(int64_t exit_code) { } } -static Dart_Isolate IsolateSetupHelper(Dart_Isolate isolate, - bool is_main_isolate, - const char* script_uri, - const char* package_root, - const char* packages_config, - bool isolate_run_app_snapshot, - Dart_IsolateFlags* flags, - char** error, - int* exit_code) { - Dart_EnterScope(); -#if !defined(DART_PRECOMPILED_RUNTIME) - IsolateData* isolate_data = - reinterpret_cast(Dart_IsolateData(isolate)); - const uint8_t* kernel_buffer = isolate_data->kernel_buffer().get(); - intptr_t kernel_buffer_size = isolate_data->kernel_buffer_size(); -#endif +static Dart_Handle SetupCoreLibraries(Dart_Isolate isolate, + IsolateGroupData* isolate_group_data, + bool is_isolate_group_start, + const char** resolved_packages_config) { + const auto packages_file = isolate_group_data->packages_file; + const auto script_uri = isolate_group_data->script_url; + + Dart_Handle result; // Set up the library tag handler for this isolate. - Dart_Handle result = Dart_SetLibraryTagHandler(Loader::LibraryTagHandler); - CHECK_RESULT(result); + result = Dart_SetLibraryTagHandler(Loader::LibraryTagHandler); + if (Dart_IsError(result)) return result; // Prepare builtin and other core libraries for use to resolve URIs. // Set up various closures, e.g: printing, timers etc. // Set up 'package root' for URI resolution. result = DartUtils::PrepareForScriptLoading(false, Options::trace_loading()); - CHECK_RESULT(result); + if (Dart_IsError(result)) return result; if (Dart_IsVMFlagSet("support_service") || !Dart_IsPrecompiledRuntime()) { // Set up the load port provided by the service isolate so that we can // load scripts. result = DartUtils::SetupServiceLoadPort(); - CHECK_RESULT(result); + if (Dart_IsError(result)) return result; } // Setup package root if specified. - result = DartUtils::SetupPackageRoot(NULL, packages_config); - CHECK_RESULT(result); - const char* resolved_packages_config = NULL; - if (!Dart_IsNull(result)) { - result = Dart_StringToCString(result, &resolved_packages_config); - CHECK_RESULT(result); - ASSERT(resolved_packages_config != NULL); + result = DartUtils::SetupPackageRoot(nullptr, packages_file); + if (Dart_IsError(result)) return result; + if (!Dart_IsNull(result) && resolved_packages_config != nullptr) { + result = Dart_StringToCString(result, resolved_packages_config); + if (Dart_IsError(result)) return result; + ASSERT(*resolved_packages_config != nullptr); + #if !defined(DART_PRECOMPILED_RUNTIME) - isolate_data->set_resolved_packages_config(resolved_packages_config); + if (is_isolate_group_start) { + isolate_group_data->set_resolved_packages_config( + *resolved_packages_config); + } else { + ASSERT(strcmp(isolate_group_data->resolved_packages_config(), + *resolved_packages_config) == 0); + } #endif } result = Dart_SetEnvironmentCallback(DartUtils::EnvironmentCallback); + if (Dart_IsError(result)) return result; + + // Setup the native resolver as the snapshot does not carry it. + Builtin::SetNativeResolver(Builtin::kBuiltinLibrary); + Builtin::SetNativeResolver(Builtin::kIOLibrary); + Builtin::SetNativeResolver(Builtin::kCLILibrary); + VmService::SetNativeResolver(); + + const char* namespc = + Dart_IsKernelIsolate(isolate) ? NULL : Options::namespc(); + result = + DartUtils::SetupIOLibrary(namespc, script_uri, Options::exit_disabled()); + if (Dart_IsError(result)) return result; + + return Dart_Null(); +} + +static bool OnIsolateInitialize(void** child_callback_data, char** error) { + Dart_Isolate isolate = Dart_CurrentIsolate(); + ASSERT(isolate != nullptr); + + auto isolate_group_data = + reinterpret_cast(Dart_CurrentIsolateGroupData()); + + Dart_EnterScope(); + const auto script_uri = isolate_group_data->script_url; + const bool isolate_run_app_snapshot = + isolate_group_data->RunFromAppSnapshot(); + Dart_Handle result = SetupCoreLibraries(isolate, isolate_group_data, + /*group_start=*/false, + /*resolved_packages_config=*/nullptr); + if (Dart_IsError(result)) goto failed; + + if (isolate_run_app_snapshot) { + if (Dart_IsVMFlagSet("support_service") || !Dart_IsPrecompiledRuntime()) { + Loader::InitForSnapshot(script_uri); + } + } else { + result = DartUtils::ResolveScript(Dart_NewStringFromCString(script_uri)); + if (Dart_IsError(result)) return result; + + if (isolate_group_data->kernel_buffer().get() != nullptr) { + // Various core-library parts will send requests to the Loader to resolve + // relative URIs and perform other related tasks. We need Loader to be + // initialized for this to work because loading from Kernel binary + // bypasses normal source code loading paths that initialize it. + const char* resolved_script_uri = NULL; + result = Dart_StringToCString(result, &resolved_script_uri); + if (Dart_IsError(result)) return result; + Loader::InitForSnapshot(resolved_script_uri); + } + } + + if (isolate_run_app_snapshot) { + result = Loader::ReloadNativeExtensions(); + if (Dart_IsError(result)) goto failed; + } + + // Make the isolate runnable so that it is ready to handle messages. + Dart_ExitScope(); + Dart_ExitIsolate(); + *error = Dart_IsolateMakeRunnable(isolate); + Dart_EnterIsolate(isolate); + return *error == nullptr; + +failed: + *error = strdup(Dart_GetError(result)); + Dart_ExitScope(); + return false; +} + +static Dart_Isolate IsolateSetupHelper(Dart_Isolate isolate, + bool is_main_isolate, + const char* script_uri, + const char* packages_config, + bool isolate_run_app_snapshot, + Dart_IsolateFlags* flags, + char** error, + int* exit_code) { + Dart_EnterScope(); + + auto isolate_group_data = + reinterpret_cast(Dart_IsolateGroupData(isolate)); + + const char* resolved_packages_config = nullptr; + Dart_Handle result = SetupCoreLibraries(isolate, isolate_group_data, + /*is_isolate_group_start=*/true, + &resolved_packages_config); CHECK_RESULT(result); #if !defined(DART_PRECOMPILED_RUNTIME) + const uint8_t* kernel_buffer = isolate_group_data->kernel_buffer().get(); + intptr_t kernel_buffer_size = isolate_group_data->kernel_buffer_size(); if (!isolate_run_app_snapshot && kernel_buffer == NULL && !Dart_IsKernelIsolate(isolate)) { if (!dfe.CanUseDartFrontend()) { @@ -265,8 +353,8 @@ static Dart_Isolate IsolateSetupHelper(Dart_Isolate isolate, Dart_ShutdownIsolate(); return NULL; } - isolate_data->SetKernelBufferNewlyOwned(application_kernel_buffer, - application_kernel_buffer_size); + isolate_group_data->SetKernelBufferNewlyOwned( + application_kernel_buffer, application_kernel_buffer_size); kernel_buffer = application_kernel_buffer; kernel_buffer_size = application_kernel_buffer_size; } @@ -280,23 +368,12 @@ static Dart_Isolate IsolateSetupHelper(Dart_Isolate isolate, } #endif // !defined(DART_PRECOMPILED_RUNTIME) - // Setup the native resolver as the snapshot does not carry it. - Builtin::SetNativeResolver(Builtin::kBuiltinLibrary); - Builtin::SetNativeResolver(Builtin::kIOLibrary); - Builtin::SetNativeResolver(Builtin::kCLILibrary); - VmService::SetNativeResolver(); - if (isolate_run_app_snapshot) { Dart_Handle result = Loader::ReloadNativeExtensions(); CHECK_RESULT(result); } - const char* namespc = - Dart_IsKernelIsolate(isolate) ? NULL : Options::namespc(); if (isolate_run_app_snapshot) { - result = DartUtils::SetupIOLibrary(namespc, script_uri, - Options::exit_disabled()); - CHECK_RESULT(result); if (Dart_IsVMFlagSet("support_service") || !Dart_IsPrecompiledRuntime()) { Loader::InitForSnapshot(script_uri); } @@ -336,10 +413,6 @@ static Dart_Isolate IsolateSetupHelper(Dart_Isolate isolate, Dart_TimelineEvent("LoadScript", Dart_TimelineGetMicros(), Dart_GetMainPortId(), Dart_Timeline_Event_Async_End, 0, NULL, NULL); - - result = DartUtils::SetupIOLibrary(namespc, script_uri, - Options::exit_disabled()); - CHECK_RESULT(result); #else UNREACHABLE(); #endif // !defined(DART_PRECOMPILED_RUNTIME) @@ -397,7 +470,7 @@ static Dart_Isolate CreateAndSetupKernelIsolate(const char* script_uri, } Dart_Isolate isolate = NULL; - IsolateData* isolate_data = NULL; + IsolateGroupData* isolate_group_data = NULL; bool isolate_run_app_snapshot = false; AppSnapshot* app_snapshot = NULL; // Kernel isolate uses an app snapshot or uses the dill file. @@ -412,42 +485,43 @@ static Dart_Isolate CreateAndSetupKernelIsolate(const char* script_uri, app_snapshot->SetBuffers( &ignore_vm_snapshot_data, &ignore_vm_snapshot_instructions, &isolate_snapshot_data, &isolate_snapshot_instructions); - isolate_data = - new IsolateData(uri, package_root, packages_config, app_snapshot); - isolate = Dart_CreateIsolate( + isolate_group_data = + new IsolateGroupData(uri, package_root, packages_config, app_snapshot); + isolate = Dart_CreateIsolateGroup( DART_KERNEL_ISOLATE_NAME, DART_KERNEL_ISOLATE_NAME, isolate_snapshot_data, isolate_snapshot_instructions, app_isolate_shared_data, app_isolate_shared_instructions, flags, - isolate_data, error); + isolate_group_data, /*isolate_data=*/nullptr, error); } if (isolate == NULL) { // Clear error from app snapshot and re-trying from kernel file. free(*error); *error = NULL; - delete isolate_data; + delete isolate_group_data; const uint8_t* kernel_service_buffer = NULL; intptr_t kernel_service_buffer_size = 0; dfe.LoadKernelService(&kernel_service_buffer, &kernel_service_buffer_size); ASSERT(kernel_service_buffer != NULL); - isolate_data = new IsolateData(uri, package_root, packages_config, NULL); - isolate_data->SetKernelBufferUnowned( + isolate_group_data = + new IsolateGroupData(uri, package_root, packages_config, NULL); + isolate_group_data->SetKernelBufferUnowned( const_cast(kernel_service_buffer), kernel_service_buffer_size); - isolate = Dart_CreateIsolateFromKernel( + isolate = Dart_CreateIsolateGroupFromKernel( DART_KERNEL_ISOLATE_NAME, DART_KERNEL_ISOLATE_NAME, - kernel_service_buffer, kernel_service_buffer_size, flags, isolate_data, - error); + kernel_service_buffer, kernel_service_buffer_size, flags, + isolate_group_data, nullptr, error); } if (isolate == NULL) { Syslog::PrintErr("%s\n", *error); - delete isolate_data; + delete isolate_group_data; return NULL; } kernel_isolate_is_running = true; - return IsolateSetupHelper(isolate, false, uri, package_root, packages_config, + return IsolateSetupHelper(isolate, false, uri, packages_config, isolate_run_app_snapshot, flags, error, exit_code); } #endif // !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM) @@ -463,18 +537,19 @@ static Dart_Isolate CreateAndSetupServiceIsolate(const char* script_uri, int* exit_code) { ASSERT(script_uri != NULL); Dart_Isolate isolate = NULL; - IsolateData* isolate_data = - new IsolateData(script_uri, package_root, packages_config, NULL); + IsolateGroupData* isolate_group_data = + new IsolateGroupData(script_uri, package_root, packages_config, NULL); #if defined(DART_PRECOMPILED_RUNTIME) // AOT: All isolates start from the app snapshot. const uint8_t* isolate_snapshot_data = app_isolate_snapshot_data; const uint8_t* isolate_snapshot_instructions = app_isolate_snapshot_instructions; - isolate = Dart_CreateIsolate( + isolate = Dart_CreateIsolateGroup( script_uri, DART_VM_SERVICE_ISOLATE_NAME, isolate_snapshot_data, isolate_snapshot_instructions, app_isolate_shared_data, - app_isolate_shared_instructions, flags, isolate_data, error); + app_isolate_shared_instructions, flags, isolate_group_data, + /*isolate_data=*/nullptr, error); #else // JIT: Service isolate uses the core libraries snapshot. @@ -484,13 +559,14 @@ static Dart_Isolate CreateAndSetupServiceIsolate(const char* script_uri, const uint8_t* isolate_snapshot_data = core_isolate_snapshot_data; const uint8_t* isolate_snapshot_instructions = core_isolate_snapshot_instructions; - isolate = Dart_CreateIsolate( + isolate = Dart_CreateIsolateGroup( script_uri, DART_VM_SERVICE_ISOLATE_NAME, isolate_snapshot_data, isolate_snapshot_instructions, app_isolate_shared_data, - app_isolate_shared_instructions, flags, isolate_data, error); + app_isolate_shared_instructions, flags, isolate_group_data, + /*isolate_data=*/nullptr, error); #endif // !defined(DART_PRECOMPILED_RUNTIME) if (isolate == NULL) { - delete isolate_data; + delete isolate_group_data; return NULL; } @@ -519,15 +595,16 @@ static Dart_Isolate CreateAndSetupServiceIsolate(const char* script_uri, } // Returns newly created Isolate on success, NULL on failure. -static Dart_Isolate CreateIsolateAndSetupHelper(bool is_main_isolate, - const char* script_uri, - const char* name, - const char* package_root, - const char* packages_config, - Dart_IsolateFlags* flags, - void* callback_data, - char** error, - int* exit_code) { +static Dart_Isolate CreateIsolateGroupAndSetupHelper( + bool is_main_isolate, + const char* script_uri, + const char* name, + const char* package_root, + const char* packages_config, + Dart_IsolateFlags* flags, + void* callback_data, + char** error, + int* exit_code) { int64_t start = Dart_TimelineGetMicros(); ASSERT(script_uri != NULL); uint8_t* kernel_buffer = NULL; @@ -567,8 +644,8 @@ static Dart_Isolate CreateIsolateAndSetupHelper(bool is_main_isolate, } if (flags->copy_parent_code && callback_data) { - IsolateData* parent_isolate_data = - reinterpret_cast(callback_data); + IsolateGroupData* parent_isolate_data = + reinterpret_cast(callback_data); parent_kernel_buffer = parent_isolate_data->kernel_buffer(); kernel_buffer = parent_kernel_buffer.get(); kernel_buffer_size = parent_isolate_data->kernel_buffer_size(); @@ -579,19 +656,19 @@ static Dart_Isolate CreateIsolateAndSetupHelper(bool is_main_isolate, } #endif // !defined(DART_PRECOMPILED_RUNTIME) - IsolateData* isolate_data = - new IsolateData(script_uri, package_root, packages_config, app_snapshot); + IsolateGroupData* isolate_group_data = new IsolateGroupData( + script_uri, package_root, packages_config, app_snapshot); if (kernel_buffer != NULL) { if (parent_kernel_buffer) { - isolate_data->SetKernelBufferAlreadyOwned(std::move(parent_kernel_buffer), - kernel_buffer_size); + isolate_group_data->SetKernelBufferAlreadyOwned( + std::move(parent_kernel_buffer), kernel_buffer_size); } else { - isolate_data->SetKernelBufferNewlyOwned(kernel_buffer, - kernel_buffer_size); + isolate_group_data->SetKernelBufferNewlyOwned(kernel_buffer, + kernel_buffer_size); } } if (is_main_isolate && (Options::depfile() != NULL)) { - isolate_data->set_dependencies(new MallocGrowableArray()); + isolate_group_data->set_dependencies(new MallocGrowableArray()); } Dart_Isolate isolate = NULL; @@ -618,45 +695,45 @@ static Dart_Isolate CreateIsolateAndSetupHelper(bool is_main_isolate, // TODO(sivachandra): When the platform program is unavailable, check if // application kernel binary is self contained or an incremental binary. // Isolate should be created only if it is a self contained kernel binary. - isolate = Dart_CreateIsolateFromKernel( + isolate = Dart_CreateIsolateGroupFromKernel( script_uri, name, platform_kernel_buffer, platform_kernel_buffer_size, - flags, isolate_data, error); + flags, isolate_group_data, /*isolate_data=*/nullptr, error); } else { - isolate = Dart_CreateIsolate( + isolate = Dart_CreateIsolateGroup( script_uri, name, isolate_snapshot_data, isolate_snapshot_instructions, app_isolate_shared_data, app_isolate_shared_instructions, flags, - isolate_data, error); + isolate_group_data, /*isolate_data=*/nullptr, error); } #else - isolate = Dart_CreateIsolate( + isolate = Dart_CreateIsolateGroup( script_uri, name, isolate_snapshot_data, isolate_snapshot_instructions, app_isolate_shared_data, app_isolate_shared_instructions, flags, - isolate_data, error); + isolate_group_data, /*isolate_data=*/nullptr, error); #endif // !defined(DART_PRECOMPILED_RUNTIME) Dart_Isolate created_isolate = NULL; if (isolate == NULL) { - delete isolate_data; + delete isolate_group_data; } else { created_isolate = IsolateSetupHelper( - isolate, is_main_isolate, script_uri, package_root, packages_config, + isolate, is_main_isolate, script_uri, packages_config, isolate_run_app_snapshot, flags, error, exit_code); } int64_t end = Dart_TimelineGetMicros(); - Dart_TimelineEvent("CreateIsolateAndSetupHelper", start, end, + Dart_TimelineEvent("CreateIsolateGroupAndSetupHelper", start, end, Dart_Timeline_Event_Duration, 0, NULL, NULL); return created_isolate; } #undef CHECK_RESULT -static Dart_Isolate CreateIsolateAndSetup(const char* script_uri, - const char* main, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - void* callback_data, - char** error) { +static Dart_Isolate CreateIsolateGroupAndSetup(const char* script_uri, + const char* main, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + void* callback_data, + char** error) { // The VM should never call the isolate helper with a NULL flags. ASSERT(flags != NULL); ASSERT(flags->version == DART_FLAGS_CURRENT_VERSION); @@ -679,28 +756,23 @@ static Dart_Isolate CreateIsolateAndSetup(const char* script_uri, script_uri, package_root, package_config, flags, error, &exit_code); } bool is_main_isolate = false; - return CreateIsolateAndSetupHelper(is_main_isolate, script_uri, main, - package_root, package_config, flags, - callback_data, error, &exit_code); + return CreateIsolateGroupAndSetupHelper(is_main_isolate, script_uri, main, + package_root, package_config, flags, + callback_data, error, &exit_code); } -static void OnIsolateShutdown(void* callback_data) { +static void OnIsolateShutdown(void* isolate_group_data, void* isolate_data) { Dart_EnterScope(); - Dart_Handle sticky_error = Dart_GetStickyError(); if (!Dart_IsNull(sticky_error) && !Dart_IsFatalError(sticky_error)) { Syslog::PrintErr("%s\n", Dart_GetError(sticky_error)); } - - IsolateData* isolate_data = reinterpret_cast(callback_data); - isolate_data->OnIsolateShutdown(); - Dart_ExitScope(); } -static void DeleteIsolateData(void* callback_data) { - IsolateData* isolate_data = reinterpret_cast(callback_data); - delete isolate_data; +static void DeleteIsolateGroupData(void* callback_data) { + auto isolate_group_data = reinterpret_cast(callback_data); + delete isolate_group_data; } static const char* kStdoutStreamId = "Stdout"; @@ -789,7 +861,7 @@ static void LoadBytecode() { } bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) { - // Call CreateIsolateAndSetup which creates an isolate and loads up + // Call CreateIsolateGroupAndSetup which creates an isolate and loads up // the specified application script. char* error = NULL; bool is_main_isolate = true; @@ -797,7 +869,7 @@ bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) { Dart_IsolateFlags flags; Dart_IsolateFlagsInitialize(&flags); - Dart_Isolate isolate = CreateIsolateAndSetupHelper( + Dart_Isolate isolate = CreateIsolateGroupAndSetupHelper( is_main_isolate, script_name, "main", Options::package_root(), Options::packages_file(), &flags, NULL /* callback_data */, &error, &exit_code); @@ -825,8 +897,8 @@ bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) { Dart_EnterScope(); - IsolateData* isolate_data = - reinterpret_cast(Dart_IsolateData(isolate)); + auto isolate_group_data = + reinterpret_cast(Dart_IsolateGroupData(isolate)); if (Options::gen_snapshot_kind() == kKernel) { if (vm_run_app_snapshot) { Syslog::PrintErr( @@ -836,7 +908,7 @@ bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) { Platform::Exit(kErrorExitCode); } Snapshot::GenerateKernel(Options::snapshot_filename(), script_name, - isolate_data->resolved_packages_config()); + isolate_group_data->resolved_packages_config()); } else { // Lookup the library of the root script. Dart_Handle root_lib = Dart_RootLibrary(); @@ -1109,9 +1181,11 @@ void main(int argc, char** argv) { init_params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; init_params.vm_snapshot_data = vm_snapshot_data; init_params.vm_snapshot_instructions = vm_snapshot_instructions; - init_params.create = CreateIsolateAndSetup; - init_params.shutdown = OnIsolateShutdown; - init_params.cleanup = DeleteIsolateData; + init_params.create_group = CreateIsolateGroupAndSetup; + init_params.initialize_isolate = OnIsolateInitialize; + init_params.shutdown_isolate = OnIsolateShutdown; + init_params.cleanup_isolate = nullptr; + init_params.cleanup_group = DeleteIsolateGroupData; init_params.file_open = DartUtils::OpenFile; init_params.file_read = DartUtils::ReadFile; init_params.file_write = DartUtils::WriteFile; diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc index 019522b78acf..6f5a8773354b 100644 --- a/runtime/bin/run_vm_tests.cc +++ b/runtime/bin/run_vm_tests.cc @@ -127,7 +127,7 @@ static Dart_Isolate CreateIsolateAndSetup(const char* script_uri, return NULL; } Dart_Isolate isolate = NULL; - bin::IsolateData* isolate_data = NULL; + bin::IsolateGroupData* isolate_group_data = NULL; const uint8_t* kernel_service_buffer = NULL; intptr_t kernel_service_buffer_size = 0; @@ -146,12 +146,12 @@ static Dart_Isolate CreateIsolateAndSetup(const char* script_uri, app_snapshot->SetBuffers( &ignore_vm_snapshot_data, &ignore_vm_snapshot_instructions, &isolate_snapshot_data, &isolate_snapshot_instructions); - isolate_data = new bin::IsolateData(script_uri, package_root, - packages_config, app_snapshot); - isolate = - Dart_CreateIsolate(DART_KERNEL_ISOLATE_NAME, DART_KERNEL_ISOLATE_NAME, - isolate_snapshot_data, isolate_snapshot_instructions, - NULL, NULL, flags, isolate_data, error); + isolate_group_data = new bin::IsolateGroupData( + script_uri, package_root, packages_config, app_snapshot); + isolate = Dart_CreateIsolateGroup( + DART_KERNEL_ISOLATE_NAME, DART_KERNEL_ISOLATE_NAME, + isolate_snapshot_data, isolate_snapshot_instructions, NULL, NULL, flags, + isolate_group_data, /*isolate_data=*/nullptr, error); if (*error != NULL) { free(*error); *error = NULL; @@ -161,29 +161,29 @@ static Dart_Isolate CreateIsolateAndSetup(const char* script_uri, // This can cause the isolate to be killed early which will return `nullptr` // here. if (isolate == nullptr) { - delete isolate_data; + delete isolate_group_data; return NULL; } } if (isolate == NULL) { - delete isolate_data; - isolate_data = NULL; + delete isolate_group_data; + isolate_group_data = NULL; bin::dfe.Init(); bin::dfe.LoadKernelService(&kernel_service_buffer, &kernel_service_buffer_size); ASSERT(kernel_service_buffer != NULL); - isolate_data = - new bin::IsolateData(script_uri, package_root, packages_config, NULL); - isolate_data->SetKernelBufferUnowned( + isolate_group_data = new bin::IsolateGroupData(script_uri, package_root, + packages_config, NULL); + isolate_group_data->SetKernelBufferUnowned( const_cast(kernel_service_buffer), kernel_service_buffer_size); - isolate = Dart_CreateIsolateFromKernel( + isolate = Dart_CreateIsolateGroupFromKernel( script_uri, main, kernel_service_buffer, kernel_service_buffer_size, - flags, isolate_data, error); + flags, isolate_group_data, /*isolate_data=*/nullptr, error); } if (isolate == NULL) { - delete isolate_data; + delete isolate_group_data; return NULL; } @@ -213,9 +213,9 @@ static Dart_Isolate CreateIsolateAndSetup(const char* script_uri, return isolate; } -static void CleanupIsolate(void* callback_data) { - bin::IsolateData* isolate_data = - reinterpret_cast(callback_data); +static void CleanupIsolateGroup(void* callback_data) { + bin::IsolateGroupData* isolate_data = + reinterpret_cast(callback_data); delete isolate_data; } @@ -311,18 +311,22 @@ static int Main(int argc, const char** argv) { TesterState::vm_snapshot_data = dart::bin::vm_snapshot_data; TesterState::create_callback = CreateIsolateAndSetup; - TesterState::cleanup_callback = CleanupIsolate; + TesterState::group_cleanup_callback = CleanupIsolateGroup; TesterState::argv = dart_argv; TesterState::argc = dart_argc; error = Dart::Init( dart::bin::vm_snapshot_data, dart::bin::vm_snapshot_instructions, - CreateIsolateAndSetup /* create */, nullptr /* shutdown */, - CleanupIsolate /* cleanup */, nullptr /* thread_exit */, - dart::bin::DartUtils::OpenFile, dart::bin::DartUtils::ReadFile, - dart::bin::DartUtils::WriteFile, dart::bin::DartUtils::CloseFile, - nullptr /* entropy_source */, nullptr /* get_service_assets */, - start_kernel_isolate, nullptr /* observer */); + /*create_group=*/CreateIsolateAndSetup, + /*initialize_isolate=*/nullptr, + /*shutdown_isolate=*/nullptr, + /*cleanup_isolate=*/nullptr, + /*cleanup_group=*/CleanupIsolateGroup, + /*thread_exit=*/nullptr, dart::bin::DartUtils::OpenFile, + dart::bin::DartUtils::ReadFile, dart::bin::DartUtils::WriteFile, + dart::bin::DartUtils::CloseFile, nullptr /* entropy_source */, + nullptr /* get_service_assets */, start_kernel_isolate, + /*code_observer=*/nullptr); if (error != nullptr) { Syslog::PrintErr("Failed to initialize VM: %s\n", error); free(error); diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h index 16a5b8046053..e52f10ff074a 100644 --- a/runtime/include/dart_api.h +++ b/runtime/include/dart_api.h @@ -88,7 +88,7 @@ typedef unsigned __int64 uint64_t; * current isolate may be NULL, in which case no isolate is ready to * execute. Most of the Dart apis require there to be a current * isolate in order to function without error. The current isolate is - * set by any call to Dart_CreateIsolate or Dart_EnterIsolate. + * set by any call to Dart_CreateIsolateGroup or Dart_EnterIsolate. */ typedef struct _Dart_Isolate* Dart_Isolate; @@ -553,7 +553,7 @@ DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); * * This callback, provided by the embedder, is called when the VM * needs to create an isolate. The callback should create an isolate - * by calling Dart_CreateIsolate and load any scripts required for + * by calling Dart_CreateIsolateGroup and load any scripts required for * execution. * * This callback may be called on a different thread than the one @@ -562,7 +562,7 @@ DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); * When the function returns NULL, it is the responsibility of this * function to ensure that Dart_ShutdownIsolate has been called if * required (for example, if the isolate was created successfully by - * Dart_CreateIsolate() but the root library fails to load + * Dart_CreateIsolateGroup() but the root library fails to load * successfully, then the function should call Dart_ShutdownIsolate * before returning). * @@ -572,7 +572,7 @@ DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); * freed. * * \param script_uri The uri of the main source file or snapshot to load. - * Either the URI of the parent isolate set in Dart_CreateIsolate for + * Either the URI of the parent isolate set in Dart_CreateIsolateGroup for * Isolate.spawn, or the argument to Isolate.spawnUri canonicalized by the * library tag handler of the parent isolate. * The callback is responsible for loading the program by a call to @@ -594,20 +594,54 @@ DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags); * from the spawning isolate or passed as parameters when spawning the * isolate from Dart code. * \param callback_data The callback data which was passed to the - * parent isolate when it was created by calling Dart_CreateIsolate(). + * parent isolate when it was created by calling Dart_CreateIsolateGroup(). * \param error A structure into which the embedder can place a * C string containing an error message in the case of failures. * * \return The embedder returns NULL if the creation and * initialization was not successful and the isolate if successful. */ -typedef Dart_Isolate (*Dart_IsolateCreateCallback)(const char* script_uri, - const char* main, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - void* callback_data, - char** error); +typedef Dart_Isolate (*Dart_IsolateGroupCreateCallback)( + const char* script_uri, + const char* main, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + void* callback_data, + char** error); + +/** + * An isolate initialization callback function. + * + * This callback, provided by the embedder, is called when the VM has created an + * isolate within an existing isolate group (i.e. from the same source as an + * existing isolate). + * + * The callback should setup native resolvers and might want to set a custom + * message handler via [Dart_SetMessageNotifyCallback] and mark the isolate as + * runnable. + * + * This callback may be called on a different thread than the one + * running the parent isolate. + * + * When the function returns `false`, it is the responsibility of this + * function to ensure that `Dart_ShutdownIsolate` has been called. + * + * When the function returns `false`, the function should set *error to + * a malloc-allocated buffer containing a useful error message. The + * caller of this function (the VM) will make sure that the buffer is + * freed. + * + * \param child_isolate_data The callback data to associate with the new + * child isolate. + * \param error A structure into which the embedder can place a + * C string containing an error message in the case of failures. + * + * \return The embedder returns NULL if the creation and + * initialization was not successful and the isolate if successful. + */ +typedef bool (*Dart_InitializeIsolateCallback)(void** child_isolate_data, + char** error); /** * An isolate unhandled exception callback function. @@ -626,11 +660,13 @@ typedef void (*Dart_IsolateUnhandledExceptionCallback)(Dart_Handle error); * This function should be used to dispose of native resources that * are allocated to an isolate in order to avoid leaks. * - * \param callback_data The same callback data which was passed to the - * isolate when it was created. - * + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. + * \param isolate_data The same callback data which was passed to the isolate + * when it was created. */ -typedef void (*Dart_IsolateShutdownCallback)(void* callback_data); +typedef void (*Dart_IsolateShutdownCallback)(void* isolate_group_data, + void* isolate_data); /** * An isolate cleanup callback function. @@ -642,11 +678,28 @@ typedef void (*Dart_IsolateShutdownCallback)(void* callback_data); * This function should be used to dispose of native resources that * are allocated to an isolate in order to avoid leaks. * - * \param callback_data The same callback data which was passed to the - * isolate when it was created. + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. + * \param isolate_data The same callback data which was passed to the isolate + * when it was created. + */ +typedef void (*Dart_IsolateCleanupCallback)(void* isolate_group_data, + void* isolate_data); + +/** + * An isolate group cleanup callback function. + * + * This callback, provided by the embedder, is called after the vm + * shuts down an isolate group. + * + * This function should be used to dispose of native resources that + * are allocated to an isolate in order to avoid leaks. + * + * \param isolate_group_data The same callback data which was passed to the + * isolate group when it was created. * */ -typedef void (*Dart_IsolateCleanupCallback)(void* callback_data); +typedef void (*Dart_IsolateGroupCleanupCallback)(void* isolate_group_data); /** * A thread death callback function. @@ -751,12 +804,17 @@ typedef struct Dart_CodeObserver { * \param instructions_snapshot A buffer containing a snapshot of precompiled * instructions, or NULL if no snapshot is provided. If provided, the buffer * must remain valid until Dart_Cleanup returns. - * \param create A function to be called during isolate creation. - * See Dart_IsolateCreateCallback. - * \param shutdown A function to be called when an isolate is shutdown. + * \param initialize_isolate A function to be called during isolate + * initialization inside an existing isolate group. + * See Dart_InitializeIsolateCallback. + * \param create_group A function to be called during isolate group creation. + * See Dart_IsolateGroupCreateCallback. + * \param shutdown A function to be called right before an isolate is shutdown. * See Dart_IsolateShutdownCallback. - * \param cleanup A function to be called after an isolate is shutdown. + * \param cleanup A function to be called after an isolate was shutdown. * See Dart_IsolateCleanupCallback. + * \param cleanup_group A function to be called after an isolate group is shutdown. + * See Dart_IsolateGroupCleanupCallback. * \param get_service_assets A function to be called by the service isolate when * it requires the vmservice assets archive. * See Dart_GetVMServiceAssetsArchive. @@ -767,9 +825,11 @@ typedef struct { int32_t version; const uint8_t* vm_snapshot_data; const uint8_t* vm_snapshot_instructions; - Dart_IsolateCreateCallback create; - Dart_IsolateShutdownCallback shutdown; - Dart_IsolateCleanupCallback cleanup; + Dart_IsolateGroupCreateCallback create_group; + Dart_InitializeIsolateCallback initialize_isolate; + Dart_IsolateShutdownCallback shutdown_isolate; + Dart_IsolateCleanupCallback cleanup_isolate; + Dart_IsolateGroupCleanupCallback cleanup_group; Dart_ThreadExitCallback thread_exit; Dart_FileOpenCallback file_open; Dart_FileReadCallback file_read; @@ -836,7 +896,7 @@ DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name); * Requires there to be no current isolate. * * \param script_uri The main source file or snapshot this isolate will load. - * The VM will provide this URI to the Dart_IsolateCreateCallback when a child + * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a child * isolate is created by Isolate.spawn. The embedder should use a URI that * allows it to load the same program into such a child isolate. * \param name A short name for the isolate to improve debugging messages. @@ -847,7 +907,7 @@ DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name); * remain valid until the isolate shuts down. * \param flags Pointer to VM specific flags or NULL for default flags. * \param callback_data Embedder data. This data will be passed to - * the Dart_IsolateCreateCallback when new isolates are spawned from + * the Dart_IsolateGroupCreateCallback when new isolates are spawned from * this parent isolate. * \param error Returns NULL if creation is successful, an error message * otherwise. The caller is responsible for calling free() on the error @@ -856,15 +916,16 @@ DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name); * \return The new isolate on success, or NULL if isolate creation failed. */ DART_EXPORT Dart_Isolate -Dart_CreateIsolate(const char* script_uri, - const char* name, - const uint8_t* isolate_snapshot_data, - const uint8_t* isolate_snapshot_instructions, - const uint8_t* shared_data, - const uint8_t* shared_instructions, - Dart_IsolateFlags* flags, - void* callback_data, - char** error); +Dart_CreateIsolateGroup(const char* script_uri, + const char* name, + const uint8_t* isolate_snapshot_data, + const uint8_t* isolate_snapshot_instructions, + const uint8_t* shared_data, + const uint8_t* shared_instructions, + Dart_IsolateFlags* flags, + void* isolate_group_data, + void* isolate_data, + char** error); /* TODO(turnidge): Document behavior when there is already a current * isolate. */ @@ -875,7 +936,7 @@ Dart_CreateIsolate(const char* script_uri, * Requires there to be no current isolate. * * \param script_uri The main source file or snapshot this isolate will load. - * The VM will provide this URI to the Dart_IsolateCreateCallback when a child + * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a child * isolate is created by Isolate.spawn. The embedder should use a URI that * allows it to load the same program into such a child isolate. * \param name A short name for the isolate to improve debugging messages. @@ -885,7 +946,7 @@ Dart_CreateIsolate(const char* script_uri, * remain valid until isolate shutdown. * \param flags Pointer to VM specific flags or NULL for default flags. * \param callback_data Embedder data. This data will be passed to - * the Dart_IsolateCreateCallback when new isolates are spawned from + * the Dart_IsolateGroupCreateCallback when new isolates are spawned from * this parent isolate. * \param error Returns NULL if creation is successful, an error message * otherwise. The caller is responsible for calling free() on the error @@ -894,13 +955,14 @@ Dart_CreateIsolate(const char* script_uri, * \return The new isolate on success, or NULL if isolate creation failed. */ DART_EXPORT Dart_Isolate -Dart_CreateIsolateFromKernel(const char* script_uri, - const char* name, - const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size, - Dart_IsolateFlags* flags, - void* callback_data, - char** error); +Dart_CreateIsolateGroupFromKernel(const char* script_uri, + const char* name, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size, + Dart_IsolateFlags* flags, + void* isolate_group_data, + void* isolate_data, + char** error); /** * Shuts down the current isolate. After this call, the current isolate is NULL. * Any current scopes created by Dart_EnterScope will be exited. Invokes the @@ -918,19 +980,31 @@ DART_EXPORT void Dart_ShutdownIsolate(); DART_EXPORT Dart_Isolate Dart_CurrentIsolate(); /** - * Returns the callback data associated with the current Isolate. This data was - * passed to the isolate when it was created. + * Returns the callback data associated with the current isolate. This + * data was set when the isolate got created or initialized. */ DART_EXPORT void* Dart_CurrentIsolateData(); /** - * Returns the callback data associated with the specified Isolate. This data - * was passed to the isolate when it was created. - * The embedder is responsible for ensuring the consistency of this data - * with respect to the lifecycle of an Isolate. + * Returns the callback data associated with the given isolate. This + * data was set when the isolate got created or initialized. */ DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate); +/** + * Returns the callback data associated with the current isolate group. This + * data was passed to the isolate group when it was created. + */ +DART_EXPORT void* Dart_CurrentIsolateGroupData(); + +/** + * Returns the callback data associated with the specified isolate group. This + * data was passed to the isolate when it was created. + * The embedder is responsible for ensuring the consistency of this data + * with respect to the lifecycle of an isolate group. + */ +DART_EXPORT void* Dart_IsolateGroupData(Dart_Isolate isolate); + /** * Returns the debugging name for the current isolate. * @@ -2526,9 +2600,9 @@ DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj, typedef struct _Dart_NativeArguments* Dart_NativeArguments; /** - * Extracts current isolate data from the native arguments structure. + * Extracts current isolate group data from the native arguments structure. */ -DART_EXPORT void* Dart_GetNativeIsolateData(Dart_NativeArguments args); +DART_EXPORT void* Dart_GetNativeIsolateGroupData(Dart_NativeArguments args); typedef enum { Dart_NativeArgument_kBool = 0, @@ -2930,7 +3004,7 @@ DART_EXPORT Dart_Handle Dart_DefaultCanonicalizeUrl(Dart_Handle base_url, * Requires there to be no current root library. * * \param buffer A buffer which contains a kernel binary (see - * pkg/kernel/binary.md). Must remain valid until isolate shutdown. + * pkg/kernel/binary.md). Must remain valid until isolate group shutdown. * \param buffer_size Length of the passed in buffer. * * \return A handle to the root library, or an error. @@ -3300,7 +3374,7 @@ typedef void (*Dart_StreamingWriteCallback)(void* callback_data, * Running this snapshot requires a VM compiled with DART_PRECOMPILED_SNAPSHOT. * The kDartVmSnapshotData and kDartVmSnapshotInstructions should be passed to * Dart_Initialize. The kDartIsolateSnapshotData and - * kDartIsolateSnapshotInstructions should be passed to Dart_CreateIsolate. + * kDartIsolateSnapshotInstructions should be passed to Dart_CreateIsolateGroup. * * The callback will be invoked one or more times to provide the assembly code. * @@ -3376,7 +3450,7 @@ DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_SortClasses(); * startup and quicker warmup in a subsequent process. * * Outputs a snapshot in two pieces. The pieces should be passed to - * Dart_CreateIsolate in a VM using the same VM snapshot pieces used in the + * Dart_CreateIsolateGroup in a VM using the same VM snapshot pieces used in the * current VM. The instructions piece must be loaded with read and execute * permissions; the data piece may be loaded as read-only. * diff --git a/runtime/include/dart_embedder_api.h b/runtime/include/dart_embedder_api.h index 9a91a8321242..61b54fd52a65 100644 --- a/runtime/include/dart_embedder_api.h +++ b/runtime/include/dart_embedder_api.h @@ -5,8 +5,8 @@ #ifndef RUNTIME_INCLUDE_DART_EMBEDDER_API_H_ #define RUNTIME_INCLUDE_DART_EMBEDDER_API_H_ -#include "dart_api.h" -#include "dart_tools_api.h" +#include "include/dart_api.h" +#include "include/dart_tools_api.h" namespace dart { namespace embedder { @@ -29,8 +29,11 @@ struct IsolateCreationData { // Isolate creation flags. Might be absent. Dart_IsolateFlags* flags; + // Isolate group callback data. + void* isolate_group_data; + // Isolate callback data. - void* callback_data; + void* isolate_data; }; // Create and initialize kernel-service isolate. This method should be used diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc index 436e895382e8..633129582797 100644 --- a/runtime/lib/isolate.cc +++ b/runtime/lib/isolate.cc @@ -129,28 +129,66 @@ class SpawnIsolateTask : public ThreadPool::Task { } void Run() override { - // Create a new isolate. - char* error = NULL; - Dart_IsolateCreateCallback callback = Isolate::CreateCallback(); - if (callback == NULL) { - ReportError( - "Isolate spawn is not supported by this Dart implementation\n"); + IsolateGroupSource* source = state_->source(); + + // The create isolate group call back is mandatory. If not provided we + // cannot spawn isolates. + Dart_IsolateGroupCreateCallback create_group_callback = + Isolate::CreateGroupCallback(); + if (create_group_callback == nullptr) { + FailedSpawn("Isolate spawn is not supported by this Dart embedder\n"); return; } - // Make a copy of the state's isolate flags and hand it to the callback. - Dart_IsolateFlags api_flags = *(state_->isolate_flags()); + // The initialize callback is optional atm, we fall back to creating isolate + // groups if it was not provided. + Dart_InitializeIsolateCallback initialize_callback = + Isolate::InitializeCallback(); + const char* name = (state_->debug_name() == NULL) ? state_->function_name() : state_->debug_name(); ASSERT(name != NULL); - Isolate* isolate = reinterpret_cast((callback)( - state_->script_url(), name, nullptr, state_->package_config(), - &api_flags, parent_isolate_->init_callback_data(), &error)); - parent_isolate_->DecrementSpawnCount(); - parent_isolate_ = nullptr; - if (isolate == NULL) { - ReportError(error); + // Create a new isolate. + char* error = nullptr; + Isolate* isolate = nullptr; + if (source == nullptr || initialize_callback == nullptr) { + // Make a copy of the state's isolate flags and hand it to the callback. + Dart_IsolateFlags api_flags = *(state_->isolate_flags()); + isolate = reinterpret_cast((create_group_callback)( + state_->script_url(), name, nullptr, state_->package_config(), + &api_flags, parent_isolate_->init_callback_data(), &error)); + parent_isolate_->DecrementSpawnCount(); + parent_isolate_ = nullptr; + } else { + if (initialize_callback == nullptr) { + FailedSpawn("Isolate spawn is not supported by this embedder."); + return; + } + + isolate = CreateIsolateFromExistingSource(source, name, &error); + parent_isolate_->DecrementSpawnCount(); + parent_isolate_ = nullptr; + if (isolate == nullptr) { + FailedSpawn(error); + free(error); + return; + } + + void* child_isolate_data = nullptr; + bool success = initialize_callback(&child_isolate_data, &error); + isolate->set_init_callback_data(child_isolate_data); + if (!success) { + Dart_ShutdownIsolate(); + FailedSpawn(error); + free(error); + return; + } + Dart_ExitIsolate(); + } + + if (isolate == nullptr) { + FailedSpawn(error); free(error); return; } @@ -169,6 +207,13 @@ class SpawnIsolateTask : public ThreadPool::Task { } private: + void FailedSpawn(const char* error) { + ReportError(error != nullptr + ? error + : "Unknown error occured during Isolate spawning."); + state_ = nullptr; + } + void ReportError(const char* error) { Dart_CObject error_cobj; error_cobj.type = Dart_CObject_kString; @@ -240,7 +285,7 @@ DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 0, 11) { std::unique_ptr state(new IsolateSpawnState( port.Id(), isolate->origin_id(), String2UTF8(script_uri), func, &message_buffer, utf8_package_config, paused.value(), fatal_errors, - on_exit_port, on_error_port, utf8_debug_name)); + on_exit_port, on_error_port, utf8_debug_name, isolate->source())); // Since this is a call to Isolate.spawn, copy the parent isolate's code. state->isolate_flags()->copy_parent_code = true; @@ -351,10 +396,12 @@ DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 0, 13) { const char* utf8_debug_name = debugName.IsNull() ? NULL : String2UTF8(debugName); + IsolateGroupSource* null_source = nullptr; + std::unique_ptr state(new IsolateSpawnState( port.Id(), canonical_uri, utf8_package_config, &arguments_buffer, &message_buffer, paused.value(), fatal_errors, on_exit_port, - on_error_port, utf8_debug_name)); + on_error_port, utf8_debug_name, null_source)); // If we were passed a value then override the default flags state for // checked mode. diff --git a/runtime/observatory/tests/service/get_source_report_test.dart b/runtime/observatory/tests/service/get_source_report_test.dart index f859e6d22842..7627ef38bcd0 100644 --- a/runtime/observatory/tests/service/get_source_report_test.dart +++ b/runtime/observatory/tests/service/get_source_report_test.dart @@ -91,7 +91,7 @@ var tests = [ final numRanges = coverage['ranges'].length; expect(coverage['type'], equals('SourceReport')); - expect((numRanges == 12), isTrue); + expect(numRanges, equals(12)); expect(coverage['ranges'][0], equals(expectedRange)); expect(coverage['scripts'].length, 1); expect( diff --git a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart index cdd9344f7a30..53fd8cda3ed9 100644 --- a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart +++ b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart @@ -89,7 +89,7 @@ void allEventsHaveIsolateNumber(List events) { } if (event['cat'] == 'Embedder' && (event['name'] == 'DFE::ReadScript' || - event['name'] == 'CreateIsolateAndSetupHelper')) { + event['name'] == 'CreateIsolateGroupAndSetupHelper')) { continue; } Map arguments = event['args']; diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc index e43381db58cf..875346679c17 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -130,9 +130,11 @@ static void CheckOffsets() { char* Dart::Init(const uint8_t* vm_isolate_snapshot, const uint8_t* instructions_snapshot, - Dart_IsolateCreateCallback create, + Dart_IsolateGroupCreateCallback create_group, + Dart_InitializeIsolateCallback initialize_isolate, Dart_IsolateShutdownCallback shutdown, - Dart_IsolateCleanupCallback cleanup, + Dart_IsolateShutdownCallback cleanup, + Dart_IsolateGroupCleanupCallback cleanup_group, Dart_ThreadExitCallback thread_exit, Dart_FileOpenCallback file_open, Dart_FileReadCallback file_read, @@ -355,9 +357,11 @@ char* Dart::Init(const uint8_t* vm_isolate_snapshot, Api::InitHandles(); Thread::ExitIsolate(); // Unregister the VM isolate from this thread. - Isolate::SetCreateCallback(create); + Isolate::SetCreateGroupCallback(create_group); + Isolate::SetInitializeCallback_(initialize_isolate); Isolate::SetShutdownCallback(shutdown); Isolate::SetCleanupCallback(cleanup); + Isolate::SetGroupCleanupCallback(cleanup_group); if (FLAG_support_service) { Service::SetGetServiceAssetsCallback(get_service_assets); @@ -620,7 +624,7 @@ RawError* Dart::InitializeIsolate(const uint8_t* snapshot_data, const uint8_t* shared_instructions, const uint8_t* kernel_buffer, intptr_t kernel_buffer_size, - void* data) { + void* isolate_data) { // Initialize the new isolate. Thread* T = Thread::Current(); Isolate* I = T->isolate(); @@ -724,7 +728,7 @@ RawError* Dart::InitializeIsolate(const uint8_t* snapshot_data, } I->heap()->InitGrowthControl(); - I->set_init_callback_data(data); + I->set_init_callback_data(isolate_data); Api::SetupAcquiredError(I); if (FLAG_print_class_table) { I->class_table()->Print(); @@ -850,11 +854,12 @@ void Dart::RunShutdownCallback() { Thread* thread = Thread::Current(); ASSERT(thread->execution_state() == Thread::kThreadInVM); Isolate* isolate = thread->isolate(); - void* callback_data = isolate->init_callback_data(); + void* isolate_group_data = isolate->source()->callback_data; + void* isolate_data = isolate->init_callback_data(); Dart_IsolateShutdownCallback callback = Isolate::ShutdownCallback(); if (callback != NULL) { TransitionVMToNative transition(thread); - (callback)(callback_data); + (callback)(isolate_group_data, isolate_data); } } diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h index 64d10f9e0f1d..6e4cf64a221b 100644 --- a/runtime/vm/dart.h +++ b/runtime/vm/dart.h @@ -28,9 +28,11 @@ class Dart : public AllStatic { // (caller owns error message and has to free it). static char* Init(const uint8_t* vm_snapshot_data, const uint8_t* vm_snapshot_instructions, - Dart_IsolateCreateCallback create, + Dart_IsolateGroupCreateCallback create_group, + Dart_InitializeIsolateCallback initialize_isolate, Dart_IsolateShutdownCallback shutdown, Dart_IsolateCleanupCallback cleanup, + Dart_IsolateGroupCleanupCallback cleanup_group, Dart_ThreadExitCallback thread_exit, Dart_FileOpenCallback file_open, Dart_FileReadCallback file_read, diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index caa2de96fae0..f3a99949f585 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -1005,11 +1005,13 @@ DART_EXPORT char* Dart_Initialize(Dart_InitializeParams* params) { } return Dart::Init(params->vm_snapshot_data, params->vm_snapshot_instructions, - params->create, params->shutdown, params->cleanup, - params->thread_exit, params->file_open, params->file_read, - params->file_write, params->file_close, - params->entropy_source, params->get_service_assets, - params->start_kernel_isolate, params->code_observer); + params->create_group, params->initialize_isolate, + params->shutdown_isolate, params->cleanup_isolate, + params->cleanup_group, params->thread_exit, + params->file_open, params->file_read, params->file_write, + params->file_close, params->entropy_source, + params->get_service_assets, params->start_kernel_isolate, + params->code_observer); } DART_EXPORT char* Dart_Cleanup() { @@ -1058,26 +1060,13 @@ ISOLATE_METRIC_LIST(ISOLATE_METRIC_API); // --- Isolates --- -static Dart_Isolate CreateIsolate(const char* script_uri, +static Dart_Isolate CreateIsolate(IsolateGroupSource* source, const char* name, - const uint8_t* snapshot_data, - const uint8_t* snapshot_instructions, - const uint8_t* shared_data, - const uint8_t* shared_instructions, - const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size, - Dart_IsolateFlags* flags, - void* callback_data, + void* isolate_data, char** error) { CHECK_NO_ISOLATE(Isolate::Current()); - // Setup default flags in case none were passed. - Dart_IsolateFlags api_flags; - if (flags == NULL) { - Isolate::FlagsInitialize(&api_flags); - flags = &api_flags; - } - Isolate* I = Dart::CreateIsolate((name == NULL) ? "isolate" : name, *flags); + Isolate* I = Dart::CreateIsolate(name, source->flags); if (I == NULL) { if (error != NULL) { *error = strdup("Isolate creation failed"); @@ -1094,14 +1083,15 @@ static Dart_Isolate CreateIsolate(const char* script_uri, // bootstrap library files which call out to a tag handler that may create // Api Handles when an error is encountered. T->EnterApiScope(); - const Error& error_obj = Error::Handle( - Z, - Dart::InitializeIsolate(snapshot_data, snapshot_instructions, - shared_data, shared_instructions, kernel_buffer, - kernel_buffer_size, callback_data)); + const Error& error_obj = + Error::Handle(Z, Dart::InitializeIsolate( + source->snapshot_data, + source->snapshot_instructions, source->shared_data, + source->shared_instructions, source->kernel_buffer, + source->kernel_buffer_size, isolate_data)); if (error_obj.IsNull()) { #if defined(DART_NO_SNAPSHOT) && !defined(PRODUCT) - if (FLAG_check_function_fingerprints && kernel_buffer == NULL) { + if (FLAG_check_function_fingerprints && source->kernel_buffer == NULL) { Library::CheckFunctionFingerprints(); } #endif // defined(DART_NO_SNAPSHOT) && !defined(PRODUCT). @@ -1113,6 +1103,8 @@ static Dart_Isolate CreateIsolate(const char* script_uri, T->ExitApiScope(); } + I->set_source(source); + if (success) { // A Thread structure has been associated to the thread, we do the // safepoint transition explicitly here instead of using the @@ -1130,37 +1122,125 @@ static Dart_Isolate CreateIsolate(const char* script_uri, return reinterpret_cast(NULL); } +Isolate* CreateIsolateFromExistingSource(IsolateGroupSource* source, + const char* name, + char** error) { + API_TIMELINE_DURATION(Thread::Current()); + CHECK_NO_ISOLATE(Isolate::Current()); + + Isolate* isolate = reinterpret_cast( + CreateIsolate(source, name, /*isolate_data=*/nullptr, error)); + RELEASE_ASSERT(isolate->source() == source); + + if (source->script_kernel_buffer != nullptr) { +#if defined(DART_PRECOMPILED_RUNTIME) + UNREACHABLE(); +#else + Dart_EnterScope(); + { + Thread* T = Thread::Current(); + TransitionNativeToVM transition(T); + HANDLESCOPE(T); + StackZone zone(T); + + // The kernel loader is about to allocate a bunch of new libraries, + // classes and functions into old space. Force growth, and use of the + // bump allocator instead of freelists. + BumpAllocateScope bump_allocate_scope(T); + + // NOTE: We do not attach a finalizer for this object, because the + // embedder will free it once the isolate group has shutdown. + const auto& td = ExternalTypedData::Handle(ExternalTypedData::New( + kExternalTypedDataUint8ArrayCid, + const_cast(source->script_kernel_buffer), + source->script_kernel_size, Heap::kOld)); + + std::unique_ptr program = + kernel::Program::ReadFromTypedData(td, + const_cast(error)); + if (program == nullptr) { + UNIMPLEMENTED(); + } + const Object& tmp = + kernel::KernelLoader::LoadEntireProgram(program.get()); + + // If the existing isolate could spawn with a root library we should be + // able to do the same + RELEASE_ASSERT(!tmp.IsNull() && tmp.IsLibrary()); + isolate->object_store()->set_root_library(Library::Cast(tmp)); + } + Dart_ExitScope(); +#endif // defined(DART_PRECOMPILED_RUNTIME) + } + + return isolate; +} + DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags) { Isolate::FlagsInitialize(flags); } DART_EXPORT Dart_Isolate -Dart_CreateIsolate(const char* script_uri, - const char* name, - const uint8_t* snapshot_data, - const uint8_t* snapshot_instructions, - const uint8_t* shared_data, - const uint8_t* shared_instructions, - Dart_IsolateFlags* flags, - void* callback_data, - char** error) { +Dart_CreateIsolateGroup(const char* script_uri, + const char* name, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions, + const uint8_t* shared_data, + const uint8_t* shared_instructions, + Dart_IsolateFlags* flags, + void* isolate_group_data, + void* isolate_data, + char** error) { API_TIMELINE_DURATION(Thread::Current()); - return CreateIsolate(script_uri, name, snapshot_data, snapshot_instructions, - shared_data, shared_instructions, NULL, 0, flags, - callback_data, error); + + Dart_IsolateFlags api_flags; + if (flags == nullptr) { + Isolate::FlagsInitialize(&api_flags); + flags = &api_flags; + } + + const char* non_null_name = name == nullptr ? "isolate" : name; + auto source = new IsolateGroupSource(script_uri, non_null_name, snapshot_data, + snapshot_instructions, shared_data, + shared_instructions, nullptr, -1, *flags, + isolate_group_data); + source->IncrementIsolateUsageCount(); + Dart_Isolate isolate = + CreateIsolate(source, non_null_name, isolate_data, error); + if (source->DecrementIsolateUsageCount()) { + delete source; + } + return isolate; } DART_EXPORT Dart_Isolate -Dart_CreateIsolateFromKernel(const char* script_uri, - const char* name, - const uint8_t* kernel_buffer, - intptr_t kernel_buffer_size, - Dart_IsolateFlags* flags, - void* callback_data, - char** error) { +Dart_CreateIsolateGroupFromKernel(const char* script_uri, + const char* name, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size, + Dart_IsolateFlags* flags, + void* isolate_group_data, + void* isolate_data, + char** error) { API_TIMELINE_DURATION(Thread::Current()); - return CreateIsolate(script_uri, name, NULL, NULL, NULL, NULL, kernel_buffer, - kernel_buffer_size, flags, callback_data, error); + + Dart_IsolateFlags api_flags; + if (flags == nullptr) { + Isolate::FlagsInitialize(&api_flags); + flags = &api_flags; + } + + const char* non_null_name = name == nullptr ? "isolate" : name; + auto source = new IsolateGroupSource( + script_uri, non_null_name, nullptr, nullptr, nullptr, nullptr, + kernel_buffer, kernel_buffer_size, *flags, isolate_group_data); + source->IncrementIsolateUsageCount(); + Dart_Isolate isolate = + CreateIsolate(source, non_null_name, isolate_data, error); + if (source->DecrementIsolateUsageCount()) { + delete source; + } + return isolate; } DART_EXPORT void Dart_ShutdownIsolate() { @@ -1171,7 +1251,7 @@ DART_EXPORT void Dart_ShutdownIsolate() { // The Thread structure is disassociated from the isolate, we do the // safepoint transition explicitly here instead of using the TransitionXXX // scope objects as the original transition happened outside this scope in - // Dart_EnterIsolate/Dart_CreateIsolate. + // Dart_EnterIsolate/Dart_CreateIsolateGroup. ASSERT(T->execution_state() == Thread::kThreadInNative); T->ExitSafepoint(); T->set_execution_state(Thread::kThreadInVM); @@ -1210,9 +1290,23 @@ DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate) { if (isolate == NULL) { FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC); } - // TODO(16615): Validate isolate parameter. - Isolate* iso = reinterpret_cast(isolate); - return iso->init_callback_data(); + // TODO(http://dartbug.com/16615): Validate isolate parameter. + return reinterpret_cast(isolate)->init_callback_data(); +} + +DART_EXPORT void* Dart_CurrentIsolateGroupData() { + Isolate* isolate = Isolate::Current(); + CHECK_ISOLATE(isolate); + NoSafepointScope no_safepoint_scope; + return isolate->source()->callback_data; +} + +DART_EXPORT void* Dart_IsolateGroupData(Dart_Isolate isolate) { + if (isolate == NULL) { + FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC); + } + // TODO(http://dartbug.com/16615): Validate isolate parameter. + return reinterpret_cast(isolate)->source()->callback_data; } DART_EXPORT Dart_Handle Dart_DebugName() { @@ -1227,6 +1321,7 @@ DART_EXPORT const char* Dart_IsolateServiceId(Dart_Isolate isolate) { if (isolate == NULL) { FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC); } + // TODO(http://dartbug.com/16615): Validate isolate parameter. Isolate* I = reinterpret_cast(isolate); int64_t main_port = static_cast(I->main_port()); return OS::SCreate(NULL, "isolates/%" Pd64, main_port); @@ -1234,7 +1329,7 @@ DART_EXPORT const char* Dart_IsolateServiceId(Dart_Isolate isolate) { DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate) { CHECK_NO_ISOLATE(Isolate::Current()); - // TODO(16615): Validate isolate parameter. + // TODO(http://dartbug.com/16615): Validate isolate parameter. Isolate* iso = reinterpret_cast(isolate); if (!Thread::EnterIsolate(iso)) { FATAL( @@ -1494,7 +1589,7 @@ DART_EXPORT void Dart_ExitIsolate() { // The Thread structure is disassociated from the isolate, we do the // safepoint transition explicitly here instead of using the TransitionXXX // scope objects as the original transition happened outside this scope in - // Dart_EnterIsolate/Dart_CreateIsolate. + // Dart_EnterIsolate/Dart_CreateIsolateGroup. ASSERT(T->execution_state() == Thread::kThreadInNative); T->ExitSafepoint(); T->set_execution_state(Thread::kThreadInVM); @@ -4559,7 +4654,7 @@ DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj, return Api::Success(); } -DART_EXPORT void* Dart_GetNativeIsolateData(Dart_NativeArguments args) { +DART_EXPORT void* Dart_GetNativeIsolateGroupData(Dart_NativeArguments args) { NativeArguments* arguments = reinterpret_cast(args); Isolate* isolate = arguments->thread()->isolate(); ASSERT(isolate == Isolate::Current()); @@ -5041,9 +5136,15 @@ DART_EXPORT Dart_Handle Dart_LoadScriptFromKernel(const uint8_t* buffer, // instead of freelists. BumpAllocateScope bump_allocate_scope(T); + // NOTE: We do not attach a finalizer for this object, because the embedder + // will free it once the isolate group has shutdown. + const auto& td = ExternalTypedData::Handle(ExternalTypedData::New( + kExternalTypedDataUint8ArrayCid, const_cast(buffer), + buffer_size, Heap::kOld)); + const char* error = nullptr; std::unique_ptr program = - kernel::Program::ReadFromBuffer(buffer, buffer_size, &error); + kernel::Program::ReadFromTypedData(td, &error); if (program == nullptr) { return Api::NewError("Can't load Kernel binary: %s.", error); } @@ -5053,6 +5154,10 @@ DART_EXPORT Dart_Handle Dart_LoadScriptFromKernel(const uint8_t* buffer, if (tmp.IsError()) { return Api::NewHandle(T, tmp.raw()); } + + I->source()->script_kernel_size = buffer_size; + I->source()->script_kernel_buffer = buffer; + // TODO(32618): Setting root library based on whether it has 'main' or not // is not correct because main can be in the exported namespace of a library // or it could be a getter. @@ -5287,9 +5392,16 @@ DART_EXPORT Dart_Handle Dart_LoadLibraryFromKernel(const uint8_t* buffer, // instead of freelists. BumpAllocateScope bump_allocate_scope(T); + // NOTE: We do not attach a finalizer for this object, because the embedder + // will/should free it once the isolate group has shutdown. + // See also http://dartbug.com/37030. + const auto& td = ExternalTypedData::Handle(ExternalTypedData::New( + kExternalTypedDataUint8ArrayCid, const_cast(buffer), + buffer_size, Heap::kOld)); + const char* error = nullptr; std::unique_ptr program = - kernel::Program::ReadFromBuffer(buffer, buffer_size, &error); + kernel::Program::ReadFromTypedData(td, &error); if (program == nullptr) { return Api::NewError("Can't load Kernel binary: %s.", error); } diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h index 2d8ad351065b..d7634e3d76b0 100644 --- a/runtime/vm/dart_api_impl.h +++ b/runtime/vm/dart_api_impl.h @@ -5,6 +5,8 @@ #ifndef RUNTIME_VM_DART_API_IMPL_H_ #define RUNTIME_VM_DART_API_IMPL_H_ +#include + #include "vm/allocation.h" #include "vm/heap/safepoint.h" #include "vm/native_arguments.h" @@ -32,7 +34,7 @@ const char* CanonicalFunction(const char* func); if ((isolate) == NULL) { \ FATAL1( \ "%s expects there to be a current isolate. Did you " \ - "forget to call Dart_CreateIsolate or Dart_EnterIsolate?", \ + "forget to call Dart_CreateIsolateGroup or Dart_EnterIsolate?", \ CURRENT_FUNC); \ } \ } while (0) @@ -360,6 +362,14 @@ class Api : AllStatic { #define ASSERT_CALLBACK_STATE(thread) \ ASSERT(thread->no_callback_scope_depth() == 0) +class IsolateGroupSource; + +// Creates a new isolate from [source] (which should come from an existing +// isolate). +Isolate* CreateIsolateFromExistingSource(IsolateGroupSource* source, + const char* name, + char** error); + } // namespace dart. #endif // RUNTIME_VM_DART_API_IMPL_H_ diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc index d00f89b0ca17..7c3c611ee384 100644 --- a/runtime/vm/dart_api_impl_test.cc +++ b/runtime/vm/dart_api_impl_test.cc @@ -33,9 +33,9 @@ UNIT_TEST_CASE(DartAPI_DartInitializeAfterCleanup) { memset(¶ms, 0, sizeof(Dart_InitializeParams)); params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; params.vm_snapshot_data = TesterState::vm_snapshot_data; - params.create = TesterState::create_callback; - params.shutdown = TesterState::shutdown_callback; - params.cleanup = TesterState::cleanup_callback; + params.create_group = TesterState::create_callback; + params.shutdown_isolate = TesterState::shutdown_callback; + params.cleanup_group = TesterState::group_cleanup_callback; params.start_kernel_isolate = true; // Reinitialize and ensure we can execute Dart code. @@ -63,9 +63,9 @@ UNIT_TEST_CASE(DartAPI_DartInitializeCallsCodeObserver) { memset(¶ms, 0, sizeof(Dart_InitializeParams)); params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; params.vm_snapshot_data = TesterState::vm_snapshot_data; - params.create = TesterState::create_callback; - params.shutdown = TesterState::shutdown_callback; - params.cleanup = TesterState::cleanup_callback; + params.create_group = TesterState::create_callback; + params.shutdown_isolate = TesterState::shutdown_callback; + params.cleanup_group = TesterState::group_cleanup_callback; params.start_kernel_isolate = true; bool was_called = false; @@ -3665,20 +3665,21 @@ VM_UNIT_TEST_CASE(DartAPI_Isolates) { VM_UNIT_TEST_CASE(DartAPI_CurrentIsolateData) { Dart_IsolateShutdownCallback saved_shutdown = Isolate::ShutdownCallback(); - Dart_IsolateCleanupCallback saved_cleanup = Isolate::CleanupCallback(); + Dart_IsolateGroupCleanupCallback saved_cleanup = + Isolate::GroupCleanupCallback(); Isolate::SetShutdownCallback(NULL); - Isolate::SetCleanupCallback(NULL); + Isolate::SetGroupCleanupCallback(NULL); intptr_t mydata = 12345; Dart_Isolate isolate = TestCase::CreateTestIsolate(NULL, reinterpret_cast(mydata)); EXPECT(isolate != NULL); - EXPECT_EQ(mydata, reinterpret_cast(Dart_CurrentIsolateData())); - EXPECT_EQ(mydata, reinterpret_cast(Dart_IsolateData(isolate))); + EXPECT_EQ(mydata, reinterpret_cast(Dart_CurrentIsolateGroupData())); + EXPECT_EQ(mydata, reinterpret_cast(Dart_IsolateGroupData(isolate))); Dart_ShutdownIsolate(); Isolate::SetShutdownCallback(saved_shutdown); - Isolate::SetCleanupCallback(saved_cleanup); + Isolate::SetGroupCleanupCallback(saved_cleanup); } static Dart_Handle LoadScript(const char* url_str, const char* source) { @@ -6613,8 +6614,8 @@ static Dart_Isolate RunLoopTestCallback(const char* script_name, // Common code for RunLoop_Success/RunLoop_Failure. static void RunLoopTest(bool throw_exception) { - Dart_IsolateCreateCallback saved = Isolate::CreateCallback(); - Isolate::SetCreateCallback(RunLoopTestCallback); + Dart_IsolateGroupCreateCallback saved = Isolate::CreateGroupCallback(); + Isolate::SetCreateGroupCallback(RunLoopTestCallback); Dart_Isolate isolate = RunLoopTestCallback(NULL, NULL, NULL, NULL, NULL, NULL, NULL); @@ -6638,7 +6639,7 @@ static void RunLoopTest(bool throw_exception) { Dart_ExitScope(); Dart_ShutdownIsolate(); - Isolate::SetCreateCallback(saved); + Isolate::SetCreateGroupCallback(saved); } VM_UNIT_TEST_CASE(DartAPI_RunLoop_Success) { @@ -6649,45 +6650,93 @@ VM_UNIT_TEST_CASE(DartAPI_RunLoop_Exception) { RunLoopTest(true); } -static void* shutdown_callback_data; -static void IsolateShutdownTestCallback(void* callback_data) { - shutdown_callback_data = callback_data; +static void* shutdown_isolate_group_data; +static void* shutdown_isolate_data; +static void* cleanup_isolate_group_data; +static void* cleanup_isolate_data; + +// Called on isolate shutdown time (which is still allowed to run Dart code) +static void IsolateShutdownTestCallback(void* group_data, void* isolate_data) { + // Shutdown runs before cleanup. + EXPECT(cleanup_isolate_group_data == nullptr); + EXPECT(cleanup_isolate_data == nullptr); + + // Shutdown must have a current isolate (since it is allowed to execute Dart + // code) + EXPECT(Dart_CurrentIsolate() != nullptr); + EXPECT(Dart_CurrentIsolateGroupData() == group_data); + EXPECT(Dart_CurrentIsolateData() == isolate_data); + + shutdown_isolate_group_data = group_data; + shutdown_isolate_data = isolate_data; } -static void* cleanup_callback_data; -static void IsolateCleanupTestCallback(void* callback_data) { - cleanup_callback_data = callback_data; + +// Called on isolate cleanup time (which is after the isolate has been +// destroyed) +static void IsolateCleanupTestCallback(void* group_data, void* isolate_data) { + // Cleanup runs after shutdown. + EXPECT(shutdown_isolate_group_data != nullptr); + EXPECT(shutdown_isolate_data != nullptr); + + // The isolate was destroyed and there should not be a current isolate. + EXPECT(Dart_CurrentIsolate() == nullptr); + + cleanup_isolate_group_data = group_data; + cleanup_isolate_data = isolate_data; +} + +// Called on isolate group cleanup time (once all isolates have been destroyed) +static void* cleanup_group_callback_data; +static void IsolateGroupCleanupTestCallback(void* callback_data) { + cleanup_group_callback_data = callback_data; } VM_UNIT_TEST_CASE(DartAPI_IsolateShutdownAndCleanup) { Dart_IsolateShutdownCallback saved_shutdown = Isolate::ShutdownCallback(); - Dart_IsolateCleanupCallback saved_cleanup = Isolate::CleanupCallback(); + Dart_IsolateGroupCleanupCallback saved_cleanup = + Isolate::GroupCleanupCallback(); Isolate::SetShutdownCallback(IsolateShutdownTestCallback); Isolate::SetCleanupCallback(IsolateCleanupTestCallback); + Isolate::SetGroupCleanupCallback(IsolateGroupCleanupTestCallback); + + shutdown_isolate_group_data = nullptr; + shutdown_isolate_data = nullptr; + cleanup_group_callback_data = nullptr; + void* my_group_data = reinterpret_cast(123); + void* my_data = reinterpret_cast(456); - shutdown_callback_data = NULL; - cleanup_callback_data = NULL; - void* my_data = reinterpret_cast(12345); // Create an isolate. - Dart_Isolate isolate = TestCase::CreateTestIsolate(NULL, my_data); + Dart_Isolate isolate = + TestCase::CreateTestIsolate(nullptr, my_group_data, my_data); EXPECT(isolate != NULL); // The shutdown callback has not been called. - EXPECT_EQ(0, reinterpret_cast(shutdown_callback_data)); - EXPECT_EQ(0, reinterpret_cast(cleanup_callback_data)); + EXPECT(nullptr == shutdown_isolate_data); + EXPECT(nullptr == shutdown_isolate_group_data); + EXPECT(nullptr == cleanup_group_callback_data); + + // The isolate is the active isolate which allows us to access the isolate + // specific and isolate-group specific data. + EXPECT(Dart_CurrentIsolateData() == my_data); + EXPECT(Dart_CurrentIsolateGroupData() == my_group_data); // Shutdown the isolate. Dart_ShutdownIsolate(); - // The shutdown callback has been called. - EXPECT_EQ(12345, reinterpret_cast(shutdown_callback_data)); - EXPECT_EQ(12345, reinterpret_cast(cleanup_callback_data)); + // The shutdown & cleanup callbacks have been called. + EXPECT(my_data == shutdown_isolate_data); + EXPECT(my_group_data == shutdown_isolate_group_data); + EXPECT(my_data == cleanup_isolate_data); + EXPECT(my_group_data == cleanup_isolate_group_data); + EXPECT(my_group_data == cleanup_group_callback_data); Isolate::SetShutdownCallback(saved_shutdown); - Isolate::SetCleanupCallback(saved_cleanup); + Isolate::SetGroupCleanupCallback(saved_cleanup); } static int64_t add_result = 0; -static void IsolateShutdownRunDartCodeTestCallback(void* callback_data) { +static void IsolateShutdownRunDartCodeTestCallback(void* isolate_group_data, + void* isolate_data) { Dart_Isolate isolate = Dart_CurrentIsolate(); if (Dart_IsKernelIsolate(isolate) || Dart_IsServiceIsolate(isolate)) { return; diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc index 11e65e958077..b6d13522f554 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc @@ -1001,7 +1001,11 @@ Isolate::~Isolate() { } void Isolate::InitVM() { - create_callback_ = nullptr; + create_group_callback_ = nullptr; + initialize_callback_ = nullptr; + shutdown_callback_ = nullptr; + cleanup_callback_ = nullptr; + cleanup_group_callback_ = nullptr; if (isolates_list_monitor_ == nullptr) { isolates_list_monitor_ = new Monitor(); } @@ -1900,15 +1904,34 @@ void Isolate::Shutdown() { // as we are shutting down the isolate. Thread::ExitIsolate(); - Dart_IsolateCleanupCallback cleanup = Isolate::CleanupCallback(); - if (cleanup != nullptr) { - cleanup(init_callback_data()); + // The source is null iff the isolate is the "vm-isolate". + ASSERT((source_ == nullptr) == (Dart::vm_isolate() == this)); + + if (source_ != nullptr) { + // Run isolate specific cleanup function. + Dart_IsolateCleanupCallback cleanup = Isolate::CleanupCallback(); + if (cleanup != nullptr) { + cleanup(source_->callback_data, init_callback_data()); + } + + // Run isolate group specific cleanup function if the last isolate in an + // isolate group died. + if (source_->DecrementIsolateUsageCount()) { + auto group_cleanup_callback = Isolate::GroupCleanupCallback(); + if (group_cleanup_callback != nullptr) { + group_cleanup_callback(source_->callback_data); + } + delete source_; + source_ = nullptr; + } } } -Dart_IsolateCreateCallback Isolate::create_callback_ = nullptr; +Dart_InitializeIsolateCallback Isolate::initialize_callback_ = nullptr; +Dart_IsolateGroupCreateCallback Isolate::create_group_callback_ = nullptr; Dart_IsolateShutdownCallback Isolate::shutdown_callback_ = nullptr; Dart_IsolateCleanupCallback Isolate::cleanup_callback_ = nullptr; +Dart_IsolateGroupCleanupCallback Isolate::cleanup_group_callback_ = nullptr; Monitor* Isolate::isolates_list_monitor_ = nullptr; Isolate* Isolate::isolates_list_head_ = nullptr; @@ -2920,7 +2943,8 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port, bool errors_are_fatal, Dart_Port on_exit_port, Dart_Port on_error_port, - const char* debug_name) + const char* debug_name, + IsolateGroupSource* source) : isolate_(nullptr), parent_port_(parent_port), origin_id_(origin_id), @@ -2932,6 +2956,7 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port, class_name_(nullptr), function_name_(nullptr), debug_name_(debug_name), + source_(source), serialized_args_(nullptr), serialized_message_(message_buffer->StealMessage()), paused_(paused), @@ -2963,7 +2988,8 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port, bool errors_are_fatal, Dart_Port on_exit_port, Dart_Port on_error_port, - const char* debug_name) + const char* debug_name, + IsolateGroupSource* source) : isolate_(nullptr), parent_port_(parent_port), origin_id_(ILLEGAL_PORT), @@ -2975,6 +3001,7 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port, class_name_(nullptr), function_name_(nullptr), debug_name_(debug_name), + source_(source), serialized_args_(args_buffer->StealMessage()), serialized_message_(message_buffer->StealMessage()), isolate_flags_(), diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h index 6c6ee8ebe0ee..a4a4bb719613 100644 --- a/runtime/vm/isolate.h +++ b/runtime/vm/isolate.h @@ -155,6 +155,78 @@ typedef FixedCache CatchEntryMovesCache; unsafe_trust_strong_mode_types, \ FLAG_experimental_unsafe_mode_use_at_your_own_risk) +// Represents the information used for spawning the first isolate within an +// isolate group. +// +// Any subsequent isolates created via `Isolate.spawn()` will be created using +// the same [IsolateGroupSource] (the object itself is shared among all isolates +// within the same group). +// +// Issue(http://dartbug.com/36097): It is still possible to run into issues if +// an isolate has spawned another one and then loads more code into the first +// one, which the latter will not get. Though it makes the status quo better +// than what we had before (where the embedder needed to maintain the +// same-source guarantee). +// +// => This is only the first step towards having multiple isolates share the +// same heap (and therefore the same program structure). +// +class IsolateGroupSource { + public: + IsolateGroupSource(const char* script_uri, + const char* name, + const uint8_t* snapshot_data, + const uint8_t* snapshot_instructions, + const uint8_t* shared_data, + const uint8_t* shared_instructions, + const uint8_t* kernel_buffer, + intptr_t kernel_buffer_size, + Dart_IsolateFlags flags, + void* callback_data) + : script_uri(script_uri), + name(strdup(name)), + snapshot_data(snapshot_data), + snapshot_instructions(snapshot_instructions), + shared_data(shared_data), + shared_instructions(shared_instructions), + kernel_buffer(kernel_buffer), + kernel_buffer_size(kernel_buffer_size), + flags(flags), + callback_data(callback_data), + script_kernel_buffer(nullptr), + script_kernel_size(-1) {} + ~IsolateGroupSource() { free(name); } + + // The arguments used for spawning in + // `Dart_CreateIsolateGroupFromKernel` / `Dart_CreateIsolate`. + const char* script_uri; + char* name; + const uint8_t* snapshot_data; + const uint8_t* snapshot_instructions; + const uint8_t* shared_data; + const uint8_t* shared_instructions; + const uint8_t* kernel_buffer; + const intptr_t kernel_buffer_size; + Dart_IsolateFlags flags; + void* callback_data; + + // The kernel buffer used in `Dart_LoadScriptFromKernel`. + const uint8_t* script_kernel_buffer; + intptr_t script_kernel_size; + + void IncrementIsolateUsageCount() { + AtomicOperations::IncrementBy(&isolate_count_, 1); + } + + // Returns true if this was the last reference. + bool DecrementIsolateUsageCount() { + return AtomicOperations::FetchAndDecrement(&isolate_count_) == 1; + } + + private: + intptr_t isolate_count_ = 0; +}; + class Isolate : public BaseIsolate { public: // Keep both these enums in sync with isolate_patch.dart. @@ -239,6 +311,13 @@ class Isolate : public BaseIsolate { message_notify_callback_ = value; } + IsolateGroupSource* source() const { return source_; } + + void set_source(IsolateGroupSource* source) { + source->IncrementIsolateUsageCount(); + source_ = source; + } + bool HasPendingMessages(); Thread* mutator_thread() const; @@ -437,11 +516,18 @@ class Isolate : public BaseIsolate { void DecrementSpawnCount(); void WaitForOutstandingSpawns(); - static void SetCreateCallback(Dart_IsolateCreateCallback cb) { - create_callback_ = cb; + static void SetCreateGroupCallback(Dart_IsolateGroupCreateCallback cb) { + create_group_callback_ = cb; + } + static Dart_IsolateGroupCreateCallback CreateGroupCallback() { + return create_group_callback_; + } + + static void SetInitializeCallback_(Dart_InitializeIsolateCallback cb) { + initialize_callback_ = cb; } - static Dart_IsolateCreateCallback CreateCallback() { - return create_callback_; + static Dart_InitializeIsolateCallback InitializeCallback() { + return initialize_callback_; } static void SetShutdownCallback(Dart_IsolateShutdownCallback cb) { @@ -458,6 +544,13 @@ class Isolate : public BaseIsolate { return cleanup_callback_; } + static void SetGroupCleanupCallback(Dart_IsolateGroupCleanupCallback cb) { + cleanup_group_callback_ = cb; + } + static Dart_IsolateGroupCleanupCallback GroupCleanupCallback() { + return cleanup_group_callback_; + } + #if !defined(PRODUCT) void set_object_id_ring(ObjectIdRing* ring) { object_id_ring_ = ring; } ObjectIdRing* object_id_ring() { return object_id_ring_; } @@ -1056,9 +1149,11 @@ class Isolate : public BaseIsolate { ReversePcLookupCache* reverse_pc_lookup_cache_ = nullptr; - static Dart_IsolateCreateCallback create_callback_; + static Dart_IsolateGroupCreateCallback create_group_callback_; + static Dart_InitializeIsolateCallback initialize_callback_; static Dart_IsolateShutdownCallback shutdown_callback_; static Dart_IsolateCleanupCallback cleanup_callback_; + static Dart_IsolateGroupCleanupCallback cleanup_group_callback_; #if !defined(PRODUCT) static void WakePauseEventHandler(Dart_Isolate isolate); @@ -1072,6 +1167,7 @@ class Isolate : public BaseIsolate { static Monitor* isolates_list_monitor_; static Isolate* isolates_list_head_; static bool creation_enabled_; + IsolateGroupSource* source_ = nullptr; #define REUSABLE_FRIEND_DECLARATION(name) \ friend class Reusable##name##HandleScope; @@ -1145,7 +1241,8 @@ class IsolateSpawnState { bool errorsAreFatal, Dart_Port onExit, Dart_Port onError, - const char* debug_name); + const char* debug_name, + IsolateGroupSource* source); IsolateSpawnState(Dart_Port parent_port, const char* script_url, const char* package_config, @@ -1155,7 +1252,8 @@ class IsolateSpawnState { bool errorsAreFatal, Dart_Port onExit, Dart_Port onError, - const char* debug_name); + const char* debug_name, + IsolateGroupSource* source); ~IsolateSpawnState(); Isolate* isolate() const { return isolate_; } @@ -1180,6 +1278,8 @@ class IsolateSpawnState { RawInstance* BuildArgs(Thread* thread); RawInstance* BuildMessage(Thread* thread); + IsolateGroupSource* source() const { return source_; } + private: Isolate* isolate_; Dart_Port parent_port_; @@ -1192,6 +1292,7 @@ class IsolateSpawnState { const char* class_name_; const char* function_name_; const char* debug_name_; + IsolateGroupSource* source_; std::unique_ptr serialized_args_; std::unique_ptr serialized_message_; diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc index e1b8c7c92493..4002a84cf419 100644 --- a/runtime/vm/kernel_isolate.cc +++ b/runtime/vm/kernel_isolate.cc @@ -60,7 +60,7 @@ const int KernelIsolate::kListDependenciesTag = 5; const int KernelIsolate::kNotifyIsolateShutdown = 6; const char* KernelIsolate::kName = DART_KERNEL_ISOLATE_NAME; -Dart_IsolateCreateCallback KernelIsolate::create_callback_ = NULL; +Dart_IsolateGroupCreateCallback KernelIsolate::create_group_callback_ = NULL; Monitor* KernelIsolate::monitor_ = new Monitor(); KernelIsolate::State KernelIsolate::state_ = KernelIsolate::kStopped; Isolate* KernelIsolate::isolate_ = NULL; @@ -76,9 +76,9 @@ class RunKernelTask : public ThreadPool::Task { char* error = NULL; Isolate* isolate = NULL; - Dart_IsolateCreateCallback create_callback = - KernelIsolate::create_callback(); - ASSERT(create_callback != NULL); + Dart_IsolateGroupCreateCallback create_group_callback = + KernelIsolate::create_group_callback(); + ASSERT(create_group_callback != NULL); // Note: these flags must match those passed to the VM during // the app-jit training run (see //utils/kernel-service/BUILD.gn). @@ -94,8 +94,8 @@ class RunKernelTask : public ThreadPool::Task { #endif isolate = reinterpret_cast( - create_callback(KernelIsolate::kName, KernelIsolate::kName, NULL, NULL, - &api_flags, NULL, &error)); + create_group_callback(KernelIsolate::kName, KernelIsolate::kName, NULL, + NULL, &api_flags, NULL, &error)); if (isolate == NULL) { if (FLAG_trace_kernel) { OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Isolate creation error: %s\n", @@ -227,8 +227,8 @@ void KernelIsolate::Run() { } // Grab the isolate create callback here to avoid race conditions with tests // that change this after Dart_Initialize returns. - create_callback_ = Isolate::CreateCallback(); - if (create_callback_ == NULL) { + create_group_callback_ = Isolate::CreateGroupCallback(); + if (create_group_callback_ == NULL) { KernelIsolate::InitializingFailed(); return; } diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h index cdfe9da4f722..fe457dde6c08 100644 --- a/runtime/vm/kernel_isolate.h +++ b/runtime/vm/kernel_isolate.h @@ -76,11 +76,11 @@ class KernelIsolate : public AllStatic { static void FinishedExiting(); static void FinishedInitializing(); static void InitializingFailed(); - static Dart_IsolateCreateCallback create_callback() { - return create_callback_; + static Dart_IsolateGroupCreateCallback create_group_callback() { + return create_group_callback_; } - static Dart_IsolateCreateCallback create_callback_; + static Dart_IsolateGroupCreateCallback create_group_callback_; static Monitor* monitor_; enum State { kStopped, diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc index d76e551eb7fc..1ab50b1da935 100644 --- a/runtime/vm/service_isolate.cc +++ b/runtime/vm/service_isolate.cc @@ -73,7 +73,7 @@ static RawArray* MakeServerControlMessage(const SendPort& sp, } const char* ServiceIsolate::kName = DART_VM_SERVICE_ISOLATE_NAME; -Dart_IsolateCreateCallback ServiceIsolate::create_callback_ = NULL; +Dart_IsolateGroupCreateCallback ServiceIsolate::create_group_callback_ = NULL; Monitor* ServiceIsolate::monitor_ = new Monitor(); ServiceIsolate::State ServiceIsolate::state_ = ServiceIsolate::kStopped; Isolate* ServiceIsolate::isolate_ = NULL; @@ -330,16 +330,15 @@ class RunServiceTask : public ThreadPool::Task { char* error = NULL; Isolate* isolate = NULL; - Dart_IsolateCreateCallback create_callback = - ServiceIsolate::create_callback(); - ASSERT(create_callback != NULL); + const auto create_group_callback = ServiceIsolate::create_group_callback(); + ASSERT(create_group_callback != NULL); Dart_IsolateFlags api_flags; Isolate::FlagsInitialize(&api_flags); isolate = reinterpret_cast( - create_callback(ServiceIsolate::kName, ServiceIsolate::kName, NULL, - NULL, &api_flags, NULL, &error)); + create_group_callback(ServiceIsolate::kName, ServiceIsolate::kName, + NULL, NULL, &api_flags, NULL, &error)); if (isolate == NULL) { if (FLAG_trace_service) { OS::PrintErr(DART_VM_SERVICE_ISOLATE_NAME @@ -478,8 +477,8 @@ void ServiceIsolate::Run() { } // Grab the isolate create callback here to avoid race conditions with tests // that change this after Dart_Initialize returns. - create_callback_ = Isolate::CreateCallback(); - if (create_callback_ == NULL) { + create_group_callback_ = Isolate::CreateGroupCallback(); + if (create_group_callback_ == NULL) { ServiceIsolate::InitializingFailed(); return; } diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h index ab086498d3d8..6d82bdca5910 100644 --- a/runtime/vm/service_isolate.h +++ b/runtime/vm/service_isolate.h @@ -65,11 +65,11 @@ class ServiceIsolate : public AllStatic { static void FinishedInitializing(); static void InitializingFailed(); static void MaybeMakeServiceIsolate(Isolate* isolate); - static Dart_IsolateCreateCallback create_callback() { - return create_callback_; + static Dart_IsolateGroupCreateCallback create_group_callback() { + return create_group_callback_; } - static Dart_IsolateCreateCallback create_callback_; + static Dart_IsolateGroupCreateCallback create_group_callback_; static Monitor* monitor_; enum State { kStopped, diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc index b75e93b3efc6..49b6339aa8ab 100644 --- a/runtime/vm/unit_test.cc +++ b/runtime/vm/unit_test.cc @@ -37,9 +37,9 @@ const uint8_t* platform_strong_dill = kPlatformStrongDill; const intptr_t platform_strong_dill_size = kPlatformStrongDillSize; const uint8_t* TesterState::vm_snapshot_data = NULL; -Dart_IsolateCreateCallback TesterState::create_callback = NULL; +Dart_IsolateGroupCreateCallback TesterState::create_callback = NULL; Dart_IsolateShutdownCallback TesterState::shutdown_callback = NULL; -Dart_IsolateCleanupCallback TesterState::cleanup_callback = NULL; +Dart_IsolateGroupCleanupCallback TesterState::group_cleanup_callback = nullptr; const char** TesterState::argv = NULL; int TesterState::argc = 0; @@ -107,17 +107,20 @@ Dart_Isolate TestCase::CreateIsolate(const uint8_t* data_buffer, intptr_t len, const uint8_t* instr_buffer, const char* name, - void* data) { + void* group_data, + void* isolate_data) { char* err; Dart_IsolateFlags api_flags; Isolate::FlagsInitialize(&api_flags); Dart_Isolate isolate = NULL; if (len == 0) { - isolate = Dart_CreateIsolate(name, NULL, data_buffer, instr_buffer, NULL, - NULL, &api_flags, data, &err); + isolate = Dart_CreateIsolateGroup(name, NULL, data_buffer, instr_buffer, + NULL, NULL, &api_flags, group_data, + isolate_data, &err); } else { - isolate = Dart_CreateIsolateFromKernel(name, NULL, data_buffer, len, - &api_flags, data, &err); + isolate = Dart_CreateIsolateGroupFromKernel(name, NULL, data_buffer, len, + &api_flags, group_data, + isolate_data, &err); } if (isolate == NULL) { OS::PrintErr("Creation of isolate failed '%s'\n", err); @@ -127,10 +130,13 @@ Dart_Isolate TestCase::CreateIsolate(const uint8_t* data_buffer, return isolate; } -Dart_Isolate TestCase::CreateTestIsolate(const char* name, void* data) { +Dart_Isolate TestCase::CreateTestIsolate(const char* name, + void* group_data, + void* isolate_data) { return CreateIsolate(bin::core_isolate_snapshot_data, 0 /* Snapshots have length encoded within them. */, - bin::core_isolate_snapshot_instructions, name, data); + bin::core_isolate_snapshot_instructions, name, + group_data, isolate_data); } static const char* kPackageScheme = "package:"; diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h index 742e3a7f144e..cdf133aada51 100644 --- a/runtime/vm/unit_test.h +++ b/runtime/vm/unit_test.h @@ -232,9 +232,9 @@ extern const intptr_t platform_strong_dill_size; class TesterState : public AllStatic { public: static const uint8_t* vm_snapshot_data; - static Dart_IsolateCreateCallback create_callback; + static Dart_IsolateGroupCreateCallback create_callback; static Dart_IsolateShutdownCallback shutdown_callback; - static Dart_IsolateCleanupCallback cleanup_callback; + static Dart_IsolateGroupCleanupCallback group_cleanup_callback; static const char** argv; static int argc; }; @@ -358,8 +358,9 @@ class TestCase : TestCaseBase { const char* name = NULL) { return CreateIsolate(buffer, 0, NULL, name); } - static Dart_Isolate CreateTestIsolate(const char* name = NULL, - void* data = NULL); + static Dart_Isolate CreateTestIsolate(const char* name = nullptr, + void* isolate_group_data = nullptr, + void* isolate_data = nullptr); static Dart_Handle library_handler(Dart_LibraryTag tag, Dart_Handle library, Dart_Handle url); @@ -393,7 +394,8 @@ class TestCase : TestCaseBase { intptr_t len, const uint8_t* instr_buffer, const char* name, - void* data = NULL); + void* group_data = nullptr, + void* isolate_data = nullptr); static char* ValidateCompilationResult(Zone* zone, Dart_KernelCompilationResult result, diff --git a/tools/patches/flutter-engine/7340a569caac6431d8698dc3788579b57ffcf0c6.patch b/tools/patches/flutter-engine/7340a569caac6431d8698dc3788579b57ffcf0c6.patch new file mode 100644 index 000000000000..5e5755986970 --- /dev/null +++ b/tools/patches/flutter-engine/7340a569caac6431d8698dc3788579b57ffcf0c6.patch @@ -0,0 +1,147 @@ +diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc +index e181dd55b..318649190 100644 +--- a/runtime/dart_isolate.cc ++++ b/runtime/dart_isolate.cc +@@ -163,7 +163,7 @@ bool DartIsolate::Initialize(Dart_Isolate dart_isolate, bool is_root_isolate) { + } + + auto* isolate_data = static_cast*>( +- Dart_IsolateData(dart_isolate)); ++ Dart_IsolateGroupData(dart_isolate)); + if (isolate_data->get() != this) { + return false; + } +@@ -174,7 +174,7 @@ bool DartIsolate::Initialize(Dart_Isolate dart_isolate, bool is_root_isolate) { + // We are entering a new scope (for the first time since initialization) and + // we want to restore the current scope to null when we exit out of this + // method. This balances the implicit Dart_EnterIsolate call made by +- // Dart_CreateIsolate (which calls the Initialize). ++ // Dart_CreateIsolateGroup (which calls the Initialize). + Dart_ExitIsolate(); + + tonic::DartIsolateScope scope(isolate()); +@@ -720,14 +720,16 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair( + } + + // Create the Dart VM isolate and give it the embedder object as the baton. +- Dart_Isolate isolate = Dart_CreateIsolate( ++ Dart_Isolate isolate = Dart_CreateIsolateGroup( + advisory_script_uri, // + advisory_script_entrypoint, // + (*embedder_isolate)->GetIsolateSnapshot()->GetDataMapping(), + (*embedder_isolate)->GetIsolateSnapshot()->GetInstructionsMapping(), + (*embedder_isolate)->GetSharedSnapshot()->GetDataMapping(), + (*embedder_isolate)->GetSharedSnapshot()->GetInstructionsMapping(), flags, +- embedder_isolate.get(), error); ++ /*isolate_group_data=*/embedder_isolate.get(), ++ /*isolate_data=*/embedder_isolate.get(), ++ error); + + if (isolate == nullptr) { + FML_DLOG(ERROR) << *error; +@@ -770,14 +772,15 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair( + + // |Dart_IsolateShutdownCallback| + void DartIsolate::DartIsolateShutdownCallback( +- std::shared_ptr* embedder_isolate) { +- embedder_isolate->get()->OnShutdownCallback(); ++ std::shared_ptr* isolate_group_data, ++ std::shared_ptr* isolate_data) { ++ isolate_group_data->get()->OnShutdownCallback(); + } + +-// |Dart_IsolateCleanupCallback| +-void DartIsolate::DartIsolateCleanupCallback( +- std::shared_ptr* embedder_isolate) { +- delete embedder_isolate; ++// |Dart_IsolateGroupCleanupCallback| ++void DartIsolate::DartIsolateGroupCleanupCallback( ++ std::shared_ptr* isolate_group_data) { ++ delete isolate_group_data; + } + + fml::RefPtr DartIsolate::GetIsolateSnapshot() const { +diff --git a/runtime/dart_isolate.h b/runtime/dart_isolate.h +index 407852dc2..1f6689e87 100644 +--- a/runtime/dart_isolate.h ++++ b/runtime/dart_isolate.h +@@ -186,11 +186,12 @@ class DartIsolate : public UIDartState { + + // |Dart_IsolateShutdownCallback| + static void DartIsolateShutdownCallback( +- std::shared_ptr* embedder_isolate); ++ std::shared_ptr* isolate_group_data, ++ std::shared_ptr* isolate_data); + +- // |Dart_IsolateCleanupCallback| +- static void DartIsolateCleanupCallback( +- std::shared_ptr* embedder_isolate); ++ // |Dart_IsolateGroupCleanupCallback| ++ static void DartIsolateGroupCleanupCallback( ++ std::shared_ptr* isolate_group_data); + + FML_DISALLOW_COPY_AND_ASSIGN(DartIsolate); + }; +diff --git a/runtime/dart_vm.cc b/runtime/dart_vm.cc +index 903e74b15..9f6d51b7a 100644 +--- a/runtime/dart_vm.cc ++++ b/runtime/dart_vm.cc +@@ -366,12 +366,16 @@ DartVM::DartVM(std::shared_ptr vm_data, + params.vm_snapshot_data = vm_data_->GetVMSnapshot().GetDataMapping(); + params.vm_snapshot_instructions = + vm_data_->GetVMSnapshot().GetInstructionsMapping(); +- params.create = reinterpret_cast( ++ params.create_group = reinterpret_cast( + DartIsolate::DartIsolateCreateCallback); +- params.shutdown = reinterpret_cast( ++ // NOTE: The Flutter embedder does not explicitly opt into having multiple ++ // isolates inside one isolate group *yet*. This means every isolate will ++ // go into it's own isolate group atm. ++ params.initialize_isolate = nullptr; ++ params.shutdown_isolate = reinterpret_cast( + DartIsolate::DartIsolateShutdownCallback); +- params.cleanup = reinterpret_cast( +- DartIsolate::DartIsolateCleanupCallback); ++ params.cleanup_group = reinterpret_cast( ++ DartIsolate::DartIsolateGroupCleanupCallback); + params.thread_exit = ThreadExitCallback; + params.get_service_assets = GetVMServiceAssetsArchiveCallback; + params.entropy_source = dart::bin::GetEntropy; +diff --git a/shell/platform/fuchsia/dart/dart_component_controller.cc b/shell/platform/fuchsia/dart/dart_component_controller.cc +index 1c4f71050..ce607ae92 100644 +--- a/shell/platform/fuchsia/dart/dart_component_controller.cc ++++ b/shell/platform/fuchsia/dart/dart_component_controller.cc +@@ -324,10 +324,11 @@ bool DartComponentController::CreateIsolate( + auto state = new std::shared_ptr(new tonic::DartState( + namespace_fd, [this](Dart_Handle result) { MessageEpilogue(result); })); + +- isolate_ = Dart_CreateIsolate( ++ isolate_ = Dart_CreateIsolateGroup( + url_.c_str(), label_.c_str(), isolate_snapshot_data, + isolate_snapshot_instructions, shared_snapshot_data, +- shared_snapshot_instructions, nullptr /* flags */, state, &error); ++ shared_snapshot_instructions, nullptr /* flags */, ++ /*isolate_group_data=*/state, /*isolate_data=*/state, &error); + if (!isolate_) { + FX_LOGF(ERROR, LOG_TAG, "Dart_CreateIsolate failed: %s", error); + return false; +diff --git a/shell/platform/fuchsia/dart/service_isolate.cc b/shell/platform/fuchsia/dart/service_isolate.cc +index 2e6eda265..b45b40a2f 100644 +--- a/shell/platform/fuchsia/dart/service_isolate.cc ++++ b/shell/platform/fuchsia/dart/service_isolate.cc +@@ -123,12 +123,12 @@ Dart_Isolate CreateServiceIsolate(const char* uri, + #endif + + auto state = new std::shared_ptr(new tonic::DartState()); +- Dart_Isolate isolate = Dart_CreateIsolate( ++ Dart_Isolate isolate = Dart_CreateIsolateGroup( + uri, DART_VM_SERVICE_ISOLATE_NAME, mapped_isolate_snapshot_data.address(), + mapped_isolate_snapshot_instructions.address(), + mapped_shared_snapshot_data.address(), +- mapped_shared_snapshot_instructions.address(), nullptr /* flags */, state, +- error); ++ mapped_shared_snapshot_instructions.address(), nullptr /* flags */, ++ /*isolate_group_data=*/state, /*isolate_data=*/state, error); + if (!isolate) { + FX_LOGF(ERROR, LOG_TAG, "Dart_CreateIsolate failed: %s", *error); + return nullptr;