Skip to content

Commit b75057b

Browse files
mkustermanncommit-bot@chromium.org
authored and
commit-bot@chromium.org
committed
[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 #36648 Issue #36097 Change-Id: I82437ac017ca33018d45e02f353b0672db155f6a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105241 Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Alexander Aprelev <aam@google.com>
1 parent 9e3b44b commit b75057b

27 files changed

+1122
-459
lines changed

runtime/bin/dart_embedder_api_impl.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ Dart_Isolate CreateKernelServiceIsolate(const IsolateCreationData& data,
4545
const uint8_t* buffer,
4646
intptr_t buffer_size,
4747
char** error) {
48-
Dart_Isolate kernel_isolate = Dart_CreateIsolateFromKernel(
48+
Dart_Isolate kernel_isolate = Dart_CreateIsolateGroupFromKernel(
4949
data.script_uri, data.main, buffer, buffer_size, data.flags,
50-
data.callback_data, error);
50+
data.isolate_group_data, data.isolate_data, error);
5151
if (kernel_isolate == nullptr) {
5252
return nullptr;
5353
}
@@ -78,9 +78,9 @@ Dart_Isolate CreateVmServiceIsolate(const IsolateCreationData& data,
7878
}
7979
data.flags->load_vmservice_library = true;
8080

81-
Dart_Isolate service_isolate = Dart_CreateIsolateFromKernel(
81+
Dart_Isolate service_isolate = Dart_CreateIsolateGroupFromKernel(
8282
data.script_uri, data.main, kernel_buffer, kernel_buffer_size, data.flags,
83-
data.callback_data, error);
83+
data.isolate_group_data, data.isolate_data, error);
8484
if (service_isolate == nullptr) {
8585
return nullptr;
8686
}

runtime/bin/gen_snapshot.cc

+12-11
Original file line numberDiff line numberDiff line change
@@ -745,23 +745,24 @@ static int CreateIsolateAndSnapshot(const CommandLineOptions& inputs) {
745745
isolate_flags.entry_points = no_entry_points;
746746
}
747747

748-
IsolateData* isolate_data = new IsolateData(NULL, NULL, NULL, NULL);
748+
auto isolate_group_data = new IsolateGroupData(NULL, NULL, NULL, NULL);
749749
Dart_Isolate isolate;
750750
char* error = NULL;
751751
if (isolate_snapshot_data == NULL) {
752752
// We need to capture the vmservice library in the core snapshot, so load it
753753
// in the main isolate as well.
754754
isolate_flags.load_vmservice_library = true;
755-
isolate = Dart_CreateIsolateFromKernel(NULL, NULL, kernel_buffer,
756-
kernel_buffer_size, &isolate_flags,
757-
isolate_data, &error);
755+
isolate = Dart_CreateIsolateGroupFromKernel(
756+
NULL, NULL, kernel_buffer, kernel_buffer_size, &isolate_flags,
757+
isolate_group_data, /*isolate_data=*/nullptr, &error);
758758
} else {
759-
isolate = Dart_CreateIsolate(NULL, NULL, isolate_snapshot_data,
760-
isolate_snapshot_instructions, NULL, NULL,
761-
&isolate_flags, isolate_data, &error);
759+
isolate = Dart_CreateIsolateGroup(NULL, NULL, isolate_snapshot_data,
760+
isolate_snapshot_instructions, NULL, NULL,
761+
&isolate_flags, isolate_group_data,
762+
/*isolate_data=*/nullptr, &error);
762763
}
763764
if (isolate == NULL) {
764-
delete isolate_data;
765+
delete isolate_group_data;
765766
Syslog::PrintErr("%s\n", error);
766767
free(error);
767768
return kErrorExitCode;
@@ -783,9 +784,9 @@ static int CreateIsolateAndSnapshot(const CommandLineOptions& inputs) {
783784
// If the input dill file does not have a root library, then
784785
// Dart_LoadScript will error.
785786
//
786-
// TODO(kernel): Dart_CreateIsolateFromKernel should respect the root library
787-
// in the kernel file, though this requires auditing the other loading paths
788-
// in the embedders that had to work around this.
787+
// TODO(kernel): Dart_CreateIsolateGroupFromKernel should respect the root
788+
// library in the kernel file, though this requires auditing the other
789+
// loading paths in the embedders that had to work around this.
789790
result = Dart_SetRootLibrary(
790791
Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size));
791792
CHECK_RESULT(result);

runtime/bin/isolate_data.cc

+5-8
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
namespace dart {
1010
namespace bin {
1111

12-
IsolateData::IsolateData(const char* url,
13-
const char* package_root,
14-
const char* packages_file,
15-
AppSnapshot* app_snapshot)
12+
IsolateGroupData::IsolateGroupData(const char* url,
13+
const char* package_root,
14+
const char* packages_file,
15+
AppSnapshot* app_snapshot)
1616
: script_url((url != NULL) ? strdup(url) : NULL),
1717
package_root(NULL),
1818
packages_file(NULL),
@@ -30,10 +30,7 @@ IsolateData::IsolateData(const char* url,
3030
}
3131
}
3232

33-
void IsolateData::OnIsolateShutdown() {
34-
}
35-
36-
IsolateData::~IsolateData() {
33+
IsolateGroupData::~IsolateGroupData() {
3734
free(script_url);
3835
script_url = NULL;
3936
free(package_root);

runtime/bin/isolate_data.h

+14-14
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ class Loader;
3131
// Data associated with every isolate in the standalone VM
3232
// embedding. This is used to free external resources for each isolate
3333
// when the isolate shuts down.
34-
class IsolateData {
34+
class IsolateGroupData {
3535
public:
36-
IsolateData(const char* url,
37-
const char* package_root,
38-
const char* packages_file,
39-
AppSnapshot* app_snapshot);
40-
~IsolateData();
36+
IsolateGroupData(const char* url,
37+
const char* package_root,
38+
const char* packages_file,
39+
AppSnapshot* app_snapshot);
40+
~IsolateGroupData();
4141

4242
char* script_url;
4343
char* package_root;
@@ -49,26 +49,26 @@ class IsolateData {
4949

5050
intptr_t kernel_buffer_size() const { return kernel_buffer_size_; }
5151

52-
// Associate the given kernel buffer with this IsolateData without giving it
53-
// ownership of the buffer.
52+
// Associate the given kernel buffer with this IsolateGroupData without
53+
// giving it ownership of the buffer.
5454
void SetKernelBufferUnowned(uint8_t* buffer, intptr_t size) {
5555
ASSERT(kernel_buffer_.get() == NULL);
5656
kernel_buffer_ = std::shared_ptr<uint8_t>(buffer, FreeUnownedKernelBuffer);
5757
kernel_buffer_size_ = size;
5858
}
5959

60-
// Associate the given kernel buffer with this IsolateData and give it
61-
// ownership of the buffer. This IsolateData is the first one to own the
60+
// Associate the given kernel buffer with this IsolateGroupData and give it
61+
// ownership of the buffer. This IsolateGroupData is the first one to own the
6262
// buffer.
6363
void SetKernelBufferNewlyOwned(uint8_t* buffer, intptr_t size) {
6464
ASSERT(kernel_buffer_.get() == NULL);
6565
kernel_buffer_ = std::shared_ptr<uint8_t>(buffer, free);
6666
kernel_buffer_size_ = size;
6767
}
6868

69-
// Associate the given kernel buffer with this IsolateData and give it
69+
// Associate the given kernel buffer with this IsolateGroupData and give it
7070
// ownership of the buffer. The buffer is already owned by another
71-
// IsolateData.
71+
// IsolateGroupData.
7272
void SetKernelBufferAlreadyOwned(std::shared_ptr<uint8_t> buffer,
7373
intptr_t size) {
7474
ASSERT(kernel_buffer_.get() == NULL);
@@ -111,7 +111,7 @@ class IsolateData {
111111
dependencies_ = deps;
112112
}
113113

114-
void OnIsolateShutdown();
114+
bool RunFromAppSnapshot() const { return app_snapshot_ != nullptr; }
115115

116116
private:
117117
Loader* loader_;
@@ -123,7 +123,7 @@ class IsolateData {
123123

124124
static void FreeUnownedKernelBuffer(uint8_t*) {}
125125

126-
DISALLOW_COPY_AND_ASSIGN(IsolateData);
126+
DISALLOW_COPY_AND_ASSIGN(IsolateGroupData);
127127
};
128128

129129
} // namespace bin

runtime/bin/loader.cc

+43-40
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ extern DFE dfe;
2929
static const intptr_t _Dart_kImportExtension = 9;
3030
static const intptr_t _Dart_kResolveAsFilePath = 10;
3131

32-
Loader::Loader(IsolateData* isolate_data)
32+
Loader::Loader(IsolateGroupData* isolate_group_data)
3333
: port_(ILLEGAL_PORT),
34-
isolate_data_(isolate_data),
34+
isolate_group_data_(isolate_group_data),
3535
error_(Dart_Null()),
3636
monitor_(),
3737
pending_operations_(0),
@@ -40,10 +40,10 @@ Loader::Loader(IsolateData* isolate_data)
4040
results_capacity_(0),
4141
payload_(NULL),
4242
payload_length_(0) {
43-
ASSERT(isolate_data_ != NULL);
43+
ASSERT(isolate_group_data_ != NULL);
4444
port_ = Dart_NewNativePort("Loader", Loader::NativeMessageHandler, false);
45-
isolate_data_->set_loader(this);
46-
AddLoader(port_, isolate_data_);
45+
isolate_group_data_->set_loader(this);
46+
AddLoader(port_, isolate_group_data_);
4747
}
4848

4949
Loader::~Loader() {
@@ -55,8 +55,8 @@ Loader::~Loader() {
5555
monitor_.Exit();
5656
RemoveLoader(port_);
5757
port_ = ILLEGAL_PORT;
58-
isolate_data_->set_loader(NULL);
59-
isolate_data_ = NULL;
58+
isolate_group_data_->set_loader(NULL);
59+
isolate_group_data_ = NULL;
6060
for (intptr_t i = 0; i < results_length_; i++) {
6161
results_[i].Cleanup();
6262
}
@@ -263,18 +263,18 @@ static bool PathContainsSeparator(const char* path) {
263263

264264
void Loader::AddDependencyLocked(Loader* loader, const char* resolved_uri) {
265265
MallocGrowableArray<char*>* dependencies =
266-
loader->isolate_data_->dependencies();
266+
loader->isolate_group_data_->dependencies();
267267
if (dependencies == NULL) {
268268
return;
269269
}
270270
dependencies->Add(strdup(resolved_uri));
271271
}
272272

273273
void Loader::ResolveDependenciesAsFilePaths() {
274-
IsolateData* isolate_data =
275-
reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
276-
ASSERT(isolate_data != NULL);
277-
MallocGrowableArray<char*>* dependencies = isolate_data->dependencies();
274+
IsolateGroupData* isolate_group_data =
275+
reinterpret_cast<IsolateGroupData*>(Dart_CurrentIsolateGroupData());
276+
ASSERT(isolate_group_data != NULL);
277+
MallocGrowableArray<char*>* dependencies = isolate_group_data->dependencies();
278278
if (dependencies == NULL) {
279279
return;
280280
}
@@ -455,14 +455,15 @@ bool Loader::ProcessQueueLocked(ProcessResult process_result) {
455455
}
456456

457457
void Loader::InitForSnapshot(const char* snapshot_uri) {
458-
IsolateData* isolate_data =
459-
reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
460-
ASSERT(isolate_data != NULL);
461-
ASSERT(!isolate_data->HasLoader());
458+
IsolateGroupData* isolate_group_data =
459+
reinterpret_cast<IsolateGroupData*>(Dart_CurrentIsolateGroupData());
460+
ASSERT(isolate_group_data != NULL);
461+
ASSERT(!isolate_group_data->HasLoader());
462462
// Setup a loader. The constructor does a bunch of leg work.
463-
Loader* loader = new Loader(isolate_data);
463+
Loader* loader = new Loader(isolate_group_data);
464464
// Send the init message.
465-
loader->Init(isolate_data->package_root, isolate_data->packages_file,
465+
loader->Init(isolate_group_data->package_root,
466+
isolate_group_data->packages_file,
466467
DartUtils::original_working_directory, snapshot_uri);
467468
// Destroy the loader. The destructor does a bunch of leg work.
468469
delete loader;
@@ -516,18 +517,19 @@ Dart_Handle Loader::SendAndProcessReply(intptr_t tag,
516517
Dart_Handle url,
517518
uint8_t** payload,
518519
intptr_t* payload_length) {
519-
IsolateData* isolate_data =
520-
reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
521-
ASSERT(isolate_data != NULL);
522-
ASSERT(!isolate_data->HasLoader());
520+
IsolateGroupData* isolate_group_data =
521+
reinterpret_cast<IsolateGroupData*>(Dart_CurrentIsolateGroupData());
522+
ASSERT(isolate_group_data != NULL);
523+
ASSERT(!isolate_group_data->HasLoader());
523524
Loader* loader = NULL;
524525

525526
// Setup the loader. The constructor does a bunch of leg work.
526-
loader = new Loader(isolate_data);
527-
loader->Init(isolate_data->package_root, isolate_data->packages_file,
527+
loader = new Loader(isolate_group_data);
528+
loader->Init(isolate_group_data->package_root,
529+
isolate_group_data->packages_file,
528530
DartUtils::original_working_directory, NULL);
529531
ASSERT(loader != NULL);
530-
ASSERT(isolate_data->HasLoader());
532+
ASSERT(isolate_group_data->HasLoader());
531533

532534
// Now send a load request to the service isolate.
533535
loader->SendRequest(tag, url, Dart_Null());
@@ -679,46 +681,47 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag,
679681
}
680682
}
681683

682-
IsolateData* isolate_data =
683-
reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
684-
ASSERT(isolate_data != NULL);
684+
IsolateGroupData* isolate_group_data =
685+
reinterpret_cast<IsolateGroupData*>(Dart_CurrentIsolateGroupData());
686+
ASSERT(isolate_group_data != NULL);
685687
if ((tag == Dart_kScriptTag) && Dart_IsString(library)) {
686688
// Update packages file for isolate.
687689
const char* packages_file = NULL;
688690
Dart_Handle result = Dart_StringToCString(library, &packages_file);
689691
if (Dart_IsError(result)) {
690692
return result;
691693
}
692-
isolate_data->UpdatePackagesFile(packages_file);
694+
isolate_group_data->UpdatePackagesFile(packages_file);
693695
}
694696
// Grab this isolate's loader.
695697
Loader* loader = NULL;
696698

697699
// The outer invocation of the tag handler for this isolate. We make the outer
698700
// invocation block and allow any nested invocations to operate in parallel.
699-
const bool blocking_call = !isolate_data->HasLoader();
701+
const bool blocking_call = !isolate_group_data->HasLoader();
700702

701703
// If we are the outer invocation of the tag handler and the tag is an import
702704
// this means that we are starting a deferred library load.
703705
const bool is_deferred_import = blocking_call && (tag == Dart_kImportTag);
704-
if (!isolate_data->HasLoader()) {
706+
if (!isolate_group_data->HasLoader()) {
705707
// The isolate doesn't have a loader -- this is the outer invocation which
706708
// will block.
707709

708710
// Setup the loader. The constructor does a bunch of leg work.
709-
loader = new Loader(isolate_data);
710-
loader->Init(isolate_data->package_root, isolate_data->packages_file,
711+
loader = new Loader(isolate_group_data);
712+
loader->Init(isolate_group_data->package_root,
713+
isolate_group_data->packages_file,
711714
DartUtils::original_working_directory,
712715
(tag == Dart_kScriptTag) ? url_string : NULL);
713716
} else {
714717
ASSERT(tag != Dart_kScriptTag);
715718
// The isolate has a loader -- this is an inner invocation that will queue
716719
// work with the service isolate.
717720
// Use the existing loader.
718-
loader = isolate_data->loader();
721+
loader = isolate_group_data->loader();
719722
}
720723
ASSERT(loader != NULL);
721-
ASSERT(isolate_data->HasLoader());
724+
ASSERT(isolate_group_data->HasLoader());
722725

723726
if (DartUtils::IsDartExtensionSchemeURL(url_string)) {
724727
loader->SendImportExtensionRequest(url, Dart_LibraryUrl(library));
@@ -815,11 +818,11 @@ Loader::LoaderInfo* Loader::loader_infos_ = NULL;
815818
intptr_t Loader::loader_infos_length_ = 0;
816819
intptr_t Loader::loader_infos_capacity_ = 0;
817820

818-
// Add a mapping from |port| to |isolate_data| (really the loader). When a
821+
// Add a mapping from |port| to |isolate_group_data| (really the loader). When a
819822
// native message arrives, we use this map to report the I/O result to the
820823
// correct loader.
821824
// This happens whenever an isolate begins loading.
822-
void Loader::AddLoader(Dart_Port port, IsolateData* isolate_data) {
825+
void Loader::AddLoader(Dart_Port port, IsolateGroupData* isolate_group_data) {
823826
MutexLocker ml(loader_infos_lock_);
824827
ASSERT(LoaderForLocked(port) == NULL);
825828
if (loader_infos_length_ == loader_infos_capacity_) {
@@ -832,12 +835,12 @@ void Loader::AddLoader(Dart_Port port, IsolateData* isolate_data) {
832835
// Initialize new entries.
833836
for (intptr_t i = loader_infos_length_; i < loader_infos_capacity_; i++) {
834837
loader_infos_[i].port = ILLEGAL_PORT;
835-
loader_infos_[i].isolate_data = NULL;
838+
loader_infos_[i].isolate_group_data = NULL;
836839
}
837840
}
838841
ASSERT(loader_infos_length_ < loader_infos_capacity_);
839842
loader_infos_[loader_infos_length_].port = port;
840-
loader_infos_[loader_infos_length_].isolate_data = isolate_data;
843+
loader_infos_[loader_infos_length_].isolate_group_data = isolate_group_data;
841844
loader_infos_length_++;
842845
ASSERT(LoaderForLocked(port) != NULL);
843846
}
@@ -871,7 +874,7 @@ Loader* Loader::LoaderForLocked(Dart_Port port) {
871874
if (index < 0) {
872875
return NULL;
873876
}
874-
return loader_infos_[index].isolate_data->loader();
877+
return loader_infos_[index].isolate_group_data->loader();
875878
}
876879

877880
Loader* Loader::LoaderFor(Dart_Port port) {

0 commit comments

Comments
 (0)