Files
sdk/runtime/bin/loader.h
T
Alexander Aprelev 0425997b31 Second attempt to reland "[vm/concurrency] Introduce concept of Isolate Groups"
This reverts commit 3d14b75f97.

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

Original review: https://dart-review.googlesource.com/c/sdk/+/105241

Difference to original review:

  * Give each isolate it's own [Loader] (for now)
  * Sort classes during initialization for spawned isolates if app-jit is used (to match main isolate)
  * Fix IsolateData memory leak if isolate startup fails

Difference to first reland(Patchset 2):

  * Fix typo where memory was freed twice.

Change-Id: Ib1c83fe83b629cd50ae6af90ee99fdd44da882d4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/108367
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2019-07-08 23:49:05 +00:00

163 lines
5.7 KiB
C++

// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_BIN_LOADER_H_
#define RUNTIME_BIN_LOADER_H_
#include "bin/isolate_data.h"
#include "bin/thread.h"
#include "include/dart_api.h"
#include "include/dart_native_api.h"
#include "platform/assert.h"
#include "platform/globals.h"
namespace dart {
namespace bin {
class Loader {
public:
explicit Loader(IsolateData* isolate_data);
~Loader();
static void InitForSnapshot(const char* snapshot_uri,
IsolateData* isolate_data);
static Dart_Handle ReloadNativeExtensions();
// Loads contents of the specified url.
static Dart_Handle LoadUrlContents(Dart_Handle url,
uint8_t** payload,
intptr_t* payload_length);
static void ResolveDependenciesAsFilePaths();
// A static tag handler that hides all usage of a loader for an isolate.
static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url);
IsolateGroupData* isolate_group_data();
Dart_Handle error() const { return error_; }
static void InitOnce();
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_;
// Remember the first error that occurs during loading.
Dart_Handle error_;
// This monitor is used to protect the pending operations count and the
// I/O result queue.
Monitor monitor_;
// The number of operations dispatched to the service isolate for loading.
// Must be accessed with monitor_ held.
intptr_t pending_operations_;
// The result of an I/O request to the service isolate. Payload is either
// a UInt8Array or a C string containing an error message.
struct IOResult {
uint8_t* payload;
intptr_t payload_length;
char* library_uri;
char* uri;
char* resolved_uri;
int8_t tag;
void Setup(Dart_CObject* message);
void Cleanup();
};
// An array of I/O results queued from the service isolate.
IOResult* results_;
intptr_t results_length_;
intptr_t results_capacity_;
uint8_t* payload_;
intptr_t payload_length_;
typedef bool (*ProcessResult)(Loader* loader, IOResult* result);
intptr_t results_length() {
return *static_cast<volatile intptr_t*>(&results_length_);
}
// Send the loader init request to the service isolate.
void Init(const char* package_root,
const char* packages_file,
const char* working_directory,
const char* root_script_uri);
// Send a request for a dart-ext: import to the service isolate.
void SendImportExtensionRequest(Dart_Handle url, Dart_Handle library_url);
// Send a request from the tag handler to the service isolate.
void SendRequest(intptr_t tag, Dart_Handle url, Dart_Handle library_url);
static Dart_Handle SendAndProcessReply(intptr_t tag,
Dart_Handle url,
uint8_t** payload,
intptr_t* payload_length);
static Dart_Handle ResolveAsFilePath(Dart_Handle url,
uint8_t** payload,
intptr_t* payload_length);
/// Queue |message| and notify the loader that a message is available.
void QueueMessage(Dart_CObject* message);
/// Blocks the caller until the loader is finished.
void BlockUntilComplete(ProcessResult process_result);
/// Saves a script dependency when applicable.
static void AddDependencyLocked(Loader* loader, const char* resolved_uri);
/// Returns false if |result| is an error and the loader should quit.
static bool ProcessResultLocked(Loader* loader, IOResult* result);
/// Returns false if |result| is an error and the loader should quit.
static bool ProcessPayloadResultLocked(Loader* loader, IOResult* result);
/// Returns false if an error occurred and the loader should quit.
bool ProcessQueueLocked(ProcessResult process_result);
// Special inner tag handler for dart: uris.
static Dart_Handle DartColonLibraryTagHandler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url,
const char* library_url_string,
const char* url_string);
// 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|.
// Static information to map Dart_Port back to the isolate in question.
struct LoaderInfo {
Dart_Port port;
IsolateData* isolate_data;
};
// The map of active loaders.
static Mutex* loader_infos_lock_;
static LoaderInfo* loader_infos_;
static intptr_t loader_infos_length_;
static intptr_t loader_infos_capacity_;
static void AddLoader(Dart_Port port, IsolateData* data);
static void RemoveLoader(Dart_Port port);
static intptr_t LoaderIndexFor(Dart_Port port);
static Loader* LoaderFor(Dart_Port port);
static Loader* LoaderForLocked(Dart_Port port);
// This is the global callback for the native message handlers.
static void NativeMessageHandler(Dart_Port dest_port_id,
Dart_CObject* message);
};
} // namespace bin
} // namespace dart
#endif // RUNTIME_BIN_LOADER_H_