[vm] Experimental ability to spawn isolate from kernel blob in memory
TEST=runtime/tests/vm/dart/spawn_uri_from_kernel_blob_test.dart Change-Id: Ieb327f0350d5d8ea1d344c64aa3dd217125da5fe Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/232682 Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Siva Annamalai <asiva@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
committed by
Commit Bot
parent
774cafe41d
commit
211da364be
+94
-6
@@ -9,6 +9,7 @@
|
||||
#include "bin/error_exit.h"
|
||||
#include "bin/exe_utils.h"
|
||||
#include "bin/file.h"
|
||||
#include "bin/lockers.h"
|
||||
#include "bin/platform.h"
|
||||
#include "bin/utils.h"
|
||||
#include "include/dart_tools_api.h"
|
||||
@@ -65,8 +66,9 @@ DFE::DFE()
|
||||
use_incremental_compiler_(false),
|
||||
frontend_filename_(nullptr),
|
||||
application_kernel_buffer_(nullptr),
|
||||
application_kernel_buffer_size_(0) {
|
||||
}
|
||||
application_kernel_buffer_size_(0),
|
||||
kernel_blobs_(&SimpleHashMap::SameStringValue, 4),
|
||||
kernel_blobs_lock_() {}
|
||||
|
||||
DFE::~DFE() {
|
||||
if (frontend_filename_ != nullptr) {
|
||||
@@ -77,6 +79,9 @@ DFE::~DFE() {
|
||||
free(application_kernel_buffer_);
|
||||
application_kernel_buffer_ = nullptr;
|
||||
application_kernel_buffer_size_ = 0;
|
||||
|
||||
kernel_blobs_.Clear(
|
||||
[](void* value) { delete reinterpret_cast<KernelBlob*>(value); });
|
||||
}
|
||||
|
||||
void DFE::Init() {
|
||||
@@ -247,14 +252,19 @@ void DFE::CompileAndReadScript(const char* script_uri,
|
||||
void DFE::ReadScript(const char* script_uri,
|
||||
uint8_t** kernel_buffer,
|
||||
intptr_t* kernel_buffer_size,
|
||||
bool decode_uri) const {
|
||||
bool decode_uri,
|
||||
std::shared_ptr<uint8_t>* kernel_blob_ptr) {
|
||||
int64_t start = Dart_TimelineGetMicros();
|
||||
if (!TryReadKernelFile(script_uri, kernel_buffer, kernel_buffer_size,
|
||||
decode_uri)) {
|
||||
decode_uri, kernel_blob_ptr)) {
|
||||
return;
|
||||
}
|
||||
if (!Dart_IsKernel(*kernel_buffer, *kernel_buffer_size)) {
|
||||
free(*kernel_buffer);
|
||||
if (kernel_blob_ptr != nullptr && *kernel_blob_ptr) {
|
||||
*kernel_blob_ptr = nullptr;
|
||||
} else {
|
||||
free(*kernel_buffer);
|
||||
}
|
||||
*kernel_buffer = nullptr;
|
||||
*kernel_buffer_size = -1;
|
||||
}
|
||||
@@ -438,10 +448,21 @@ static bool TryReadKernelListBuffer(const char* script_uri,
|
||||
bool DFE::TryReadKernelFile(const char* script_uri,
|
||||
uint8_t** kernel_ir,
|
||||
intptr_t* kernel_ir_size,
|
||||
bool decode_uri) {
|
||||
bool decode_uri,
|
||||
std::shared_ptr<uint8_t>* kernel_blob_ptr) {
|
||||
*kernel_ir = nullptr;
|
||||
*kernel_ir_size = -1;
|
||||
|
||||
if (decode_uri && kernel_blob_ptr != nullptr) {
|
||||
*kernel_blob_ptr = TryFindKernelBlob(script_uri, kernel_ir_size);
|
||||
if (*kernel_blob_ptr) {
|
||||
*kernel_ir = kernel_blob_ptr->get();
|
||||
ASSERT(DartUtils::SniffForMagicNumber(*kernel_ir, *kernel_ir_size) ==
|
||||
DartUtils::kKernelMagicNumber);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* buffer;
|
||||
if (!TryReadFile(script_uri, &buffer, kernel_ir_size, decode_uri)) {
|
||||
return false;
|
||||
@@ -456,5 +477,72 @@ bool DFE::TryReadKernelFile(const char* script_uri,
|
||||
return TryReadSimpleKernelBuffer(buffer, kernel_ir, kernel_ir_size);
|
||||
}
|
||||
|
||||
const char* DFE::RegisterKernelBlob(const uint8_t* kernel_buffer,
|
||||
intptr_t kernel_buffer_size) {
|
||||
ASSERT(DartUtils::SniffForMagicNumber(kernel_buffer, kernel_buffer_size) ==
|
||||
DartUtils::kKernelMagicNumber);
|
||||
uint8_t* buffer_copy = reinterpret_cast<uint8_t*>(malloc(kernel_buffer_size));
|
||||
if (buffer_copy == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
memmove(buffer_copy, kernel_buffer, kernel_buffer_size);
|
||||
|
||||
MutexLocker ml(&kernel_blobs_lock_);
|
||||
++kernel_blob_counter_;
|
||||
char* uri =
|
||||
Utils::SCreate("dart-kernel-blob://blob%" Pd, kernel_blob_counter_);
|
||||
KernelBlob* blob = new KernelBlob(uri, buffer_copy, kernel_buffer_size);
|
||||
|
||||
const uint32_t hash = SimpleHashMap::StringHash(uri);
|
||||
SimpleHashMap::Entry* entry =
|
||||
kernel_blobs_.Lookup(uri, hash, /*insert=*/true);
|
||||
ASSERT(entry != nullptr);
|
||||
ASSERT(entry->value == nullptr);
|
||||
entry->value = blob;
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
std::shared_ptr<uint8_t> DFE::TryFindKernelBlob(const char* uri,
|
||||
intptr_t* kernel_length) {
|
||||
*kernel_length = -1;
|
||||
|
||||
MutexLocker ml(&kernel_blobs_lock_);
|
||||
if (kernel_blob_counter_ == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This const_cast is safe as this 'key' is only used to find entry, not add.
|
||||
void* key = const_cast<char*>(uri);
|
||||
const uint32_t hash = SimpleHashMap::StringHash(uri);
|
||||
SimpleHashMap::Entry* entry =
|
||||
kernel_blobs_.Lookup(key, hash, /*insert=*/false);
|
||||
if (entry == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
KernelBlob* blob = reinterpret_cast<KernelBlob*>(entry->value);
|
||||
*kernel_length = blob->size();
|
||||
return blob->buffer();
|
||||
}
|
||||
|
||||
void DFE::UnregisterKernelBlob(const char* uri) {
|
||||
MutexLocker ml(&kernel_blobs_lock_);
|
||||
|
||||
// This const_cast is safe as this 'key' is only used to find entry, not add.
|
||||
void* key = const_cast<char*>(uri);
|
||||
const uint32_t hash = SimpleHashMap::StringHash(uri);
|
||||
SimpleHashMap::Entry* entry =
|
||||
kernel_blobs_.Lookup(key, hash, /*insert=*/false);
|
||||
if (entry == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
KernelBlob* blob = reinterpret_cast<KernelBlob*>(entry->value);
|
||||
entry->value = nullptr;
|
||||
kernel_blobs_.Remove(key, hash);
|
||||
delete blob;
|
||||
}
|
||||
|
||||
} // namespace bin
|
||||
} // namespace dart
|
||||
|
||||
+61
-10
@@ -7,10 +7,12 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "bin/thread.h"
|
||||
#include "include/dart_api.h"
|
||||
#include "include/dart_native_api.h"
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
#include "platform/hashmap.h"
|
||||
#include "platform/utils.h"
|
||||
|
||||
namespace dart {
|
||||
@@ -102,23 +104,34 @@ class DFE {
|
||||
|
||||
// Reads the script kernel file if specified 'script_uri' is a kernel file.
|
||||
// Returns an in memory kernel representation of the specified script is a
|
||||
// valid kernel file, false otherwise.
|
||||
// valid kernel file, sets 'kernel_buffer' to nullptr otherwise.
|
||||
//
|
||||
// If 'kernel_blob_ptr' is not nullptr, then this function can also
|
||||
// read kernel blobs. In such case it sets 'kernel_blob_ptr'
|
||||
// to a shared pointer which owns the kernel buffer.
|
||||
// Othwerise, the caller is responsible for free()ing 'kernel_buffer'.
|
||||
void ReadScript(const char* script_uri,
|
||||
uint8_t** kernel_buffer,
|
||||
intptr_t* kernel_buffer_size,
|
||||
bool decode_uri = true) const;
|
||||
bool decode_uri = true,
|
||||
std::shared_ptr<uint8_t>* kernel_blob_ptr = nullptr);
|
||||
|
||||
bool KernelServiceDillAvailable() const;
|
||||
|
||||
// Tries to read [script_uri] as a Kernel IR file.
|
||||
// Returns `true` if successful and sets [kernel_file] and [kernel_length]
|
||||
// Tries to read 'script_uri' as a Kernel IR file.
|
||||
// Returns `true` if successful and sets 'kernel_buffer' and 'kernel_length'
|
||||
// to be the kernel IR contents.
|
||||
// The caller is responsible for free()ing [kernel_file] if `true`
|
||||
// was returned.
|
||||
static bool TryReadKernelFile(const char* script_uri,
|
||||
uint8_t** kernel_buffer,
|
||||
intptr_t* kernel_buffer_size,
|
||||
bool decode_uri = true);
|
||||
//
|
||||
// If 'kernel_blob_ptr' is not nullptr, then this function can also
|
||||
// read kernel blobs. In such case it sets 'kernel_blob_ptr'
|
||||
// to a shared pointer which owns the kernel buffer.
|
||||
// Othwerise, the caller is responsible for free()ing 'kernel_buffer'
|
||||
// if `true` was returned.
|
||||
bool TryReadKernelFile(const char* script_uri,
|
||||
uint8_t** kernel_buffer,
|
||||
intptr_t* kernel_buffer_size,
|
||||
bool decode_uri = true,
|
||||
std::shared_ptr<uint8_t>* kernel_blob_ptr = nullptr);
|
||||
|
||||
// We distinguish between "intent to use Dart frontend" vs "can actually
|
||||
// use Dart frontend". The method UseDartFrontend tells us about the
|
||||
@@ -131,6 +144,22 @@ class DFE {
|
||||
void LoadKernelService(const uint8_t** kernel_service_buffer,
|
||||
intptr_t* kernel_service_buffer_size);
|
||||
|
||||
// Registers given kernel blob and returns blob URI which
|
||||
// can be used in TryReadKernelFile later to load the given kernel.
|
||||
// Data from [kernel_buffer] is copied, it doesn't need to stay alive.
|
||||
// Returns NULL if failed to allocate memory.
|
||||
const char* RegisterKernelBlob(const uint8_t* kernel_buffer,
|
||||
intptr_t kernel_buffer_size);
|
||||
|
||||
// Looks for kernel blob using the given [uri].
|
||||
// Returns non-null pointer to the kernel blob if successful and
|
||||
// sets [kernel_length].
|
||||
std::shared_ptr<uint8_t> TryFindKernelBlob(const char* uri,
|
||||
intptr_t* kernel_length);
|
||||
|
||||
// Unregisters kernel blob with given URI.
|
||||
void UnregisterKernelBlob(const char* uri);
|
||||
|
||||
private:
|
||||
bool use_dfe_;
|
||||
bool use_incremental_compiler_;
|
||||
@@ -142,11 +171,33 @@ class DFE {
|
||||
uint8_t* application_kernel_buffer_;
|
||||
intptr_t application_kernel_buffer_size_;
|
||||
|
||||
// Registry of kernel blobs. Maps URI (char *) to KernelBlob.
|
||||
SimpleHashMap kernel_blobs_;
|
||||
intptr_t kernel_blob_counter_ = 0;
|
||||
Mutex kernel_blobs_lock_;
|
||||
|
||||
void InitKernelServiceAndPlatformDills();
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DFE);
|
||||
};
|
||||
|
||||
class KernelBlob {
|
||||
public:
|
||||
// Takes ownership over [uri] and [buffer].
|
||||
KernelBlob(char* uri, uint8_t* buffer, intptr_t size)
|
||||
: uri_(uri, std::free), buffer_(buffer, std::free), size_(size) {}
|
||||
|
||||
std::shared_ptr<uint8_t> buffer() { return buffer_; }
|
||||
intptr_t size() const { return size_; }
|
||||
|
||||
private:
|
||||
Utils::CStringUniquePtr uri_;
|
||||
std::shared_ptr<uint8_t> buffer_;
|
||||
const intptr_t size_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(KernelBlob);
|
||||
};
|
||||
|
||||
class PathSanitizer {
|
||||
public:
|
||||
explicit PathSanitizer(const char* path);
|
||||
|
||||
@@ -83,8 +83,8 @@ Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag,
|
||||
if (tag == Dart_kKernelTag) {
|
||||
uint8_t* kernel_buffer = NULL;
|
||||
intptr_t kernel_buffer_size = 0;
|
||||
if (!DFE::TryReadKernelFile(url_string, &kernel_buffer,
|
||||
&kernel_buffer_size)) {
|
||||
if (!dfe.TryReadKernelFile(url_string, &kernel_buffer,
|
||||
&kernel_buffer_size)) {
|
||||
return DartUtils::NewError("'%s' is not a kernel file", url_string);
|
||||
}
|
||||
result = Dart_NewExternalTypedData(Dart_TypedData_kUint8, kernel_buffer,
|
||||
|
||||
+21
-6
@@ -689,7 +689,7 @@ static Dart_Isolate CreateIsolateGroupAndSetupHelper(
|
||||
int64_t start = Dart_TimelineGetMicros();
|
||||
ASSERT(script_uri != NULL);
|
||||
uint8_t* kernel_buffer = NULL;
|
||||
std::shared_ptr<uint8_t> parent_kernel_buffer;
|
||||
std::shared_ptr<uint8_t> kernel_buffer_ptr;
|
||||
intptr_t kernel_buffer_size = 0;
|
||||
AppSnapshot* app_snapshot = NULL;
|
||||
|
||||
@@ -750,13 +750,14 @@ static Dart_Isolate CreateIsolateGroupAndSetupHelper(
|
||||
if (flags->copy_parent_code && callback_data != nullptr) {
|
||||
auto parent_isolate_group_data =
|
||||
reinterpret_cast<IsolateData*>(callback_data)->isolate_group_data();
|
||||
parent_kernel_buffer = parent_isolate_group_data->kernel_buffer();
|
||||
kernel_buffer = parent_kernel_buffer.get();
|
||||
kernel_buffer_ptr = parent_isolate_group_data->kernel_buffer();
|
||||
kernel_buffer = kernel_buffer_ptr.get();
|
||||
kernel_buffer_size = parent_isolate_group_data->kernel_buffer_size();
|
||||
}
|
||||
|
||||
if (kernel_buffer == NULL && !isolate_run_app_snapshot) {
|
||||
dfe.ReadScript(script_uri, &kernel_buffer, &kernel_buffer_size);
|
||||
dfe.ReadScript(script_uri, &kernel_buffer, &kernel_buffer_size,
|
||||
/*decode_uri=*/true, &kernel_buffer_ptr);
|
||||
}
|
||||
PathSanitizer script_uri_sanitizer(script_uri);
|
||||
PathSanitizer packages_config_sanitizer(packages_config);
|
||||
@@ -770,9 +771,9 @@ static Dart_Isolate CreateIsolateGroupAndSetupHelper(
|
||||
auto isolate_group_data = new IsolateGroupData(
|
||||
script_uri, packages_config, app_snapshot, isolate_run_app_snapshot);
|
||||
if (kernel_buffer != NULL) {
|
||||
if (parent_kernel_buffer) {
|
||||
if (kernel_buffer_ptr) {
|
||||
isolate_group_data->SetKernelBufferAlreadyOwned(
|
||||
std::move(parent_kernel_buffer), kernel_buffer_size);
|
||||
std::move(kernel_buffer_ptr), kernel_buffer_size);
|
||||
} else {
|
||||
isolate_group_data->SetKernelBufferNewlyOwned(kernel_buffer,
|
||||
kernel_buffer_size);
|
||||
@@ -888,6 +889,16 @@ static Dart_Isolate CreateIsolateGroupAndSetup(const char* script_uri,
|
||||
error, &exit_code);
|
||||
}
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
static const char* RegisterKernelBlob(const uint8_t* kernel_buffer,
|
||||
intptr_t kernel_buffer_size) {
|
||||
return dfe.RegisterKernelBlob(kernel_buffer, kernel_buffer_size);
|
||||
}
|
||||
static void UnregisterKernelBlob(const char* kernel_blob_uri) {
|
||||
dfe.UnregisterKernelBlob(kernel_blob_uri);
|
||||
}
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
static void OnIsolateShutdown(void* isolate_group_data, void* isolate_data) {
|
||||
Dart_EnterScope();
|
||||
Dart_Handle sticky_error = Dart_GetStickyError();
|
||||
@@ -1332,6 +1343,10 @@ void main(int argc, char** argv) {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
init_params.start_kernel_isolate =
|
||||
dfe.UseDartFrontend() && dfe.CanUseDartFrontend();
|
||||
if (init_params.start_kernel_isolate) {
|
||||
init_params.register_kernel_blob = RegisterKernelBlob;
|
||||
init_params.unregister_kernel_blob = UnregisterKernelBlob;
|
||||
}
|
||||
#else
|
||||
init_params.start_kernel_isolate = false;
|
||||
#endif
|
||||
|
||||
@@ -919,6 +919,36 @@ typedef void (*Dart_PostTaskCallback)(void* post_task_data,
|
||||
*/
|
||||
DART_EXPORT void Dart_RunTask(Dart_Task task);
|
||||
|
||||
/**
|
||||
* Optional callback provided by the embedder that is used by the VM to
|
||||
* implement registration of kernel blobs for the subsequent Isolate.spawnUri
|
||||
* If no callback is provided, the registration of kernel blobs will throw
|
||||
* an error.
|
||||
*
|
||||
* \param kernel_buffer A buffer which contains a kernel program. Callback
|
||||
* should copy the contents of `kernel_buffer` as
|
||||
* it may be freed immediately after registration.
|
||||
* \param kernel_buffer_size The size of `kernel_buffer`.
|
||||
*
|
||||
* \return A C string representing URI which can be later used
|
||||
* to spawn a new isolate. This C String should be scope allocated
|
||||
* or owned by the embedder.
|
||||
* Returns NULL if embedder runs out of memory.
|
||||
*/
|
||||
typedef const char* (*Dart_RegisterKernelBlobCallback)(
|
||||
const uint8_t* kernel_buffer,
|
||||
intptr_t kernel_buffer_size);
|
||||
|
||||
/**
|
||||
* Optional callback provided by the embedder that is used by the VM to
|
||||
* unregister kernel blobs.
|
||||
* If no callback is provided, the unregistration of kernel blobs will throw
|
||||
* an error.
|
||||
*
|
||||
* \param kernel_blob_uri URI of the kernel blob to unregister.
|
||||
*/
|
||||
typedef void (*Dart_UnregisterKernelBlobCallback)(const char* kernel_blob_uri);
|
||||
|
||||
/**
|
||||
* Describes how to initialize the VM. Used with Dart_Initialize.
|
||||
*/
|
||||
@@ -1003,6 +1033,16 @@ typedef struct {
|
||||
Dart_PostTaskCallback post_task;
|
||||
|
||||
void* post_task_data;
|
||||
|
||||
/**
|
||||
* Kernel blob registration callback function. See Dart_RegisterKernelBlobCallback.
|
||||
*/
|
||||
Dart_RegisterKernelBlobCallback register_kernel_blob;
|
||||
|
||||
/**
|
||||
* Kernel blob unregistration callback function. See Dart_UnregisterKernelBlobCallback.
|
||||
*/
|
||||
Dart_UnregisterKernelBlobCallback unregister_kernel_blob;
|
||||
} Dart_InitializeParams;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1071,6 +1071,62 @@ DEFINE_NATIVE_ENTRY(Isolate_getCurrentRootUriStr, 0, 0) {
|
||||
return root_lib.url();
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(Isolate_registerKernelBlob, 0, 1) {
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(TypedData, kernel_blob,
|
||||
arguments->NativeArgAt(0));
|
||||
auto register_kernel_blob_callback = Isolate::RegisterKernelBlobCallback();
|
||||
if (register_kernel_blob_callback == nullptr) {
|
||||
const auto& error =
|
||||
String::Handle(zone, String::New("Registration of kernel blobs is not "
|
||||
"supported by this Dart embedder.\n"));
|
||||
Exceptions::ThrowArgumentError(error);
|
||||
UNREACHABLE();
|
||||
}
|
||||
bool is_kernel = false;
|
||||
{
|
||||
NoSafepointScope no_safepoint;
|
||||
is_kernel =
|
||||
Dart_IsKernel(reinterpret_cast<uint8_t*>(kernel_blob.DataAddr(0)),
|
||||
kernel_blob.LengthInBytes());
|
||||
}
|
||||
if (!is_kernel) {
|
||||
const auto& error = String::Handle(
|
||||
zone, String::New("kernelBlob doesn\'t contain a valid kernel.\n"));
|
||||
Exceptions::ThrowArgumentError(error);
|
||||
UNREACHABLE();
|
||||
}
|
||||
const char* uri = nullptr;
|
||||
{
|
||||
NoSafepointScope no_safepoint;
|
||||
uri = register_kernel_blob_callback(
|
||||
reinterpret_cast<uint8_t*>(kernel_blob.DataAddr(0)),
|
||||
kernel_blob.LengthInBytes());
|
||||
}
|
||||
if (uri == nullptr) {
|
||||
const Instance& exception = Instance::Handle(
|
||||
thread->isolate_group()->object_store()->out_of_memory());
|
||||
Exceptions::Throw(thread, exception);
|
||||
UNREACHABLE();
|
||||
}
|
||||
return String::New(uri);
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(Isolate_unregisterKernelBlob, 0, 1) {
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(String, kernel_blob_uri,
|
||||
arguments->NativeArgAt(0));
|
||||
auto unregister_kernel_blob_callback =
|
||||
Isolate::UnregisterKernelBlobCallback();
|
||||
if (unregister_kernel_blob_callback == nullptr) {
|
||||
const auto& error =
|
||||
String::Handle(zone, String::New("Registration of kernel blobs is not "
|
||||
"supported by this Dart embedder.\n"));
|
||||
Exceptions::ThrowArgumentError(error);
|
||||
UNREACHABLE();
|
||||
}
|
||||
unregister_kernel_blob_callback(kernel_blob_uri.ToCString());
|
||||
return Object::null();
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(Isolate_sendOOB, 0, 2) {
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(Array, msg, arguments->NativeArgAt(1));
|
||||
|
||||
@@ -23,7 +23,7 @@ class SimpleHashMap {
|
||||
|
||||
static bool SamePointerValue(void* key1, void* key2) { return key1 == key2; }
|
||||
|
||||
static uint32_t StringHash(char* key) {
|
||||
static uint32_t StringHash(const char* key) {
|
||||
uint32_t hash_ = 0;
|
||||
if (key == NULL) return hash_;
|
||||
int len = strlen(key);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import "dart:convert";
|
||||
import "dart:isolate";
|
||||
|
||||
main(List<String> args, SendPort replyPort) {
|
||||
final String encoded = base64.encode(args[0].codeUnits);
|
||||
replyPort.send(String.fromCharCodes(base64.decode(encoded)));
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// OtherResources=spawn_uri_from_kernel_blob_script.dart
|
||||
|
||||
// Test for Isolate.createUriForKernelBlob and subsequent Isolate.spawnUri.
|
||||
|
||||
import 'dart:io' show Platform;
|
||||
import 'dart:isolate' show Isolate, ReceivePort;
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import 'package:front_end/src/api_unstable/vm.dart'
|
||||
show CompilerOptions, DiagnosticMessage, kernelForProgram, NnbdMode;
|
||||
import 'package:kernel/kernel.dart';
|
||||
import 'package:kernel/target/targets.dart';
|
||||
import 'package:vm/target/vm.dart' show VmTarget;
|
||||
|
||||
import 'snapshot_test_helper.dart';
|
||||
|
||||
main() async {
|
||||
final sourceUri =
|
||||
Platform.script.resolve('spawn_uri_from_kernel_blob_script.dart');
|
||||
final options = new CompilerOptions()
|
||||
..target = VmTarget(TargetFlags())
|
||||
..additionalDills = <Uri>[Uri.file(platformDill)]
|
||||
..environmentDefines = {}
|
||||
..nnbdMode = hasSoundNullSafety ? NnbdMode.Strong : NnbdMode.Weak
|
||||
..onDiagnostic = (DiagnosticMessage message) {
|
||||
Expect.fail(
|
||||
"Compilation error: ${message.plainTextFormatted.join('\n')}");
|
||||
};
|
||||
final Component component =
|
||||
(await kernelForProgram(sourceUri, options))!.component!;
|
||||
final kernelBlob = writeComponentToBytes(component) as Uint8List;
|
||||
|
||||
final kernelBlobUri =
|
||||
(Isolate.current as dynamic).createUriForKernelBlob(kernelBlob);
|
||||
|
||||
print('URI: $kernelBlobUri');
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
final receivePort = ReceivePort();
|
||||
receivePort.listen((message) {
|
||||
Expect.equals(message, 'Hello');
|
||||
print('ok');
|
||||
receivePort.close();
|
||||
});
|
||||
|
||||
await Isolate.spawnUri(kernelBlobUri, ['Hello'], receivePort.sendPort);
|
||||
}
|
||||
|
||||
(Isolate.current as dynamic).unregisterKernelBlobUri(kernelBlobUri);
|
||||
|
||||
try {
|
||||
await Isolate.spawnUri(kernelBlobUri, ['Hello'], null);
|
||||
Expect.fail(
|
||||
"Isolate.spawnUri didn't complete with error after unregisterKernelBlobUri");
|
||||
} catch (e) {
|
||||
print('Got exception: $e');
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,7 @@ cc/Mixin_PrivateSuperResolution: Skip
|
||||
cc/Mixin_PrivateSuperResolutionCrossLibraryShouldFail: Skip
|
||||
dart/b162922506_test: SkipByDesign # Only run in JIT
|
||||
dart/entrypoints/jit/*: SkipByDesign # These tests should only run on JIT.
|
||||
dart/spawn_uri_from_kernel_blob_test: SkipByDesign # Only run in JIT.
|
||||
dart_2/b162922506_test: SkipByDesign # Only run in JIT
|
||||
dart_2/entrypoints/jit/*: SkipByDesign # These tests should only run on JIT.
|
||||
dart_2/isolates/reload_*: SkipByDesign # These tests only run on normal JIT.
|
||||
|
||||
@@ -304,6 +304,8 @@ namespace dart {
|
||||
V(Isolate_getCurrentRootUriStr, 0) \
|
||||
V(Isolate_getDebugName, 1) \
|
||||
V(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0) \
|
||||
V(Isolate_registerKernelBlob, 1) \
|
||||
V(Isolate_unregisterKernelBlob, 1) \
|
||||
V(Isolate_sendOOB, 2) \
|
||||
V(Isolate_spawnFunction, 10) \
|
||||
V(Isolate_spawnUri, 12) \
|
||||
|
||||
@@ -484,6 +484,8 @@ char* Dart::DartInit(const Dart_InitializeParams* params) {
|
||||
Isolate::SetShutdownCallback(params->shutdown_isolate);
|
||||
Isolate::SetCleanupCallback(params->cleanup_isolate);
|
||||
Isolate::SetGroupCleanupCallback(params->cleanup_group);
|
||||
Isolate::SetRegisterKernelBlobCallback(params->register_kernel_blob);
|
||||
Isolate::SetUnregisterKernelBlobCallback(params->unregister_kernel_blob);
|
||||
|
||||
#ifndef PRODUCT
|
||||
const bool support_service = true;
|
||||
|
||||
@@ -1785,6 +1785,8 @@ void Isolate::InitVM() {
|
||||
shutdown_callback_ = nullptr;
|
||||
cleanup_callback_ = nullptr;
|
||||
cleanup_group_callback_ = nullptr;
|
||||
register_kernel_blob_callback_ = nullptr;
|
||||
unregister_kernel_blob_callback_ = nullptr;
|
||||
if (isolate_creation_monitor_ == nullptr) {
|
||||
isolate_creation_monitor_ = new Monitor();
|
||||
}
|
||||
@@ -2707,6 +2709,10 @@ 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;
|
||||
Dart_RegisterKernelBlobCallback Isolate::register_kernel_blob_callback_ =
|
||||
nullptr;
|
||||
Dart_UnregisterKernelBlobCallback Isolate::unregister_kernel_blob_callback_ =
|
||||
nullptr;
|
||||
|
||||
Random* IsolateGroup::isolate_group_random_ = nullptr;
|
||||
Monitor* Isolate::isolate_creation_monitor_ = nullptr;
|
||||
|
||||
@@ -1230,6 +1230,20 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry<Isolate> {
|
||||
static Dart_IsolateGroupCleanupCallback GroupCleanupCallback() {
|
||||
return cleanup_group_callback_;
|
||||
}
|
||||
static void SetRegisterKernelBlobCallback(
|
||||
Dart_RegisterKernelBlobCallback cb) {
|
||||
register_kernel_blob_callback_ = cb;
|
||||
}
|
||||
static Dart_RegisterKernelBlobCallback RegisterKernelBlobCallback() {
|
||||
return register_kernel_blob_callback_;
|
||||
}
|
||||
static void SetUnregisterKernelBlobCallback(
|
||||
Dart_UnregisterKernelBlobCallback cb) {
|
||||
unregister_kernel_blob_callback_ = cb;
|
||||
}
|
||||
static Dart_UnregisterKernelBlobCallback UnregisterKernelBlobCallback() {
|
||||
return unregister_kernel_blob_callback_;
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
ObjectIdRing* object_id_ring() const { return object_id_ring_; }
|
||||
@@ -1680,6 +1694,8 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry<Isolate> {
|
||||
static Dart_IsolateShutdownCallback shutdown_callback_;
|
||||
static Dart_IsolateCleanupCallback cleanup_callback_;
|
||||
static Dart_IsolateGroupCleanupCallback cleanup_group_callback_;
|
||||
static Dart_RegisterKernelBlobCallback register_kernel_blob_callback_;
|
||||
static Dart_UnregisterKernelBlobCallback unregister_kernel_blob_callback_;
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
static void WakePauseEventHandler(Dart_Isolate isolate);
|
||||
|
||||
@@ -652,6 +652,31 @@ class Isolate {
|
||||
static Never exit([SendPort? finalMessagePort, Object? message]) {
|
||||
_exit(finalMessagePort, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Uri representing the script which was compiled into kernel
|
||||
* binary in [kernelBlob].
|
||||
* The resulting Uri can be used for the subsequent spawnUri calls.
|
||||
* Such spawnUri will start an isolate which would run the given
|
||||
* compiled script in [kernelBlob].
|
||||
*/
|
||||
/*static*/ Uri createUriForKernelBlob(Uint8List kernelBlob) {
|
||||
return Uri.parse(_registerKernelBlob(kernelBlob));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters kernel blob previously registered with
|
||||
* [createUriForKernelBlob] and frees underlying resources.
|
||||
*/
|
||||
/*static*/ void unregisterKernelBlobUri(Uri kernelBlobUri) {
|
||||
_unregisterKernelBlob(kernelBlobUri.toString());
|
||||
}
|
||||
|
||||
@pragma("vm:external-name", "Isolate_registerKernelBlob")
|
||||
external static String _registerKernelBlob(Uint8List kernelBlob);
|
||||
|
||||
@pragma("vm:external-name", "Isolate_unregisterKernelBlob")
|
||||
external static void _unregisterKernelBlob(String kernelBlobUri);
|
||||
}
|
||||
|
||||
@patch
|
||||
|
||||
Reference in New Issue
Block a user