[vm/embedder] Introduce dart_standalone_embedder_api.h
This enables other emdedders to reuse parts of the standalone embedder
implementation without depending too much on the implementations details.
As part of the change we also remove a dependency from DartUtils on
IsolateData - by removing dart:_builtin library caching. Lookup
of this library does not seem to be on hot path anymore in Kernel world.
Change-Id: Ia35b28886121828fad7a96f00bcbceff75e00ae8
Reviewed-on: https://dart-review.googlesource.com/64848
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 7f55d9a..5cd4241 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -929,6 +929,7 @@
}
sources = [
+ "dart_embedder_api_impl.cc",
"error_exit.cc",
"error_exit.h",
"main.cc",
diff --git a/runtime/bin/dart_embedder_api_impl.cc b/runtime/bin/dart_embedder_api_impl.cc
new file mode 100644
index 0000000..645a7bb
--- /dev/null
+++ b/runtime/bin/dart_embedder_api_impl.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2018, 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.
+
+#include "include/dart_embedder_api.h"
+
+#include "bin/dartutils.h"
+#include "bin/eventhandler.h"
+#include "bin/isolate_data.h"
+#include "bin/thread.h"
+#include "bin/utils.h"
+#include "bin/vmservice_impl.h"
+
+namespace dart {
+namespace embedder {
+
+static char* MallocFormatedString(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ intptr_t len = vsnprintf(NULL, 0, format, args);
+ va_end(args);
+
+ char* buffer = reinterpret_cast<char*>(malloc(len + 1));
+ MSAN_UNPOISON(buffer, (len + 1));
+ va_list args2;
+ va_start(args2, format);
+ vsnprintf(buffer, (len + 1), format, args2);
+ va_end(args2);
+ return buffer;
+}
+
+bool InitOnce(char** error) {
+ if (!bin::DartUtils::SetOriginalWorkingDirectory()) {
+ bin::OSError err;
+ *error = MallocFormatedString("Error determining current directory: %s\n",
+ err.message());
+ return false;
+ }
+ bin::Thread::InitOnce();
+ bin::TimerUtils::InitOnce();
+ bin::EventHandler::Start();
+ return true;
+}
+
+Dart_Isolate CreateKernelServiceIsolate(const IsolateCreationData& data,
+ const uint8_t* buffer,
+ intptr_t buffer_size,
+ char** error) {
+ Dart_Isolate kernel_isolate = Dart_CreateIsolateFromKernel(
+ data.script_uri, data.main, buffer, buffer_size, data.flags,
+ data.callback_data, error);
+ if (kernel_isolate == nullptr) {
+ return nullptr;
+ }
+
+ Dart_EnterScope();
+ Dart_Handle result = Dart_LoadScriptFromKernel(buffer, buffer_size);
+ if (Dart_IsError(result)) {
+ *error = strdup(Dart_GetError(result));
+ Dart_ExitScope();
+ Dart_ShutdownIsolate();
+ return nullptr;
+ }
+ result = bin::DartUtils::PrepareForScriptLoading(/*is_service_isolate=*/false,
+ /*trace_loading=*/false);
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+ return kernel_isolate;
+}
+
+Dart_Isolate CreateVmServiceIsolate(const IsolateCreationData& data,
+ const VmServiceConfiguration& config,
+ const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_size,
+ char** error) {
+ if (data.flags == nullptr) {
+ *error = strdup("Expected non-null flags");
+ return nullptr;
+ }
+ data.flags->load_vmservice_library = true;
+
+ Dart_Isolate service_isolate = Dart_CreateIsolateFromKernel(
+ data.script_uri, data.main, kernel_buffer, kernel_buffer_size, data.flags,
+ data.callback_data, error);
+ if (service_isolate == nullptr) {
+ return nullptr;
+ }
+
+ Dart_EnterScope();
+ // Load embedder specific bits and return.
+ if (!bin::VmService::Setup(config.ip, config.port,
+ /*running_precompiled=*/true, config.dev_mode,
+ /*trace_loading=*/false, config.deterministic)) {
+ *error = strdup(bin::VmService::GetErrorMessage());
+ Dart_ExitScope();
+ Dart_ShutdownIsolate();
+ return nullptr;
+ }
+
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+ return service_isolate;
+}
+
+} // namespace embedder
+} // namespace dart
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index e7c7886..6bba557 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -385,18 +385,16 @@
}
Dart_Handle DartUtils::SetWorkingDirectory() {
- IsolateData* isolate_data =
- reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
- Dart_Handle builtin_lib = isolate_data->builtin_lib();
Dart_Handle directory = NewString(original_working_directory);
- return SingleArgDart_Invoke(builtin_lib, "_setWorkingDirectory", directory);
+ return SingleArgDart_Invoke(LookupBuiltinLib(), "_setWorkingDirectory",
+ directory);
}
Dart_Handle DartUtils::ResolveUriInWorkingDirectory(Dart_Handle script_uri) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = script_uri;
- return Dart_Invoke(DartUtils::BuiltinLib(),
+ return Dart_Invoke(DartUtils::LookupBuiltinLib(),
NewString("_resolveInWorkingDirectory"), kNumArgs,
dart_args);
}
@@ -405,16 +403,16 @@
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = library_uri;
- return Dart_Invoke(DartUtils::BuiltinLib(), NewString("_libraryFilePath"),
- kNumArgs, dart_args);
+ return Dart_Invoke(DartUtils::LookupBuiltinLib(),
+ NewString("_libraryFilePath"), kNumArgs, dart_args);
}
Dart_Handle DartUtils::ResolveScript(Dart_Handle url) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = url;
- return Dart_Invoke(DartUtils::BuiltinLib(), NewString("_resolveScriptUri"),
- kNumArgs, dart_args);
+ return Dart_Invoke(DartUtils::LookupBuiltinLib(),
+ NewString("_resolveScriptUri"), kNumArgs, dart_args);
}
static bool CheckMagicNumber(const uint8_t* buffer,
@@ -569,16 +567,16 @@
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = result;
- result = Dart_Invoke(DartUtils::BuiltinLib(), NewString("_setPackageRoot"),
- kNumArgs, dart_args);
+ result = Dart_Invoke(DartUtils::LookupBuiltinLib(),
+ NewString("_setPackageRoot"), kNumArgs, dart_args);
} else if (packages_config != NULL) {
result = NewString(packages_config);
RETURN_IF_ERROR(result);
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = result;
- result = Dart_Invoke(DartUtils::BuiltinLib(), NewString("_setPackagesMap"),
- kNumArgs, dart_args);
+ result = Dart_Invoke(DartUtils::LookupBuiltinLib(),
+ NewString("_setPackagesMap"), kNumArgs, dart_args);
}
return result;
}
@@ -613,13 +611,6 @@
RETURN_IF_ERROR(cli_lib);
Builtin::SetNativeResolver(Builtin::kCLILibrary);
- // Setup the builtin library in a persistent handle attached the isolate
- // specific data as we seem to lookup and use builtin lib a lot.
- IsolateData* isolate_data =
- reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
- ASSERT(isolate_data != NULL);
- isolate_data->set_builtin_lib(builtin_lib);
-
// We need to ensure that all the scripts loaded so far are finalized
// as we are about to invoke some Dart code below to setup closures.
Dart_Handle result = Dart_FinalizeLoading(false);
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 661ec7f..68cd47f 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -204,10 +204,8 @@
static Dart_Handle NewError(const char* format, ...);
static Dart_Handle NewInternalError(const char* message);
- static Dart_Handle BuiltinLib() {
- IsolateData* isolate_data =
- reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
- return isolate_data->builtin_lib();
+ static Dart_Handle LookupBuiltinLib() {
+ return Dart_LookupLibrary(NewString(kBuiltinLibURL));
}
static bool SetOriginalWorkingDirectory();
diff --git a/runtime/bin/isolate_data.cc b/runtime/bin/isolate_data.cc
index c7f1779..dfd440c 100644
--- a/runtime/bin/isolate_data.cc
+++ b/runtime/bin/isolate_data.cc
@@ -15,7 +15,6 @@
: script_url((url != NULL) ? strdup(url) : NULL),
package_root(NULL),
packages_file(NULL),
- builtin_lib_(NULL),
loader_(NULL),
app_snapshot_(app_snapshot),
dependencies_(NULL),
@@ -32,10 +31,6 @@
}
void IsolateData::OnIsolateShutdown() {
- if (builtin_lib_ != NULL) {
- Dart_DeletePersistentHandle(builtin_lib_);
- builtin_lib_ = NULL;
- }
}
IsolateData::~IsolateData() {
diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h
index 575d1b0..ceab601 100644
--- a/runtime/bin/isolate_data.h
+++ b/runtime/bin/isolate_data.h
@@ -36,18 +36,6 @@
AppSnapshot* app_snapshot);
~IsolateData();
- Dart_Handle builtin_lib() const {
- ASSERT(builtin_lib_ != NULL);
- ASSERT(!Dart_IsError(builtin_lib_));
- return builtin_lib_;
- }
- void set_builtin_lib(Dart_Handle lib) {
- ASSERT(builtin_lib_ == NULL);
- ASSERT(lib != NULL);
- ASSERT(!Dart_IsError(lib));
- builtin_lib_ = Dart_NewPersistentHandle(lib);
- }
-
char* script_url;
char* package_root;
char* packages_file;
@@ -99,7 +87,6 @@
void OnIsolateShutdown();
private:
- Dart_Handle builtin_lib_;
Loader* loader_;
AppSnapshot* app_snapshot_;
MallocGrowableArray<char*>* dependencies_;
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 38b59c3..51bbe73 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -7,6 +7,7 @@
#include <string.h>
#include "include/dart_api.h"
+#include "include/dart_embedder_api.h"
#include "include/dart_tools_api.h"
#include "bin/builtin.h"
@@ -267,11 +268,6 @@
Dart_EnterScope();
Dart_Handle library = Dart_LoadScriptFromKernel(payload, payload_length);
CHECK_RESULT(library);
- Dart_Handle url = DartUtils::NewString("dart:_builtin");
- CHECK_RESULT(url);
- Dart_Handle builtin_lib = Dart_LookupLibrary(url);
- CHECK_RESULT(builtin_lib);
- isolate_data->set_builtin_lib(builtin_lib);
Dart_ExitScope();
Dart_ExitIsolate();
@@ -1018,7 +1014,7 @@
Dart_Handle root_lib = Dart_RootLibrary();
// Import the root library into the builtin library so that we can easily
// lookup the main entry point exported from the root library.
- result = Dart_LibraryImportLibrary(isolate_data->builtin_lib(), root_lib,
+ result = Dart_LibraryImportLibrary(DartUtils::LookupBuiltinLib(), root_lib,
Dart_Null());
#if !defined(DART_PRECOMPILED_RUNTIME)
if (Options::gen_snapshot_kind() == kAppAOT) {
@@ -1222,8 +1218,6 @@
}
}
- Thread::InitOnce();
-
Loader::InitOnce();
if (!DartUtils::SetOriginalWorkingDirectory()) {
@@ -1284,7 +1278,14 @@
Process::SetExitHook(SnapshotOnExitHook);
}
- char* error = Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
+ char* error = nullptr;
+ if (!dart::embedder::InitOnce(&error)) {
+ Log::PrintErr("Stanalone embedder initialization failed: %s\n", error);
+ free(error);
+ Platform::Exit(kErrorExitCode);
+ }
+
+ error = Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
if (error != NULL) {
Log::PrintErr("Setting VM flags failed: %s\n", error);
free(error);
@@ -1309,10 +1310,6 @@
}
#endif
- // Start event handler.
- TimerUtils::InitOnce();
- EventHandler::Start();
-
// Initialize the Dart VM.
Dart_InitializeParams init_params;
memset(&init_params, 0, sizeof(init_params));
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 74f96e6..f512dfb 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -41,7 +41,7 @@
int length_;
};
-#if defined(DART_PRECOMPILED_RUNTIME)
+#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_DART2_ONLY_MODE)
ResourcesEntry __service_bin_resources_[] = {{NULL, NULL, 0}};
#else
extern ResourcesEntry __service_bin_resources_[];
@@ -185,7 +185,8 @@
// Prepare builtin and its dependent 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(true, false);
+ result = DartUtils::PrepareForScriptLoading(/*is_service_isolate=*/true,
+ trace_loading);
SHUTDOWN_ON_ERROR(result);
if (running_precompiled) {
@@ -261,12 +262,6 @@
Dart_SetField(library, DartUtils::NewString("_isFuchsia"), is_fuchsia);
SHUTDOWN_ON_ERROR(result);
- if (trace_loading) {
- result = Dart_SetField(library, DartUtils::NewString("_traceLoading"),
- Dart_True());
- SHUTDOWN_ON_ERROR(result);
- }
-
if (deterministic) {
result = Dart_SetField(library, DartUtils::NewString("_deterministic"),
Dart_True());
diff --git a/runtime/include/dart_embedder_api.h b/runtime/include/dart_embedder_api.h
new file mode 100644
index 0000000..eda9059
--- /dev/null
+++ b/runtime/include/dart_embedder_api.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2018, 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_INCLUDE_DART_EMBEDDER_API_H_
+#define RUNTIME_INCLUDE_DART_EMBEDDER_API_H_
+
+#include "dart_api.h"
+#include "dart_tools_api.h"
+
+namespace dart {
+namespace embedder {
+
+// Initialize all subsystems of the embedder.
+// Returns true on success and false otherwise, in which case error would
+// contain error message.
+DART_WARN_UNUSED_RESULT bool InitOnce(char** error);
+
+// Common arguments that are passed to isolate creation callback and to
+// API methods that create isolates.
+struct IsolateCreationData {
+ // URI for the main script that will be running in the isolate.
+ const char* script_uri;
+
+ // Advisory name of the main method that will be run by isolate.
+ // Only used for error messages.
+ const char* main;
+
+ // Isolate creation flags. Might be absent.
+ Dart_IsolateFlags* flags;
+
+ // Isolate callback data.
+ void* callback_data;
+};
+
+// Create and initialize kernel-service isolate. This method should be used
+// when VM invokes isolate creation callback with DART_KERNEL_ISOLATE_NAME as
+// script_uri.
+// The isolate is created from the given snapshot (might be kernel data or
+// app-jit snapshot).
+DART_WARN_UNUSED_RESULT Dart_Isolate
+CreateKernelServiceIsolate(const IsolateCreationData& data,
+ const uint8_t* buffer,
+ intptr_t buffer_size,
+ char** error);
+
+// Service isolate configuration.
+struct VmServiceConfiguration {
+ enum {
+ kBindHttpServerToAFreePort = 0,
+ kDoNotAutoStartHttpServer = -1
+ };
+
+ // Address to which HTTP server will be bound.
+ const char* ip;
+
+ // Default port. See enum above for special values.
+ int port;
+
+ // TODO(vegorov) document these ones.
+ bool dev_mode;
+ bool deterministic;
+};
+
+// Create and initialize vm-service isolate. This method should be used
+// when VM invokes isolate creation callback with DART_VM_SERVICE_ISOLATE_NAME
+// as script_uri.
+// The isolate is created from the given kernel binary that is expected to
+// contain all necessary vmservice libraries.
+DART_WARN_UNUSED_RESULT Dart_Isolate
+CreateVmServiceIsolate(const IsolateCreationData& data,
+ const VmServiceConfiguration& config,
+ const uint8_t* kernel_buffer,
+ intptr_t kernel_buffer_size,
+ char** error);
+
+} // namespace embedder
+} // namespace dart
+
+#endif // RUNTIME_INCLUDE_DART_EMBEDDER_API_H_
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index c065f34..89c1883 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -213,7 +213,7 @@
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = DartUtils::NewString(uri_chars);
- return Dart_Invoke(DartUtils::BuiltinLib(),
+ return Dart_Invoke(DartUtils::LookupBuiltinLib(),
DartUtils::NewString("_filePathFromUri"), kNumArgs,
dart_args);
}