| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/callback.h" |
| #include "base/files/file_util.h" |
| #include "base/logging.h" |
| #include "base/path_service.h" |
| #include "base/sys_info.h" |
| #include "crypto/random.h" |
| #include "dart/runtime/include/dart_api.h" |
| #include "dart/runtime/include/dart_native_api.h" |
| #include "mojo/dart/embedder/builtin.h" |
| #include "mojo/dart/embedder/dart_controller.h" |
| #include "mojo/dart/embedder/isolate_data.h" |
| #include "mojo/public/c/system/core.h" |
| |
| namespace mojo { |
| namespace dart { |
| |
| extern const uint8_t* vm_isolate_snapshot_buffer; |
| extern const uint8_t* isolate_snapshot_buffer; |
| |
| const char* kDartScheme = "dart:"; |
| const char* kAsyncLibURL = "dart:async"; |
| const char* kInternalLibURL = "dart:_internal"; |
| const char* kIsolateLibURL = "dart:isolate"; |
| const char* kIOLibURL = "dart:io"; |
| const char* kCoreLibURL = "dart:core"; |
| |
| static bool IsDartSchemeURL(const char* url_name) { |
| static const intptr_t kDartSchemeLen = strlen(kDartScheme); |
| // If the URL starts with "dart:" then it is considered as a special |
| // library URL which is handled differently from other URLs. |
| return (strncmp(url_name, kDartScheme, kDartSchemeLen) == 0); |
| } |
| |
| static bool IsServiceIsolateURL(const char* url_name) { |
| if (url_name == nullptr) { |
| return false; |
| } |
| static const intptr_t kServiceIsolateNameLen = |
| strlen(DART_VM_SERVICE_ISOLATE_NAME); |
| return (strncmp(url_name, |
| DART_VM_SERVICE_ISOLATE_NAME, |
| kServiceIsolateNameLen) == 0); |
| } |
| |
| static bool IsDartIOLibURL(const char* url_name) { |
| return (strcmp(url_name, kIOLibURL) == 0); |
| } |
| |
| static void ReportScriptError(Dart_Handle handle) { |
| // The normal DART_CHECK_VALID macro displays error information and a stack |
| // dump for the C++ application, which is confusing. Only show the Dart error. |
| if (Dart_IsError((handle))) { |
| LOG(ERROR) << "Dart runtime error:\n" << Dart_GetError(handle) << "\n"; |
| } |
| } |
| |
| Dart_Handle ResolveUri(Dart_Handle library_url, |
| Dart_Handle url, |
| Dart_Handle builtin_lib) { |
| const int kNumArgs = 2; |
| Dart_Handle dart_args[kNumArgs]; |
| dart_args[0] = library_url; |
| dart_args[1] = url; |
| return Dart_Invoke(builtin_lib, |
| Dart_NewStringFromCString("_resolveUri"), |
| kNumArgs, |
| dart_args); |
| } |
| |
| static Dart_Handle LoadDataAsync_Invoke(Dart_Handle tag, |
| Dart_Handle url, |
| Dart_Handle library_url, |
| Dart_Handle builtin_lib, |
| Dart_Handle data) { |
| const int kNumArgs = 4; |
| Dart_Handle dart_args[kNumArgs]; |
| dart_args[0] = tag; |
| dart_args[1] = url; |
| dart_args[2] = library_url; |
| dart_args[3] = data; |
| return Dart_Invoke(builtin_lib, |
| Dart_NewStringFromCString("_loadDataAsync"), |
| kNumArgs, |
| dart_args); |
| } |
| |
| static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag, |
| Dart_Handle library, |
| Dart_Handle url) { |
| if (!Dart_IsLibrary(library)) { |
| return Dart_NewApiError("not a library"); |
| } |
| if (!Dart_IsString(url)) { |
| return Dart_NewApiError("url is not a string"); |
| } |
| Dart_Handle library_url = Dart_LibraryUrl(library); |
| const char* library_url_string = nullptr; |
| Dart_Handle result = Dart_StringToCString(library_url, &library_url_string); |
| if (Dart_IsError(result)) { |
| return result; |
| } |
| |
| bool is_io_library = IsDartIOLibURL(library_url_string); |
| |
| // Handle IO library. |
| if (is_io_library) { |
| return Builtin::NewError( |
| "The built-in io library is not available in this embedding: %s.\n", |
| library_url_string); |
| } |
| |
| // Handle URI canonicalization requests. |
| const char* url_string = nullptr; |
| result = Dart_StringToCString(url, &url_string); |
| if (tag == Dart_kCanonicalizeUrl) { |
| if (Dart_IsError(result)) { |
| return result; |
| } |
| const bool is_internal_scheme_url = IsDartSchemeURL(url_string); |
| // If this is a Dart Scheme URL, or a Mojo Scheme URL, then it is not |
| // modified as it will be handled internally. |
| if (is_internal_scheme_url) { |
| return url; |
| } |
| // Resolve the url within the context of the library's URL. |
| Dart_Handle builtin_lib = |
| Builtin::GetLibrary(Builtin::kBuiltinLibrary); |
| return ResolveUri(library_url, url, builtin_lib); |
| } |
| |
| Dart_Handle builtin_lib = |
| Builtin::GetLibrary(Builtin::kBuiltinLibrary); |
| // Handle 'import' or 'part' requests for all other URIs. Call dart code to |
| // read the source code asynchronously. |
| return LoadDataAsync_Invoke( |
| Dart_NewInteger(tag), url, library_url, builtin_lib, Dart_Null()); |
| } |
| |
| static Dart_Handle SetWorkingDirectory(Dart_Handle builtin_lib) { |
| base::FilePath current_dir; |
| PathService::Get(base::DIR_CURRENT, ¤t_dir); |
| |
| const int kNumArgs = 1; |
| Dart_Handle dart_args[kNumArgs]; |
| std::string current_dir_string = current_dir.AsUTF8Unsafe(); |
| dart_args[0] = Dart_NewStringFromUTF8( |
| reinterpret_cast<const uint8_t*>(current_dir_string.data()), |
| current_dir_string.length()); |
| return Dart_Invoke(builtin_lib, |
| Dart_NewStringFromCString("_setWorkingDirectory"), |
| kNumArgs, |
| dart_args); |
| } |
| |
| static Dart_Handle PrepareScriptForLoading(const std::string& package_root, |
| Dart_Handle builtin_lib) { |
| // First ensure all required libraries are available. |
| Dart_Handle url = Dart_NewStringFromCString(kInternalLibURL); |
| DART_CHECK_VALID(url); |
| Dart_Handle internal_lib = Dart_LookupLibrary(url); |
| DART_CHECK_VALID(internal_lib); |
| url = Dart_NewStringFromCString(kCoreLibURL); |
| DART_CHECK_VALID(url); |
| Dart_Handle core_lib = Dart_LookupLibrary(url); |
| DART_CHECK_VALID(internal_lib); |
| url = Dart_NewStringFromCString(kAsyncLibURL); |
| DART_CHECK_VALID(url); |
| Dart_Handle async_lib = Dart_LookupLibrary(url); |
| DART_CHECK_VALID(async_lib); |
| url = Dart_NewStringFromCString(kIsolateLibURL); |
| DART_CHECK_VALID(url); |
| Dart_Handle isolate_lib = Dart_LookupLibrary(url); |
| DART_CHECK_VALID(isolate_lib); |
| Dart_Handle mojo_internal_lib = |
| Builtin::GetLibrary(Builtin::kMojoInternalLibrary); |
| DART_CHECK_VALID(mojo_internal_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); |
| DART_CHECK_VALID(result); |
| |
| // Import dart:_internal into dart:mojo.builtin for setting up hooks. |
| result = Dart_LibraryImportLibrary(builtin_lib, internal_lib, Dart_Null()); |
| DART_CHECK_VALID(result); |
| |
| // Setup the internal library's 'internalPrint' function. |
| Dart_Handle print = Dart_Invoke(builtin_lib, |
| Dart_NewStringFromCString("_getPrintClosure"), |
| 0, |
| nullptr); |
| DART_CHECK_VALID(print); |
| result = Dart_SetField(internal_lib, |
| Dart_NewStringFromCString("_printClosure"), |
| print); |
| DART_CHECK_VALID(result); |
| |
| DART_CHECK_VALID(Dart_Invoke( |
| builtin_lib, Dart_NewStringFromCString("_setupHooks"), 0, nullptr)); |
| DART_CHECK_VALID(Dart_Invoke( |
| isolate_lib, Dart_NewStringFromCString("_setupHooks"), 0, nullptr)); |
| |
| // Setup the 'scheduleImmediate' closure. |
| Dart_Handle schedule_immediate_closure = Dart_Invoke( |
| isolate_lib, |
| Dart_NewStringFromCString("_getIsolateScheduleImmediateClosure"), |
| 0, |
| nullptr); |
| Dart_Handle schedule_args[1]; |
| schedule_args[0] = schedule_immediate_closure; |
| result = Dart_Invoke( |
| async_lib, |
| Dart_NewStringFromCString("_setScheduleImmediateClosure"), |
| 1, |
| schedule_args); |
| DART_CHECK_VALID(result); |
| |
| // Set current working directory. |
| result = SetWorkingDirectory(builtin_lib); |
| if (Dart_IsError(result)) { |
| return result; |
| } |
| |
| // Set up package root. |
| result = Dart_NewStringFromUTF8( |
| reinterpret_cast<const uint8_t*>(package_root.c_str()), |
| package_root.length()); |
| DART_CHECK_VALID(result); |
| |
| const int kNumArgs = 1; |
| Dart_Handle dart_args[kNumArgs]; |
| dart_args[0] = result; |
| result = Dart_Invoke(builtin_lib, |
| Dart_NewStringFromCString("_setPackageRoot"), |
| kNumArgs, |
| dart_args); |
| DART_CHECK_VALID(result); |
| |
| // Setup the uriBase with the base uri of the mojo app. |
| Dart_Handle uri_base = Dart_Invoke( |
| builtin_lib, |
| Dart_NewStringFromCString("_getUriBaseClosure"), |
| 0, |
| nullptr); |
| DART_CHECK_VALID(uri_base); |
| result = Dart_SetField(core_lib, |
| Dart_NewStringFromCString("_uriBaseClosure"), |
| uri_base); |
| DART_CHECK_VALID(result); |
| |
| return result; |
| } |
| |
| static Dart_Isolate CreateServiceIsolateHelper(const char* script_uri, |
| char** error) { |
| // TODO(johnmccutchan): Add support the service isolate. |
| // No callbacks for service isolate. |
| IsolateCallbacks callbacks; |
| IsolateData* isolate_data = |
| new IsolateData(nullptr, false, callbacks, "", "", ""); |
| Dart_Isolate isolate = Dart_CreateIsolate(script_uri, |
| "main", |
| isolate_snapshot_buffer, |
| isolate_data, |
| error); |
| if (isolate == nullptr) { |
| delete isolate_data; |
| return nullptr; |
| } |
| return isolate; |
| } |
| |
| static Dart_Isolate CreateIsolateHelper(void* dart_app, |
| bool strict_compilation, |
| IsolateCallbacks callbacks, |
| const std::string& script, |
| const std::string& script_uri, |
| const std::string& package_root, |
| char** error) { |
| IsolateData* isolate_data = new IsolateData( |
| dart_app, |
| strict_compilation, |
| callbacks, |
| script, |
| script_uri, |
| package_root); |
| Dart_Isolate isolate = Dart_CreateIsolate( |
| script_uri.c_str(), "main", isolate_snapshot_buffer, isolate_data, error); |
| if (isolate == nullptr) { |
| delete isolate_data; |
| return nullptr; |
| } |
| |
| DPCHECK(!Dart_IsServiceIsolate(isolate)); |
| Dart_EnterScope(); |
| |
| Dart_IsolateSetStrictCompilation(strict_compilation); |
| |
| // Setup the native resolvers for the builtin libraries as they are not set |
| // up when the snapshot is read. |
| CHECK(isolate_snapshot_buffer != nullptr); |
| Builtin::PrepareLibrary(Builtin::kBuiltinLibrary); |
| Builtin::PrepareLibrary(Builtin::kMojoInternalLibrary); |
| |
| if (!callbacks.create.is_null()) { |
| callbacks.create.Run(script_uri.c_str(), |
| "main", |
| package_root.c_str(), |
| isolate_data, |
| error); |
| } |
| |
| // Set up the library tag handler for this isolate. |
| Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler); |
| DART_CHECK_VALID(result); |
| |
| // Prepare builtin and its dependent libraries for use to resolve URIs. |
| // The builtin library is part of the snapshot and is already available. |
| Dart_Handle builtin_lib = |
| Builtin::GetLibrary(Builtin::kBuiltinLibrary); |
| DART_CHECK_VALID(builtin_lib); |
| |
| result = PrepareScriptForLoading(package_root, builtin_lib); |
| DART_CHECK_VALID(result); |
| |
| Dart_Handle uri = Dart_NewStringFromUTF8( |
| reinterpret_cast<const uint8_t*>(script_uri.c_str()), |
| script_uri.length()); |
| DART_CHECK_VALID(uri); |
| |
| const void* data = static_cast<const void*>(script.data()); |
| Dart_Handle script_source = Dart_NewExternalTypedData( |
| Dart_TypedData_kUint8, |
| const_cast<void*>(data), |
| script.length()); |
| DART_CHECK_VALID(script_source); |
| |
| result = LoadDataAsync_Invoke( |
| Dart_Null(), uri, Dart_Null(), builtin_lib, script_source); |
| DART_CHECK_VALID(result); |
| |
| // Run event-loop and wait for script loading to complete. |
| result = Dart_RunLoop(); |
| ReportScriptError(result); |
| |
| // Make the isolate runnable so that it is ready to handle messages. |
| Dart_ExitScope(); |
| Dart_ExitIsolate(); |
| bool retval = Dart_IsolateMakeRunnable(isolate); |
| if (!retval) { |
| *error = strdup("Invalid isolate state - Unable to make it runnable"); |
| Dart_EnterIsolate(isolate); |
| Dart_ShutdownIsolate(); |
| return nullptr; |
| } |
| |
| return isolate; |
| } |
| |
| static Dart_Isolate IsolateCreateCallback(const char* script_uri, |
| const char* main, |
| const char* package_root, |
| void* callback_data, |
| char** error) { |
| IsolateData* parent_isolate_data = |
| reinterpret_cast<IsolateData*>(callback_data); |
| std::string script_uri_string; |
| std::string package_root_string; |
| |
| if (IsServiceIsolateURL(script_uri)) { |
| return CreateServiceIsolateHelper(script_uri, error); |
| } |
| if (script_uri == nullptr) { |
| if (callback_data == nullptr) { |
| *error = strdup("Invalid 'callback_data' - Unable to spawn new isolate"); |
| return nullptr; |
| } |
| script_uri_string = parent_isolate_data->script_uri; |
| } else { |
| script_uri_string = std::string(script_uri); |
| } |
| if (package_root == nullptr) { |
| package_root_string = parent_isolate_data->package_root; |
| } else { |
| package_root_string = std::string(package_root); |
| } |
| return CreateIsolateHelper(parent_isolate_data->app, |
| parent_isolate_data->strict_compilation, |
| parent_isolate_data->callbacks, |
| parent_isolate_data->script, |
| script_uri_string, |
| package_root_string, |
| error); |
| } |
| |
| static void IsolateShutdownCallback(void* callback_data) { |
| IsolateData* isolate_data = reinterpret_cast<IsolateData*>(callback_data); |
| if (!isolate_data->callbacks.shutdown.is_null()) { |
| isolate_data->callbacks.shutdown.Run(callback_data); |
| } |
| delete isolate_data; |
| } |
| |
| static void UnhandledExceptionCallback(Dart_Handle error) { |
| Dart_Isolate isolate = Dart_CurrentIsolate(); |
| void* data = Dart_IsolateData(isolate); |
| IsolateData* isolate_data = reinterpret_cast<IsolateData*>(data); |
| if (!isolate_data->callbacks.exception.is_null()) { |
| // TODO(zra): Instead of passing an error handle, it may make life easier |
| // for clients if we pass any error string here instead. |
| isolate_data->callbacks.exception.Run(error); |
| } |
| |
| // Close handles generated by the isolate. |
| std::set<MojoHandle>& handles = isolate_data->unclosed_handles; |
| for (auto it = handles.begin(); it != handles.end(); ++it) { |
| MojoClose((*it)); |
| } |
| handles.clear(); |
| } |
| |
| |
| bool DartController::initialized_ = false; |
| Dart_Isolate DartController::root_isolate_ = nullptr; |
| bool DartController::strict_compilation_ = false; |
| |
| void DartController::InitVmIfNeeded(Dart_EntropySource entropy, |
| const char** arguments, |
| int arguments_count) { |
| // TODO(zra): If runDartScript can be called from multiple threads |
| // concurrently, then initialized_ will need to be protected by a lock. |
| if (initialized_) { |
| return; |
| } |
| |
| const int kNumArgs = arguments_count + 1; |
| const char* args[kNumArgs]; |
| |
| // TODO(zra): Fix Dart VM Shutdown race. |
| // There is a bug in Dart VM shutdown which causes its thread pool threads |
| // to potentially fail to exit when the rest of the VM is going down. This |
| // results in a segfault if they begin running again after the Dart |
| // embedder has been unloaded. Setting this flag to 0 ensures that these |
| // threads sleep forever instead of waking up and trying to run code |
| // that isn't there anymore. |
| args[0] = "--worker-timeout-millis=0"; |
| |
| for (int i = 0; i < arguments_count; ++i) { |
| args[i + 1] = arguments[i]; |
| } |
| |
| bool result = Dart_SetVMFlags(kNumArgs, args); |
| CHECK(result); |
| |
| result = Dart_Initialize(vm_isolate_snapshot_buffer, |
| IsolateCreateCallback, |
| nullptr, // Isolate interrupt callback. |
| UnhandledExceptionCallback, |
| IsolateShutdownCallback, |
| // File IO callbacks. |
| nullptr, nullptr, nullptr, nullptr, |
| entropy); |
| CHECK(result); |
| initialized_ = true; |
| } |
| |
| bool DartController::RunSingleDartScript(const DartControllerConfig& config) { |
| InitVmIfNeeded(config.entropy, |
| config.arguments, |
| config.arguments_count); |
| Dart_Isolate isolate = CreateIsolateHelper(config.application_data, |
| config.strict_compilation, |
| config.callbacks, |
| config.script, |
| config.script_uri, |
| config.package_root, |
| config.error); |
| if (isolate == nullptr) { |
| return false; |
| } |
| |
| Dart_EnterIsolate(isolate); |
| Dart_Handle result; |
| Dart_EnterScope(); |
| |
| // Start the MojoHandleWatcher. |
| Dart_Handle mojo_internal_lib = |
| Builtin::GetLibrary(Builtin::kMojoInternalLibrary); |
| DART_CHECK_VALID(mojo_internal_lib); |
| Dart_Handle handle_watcher_type = |
| Dart_GetType(mojo_internal_lib, |
| Dart_NewStringFromCString("MojoHandleWatcher"), 0, nullptr); |
| DART_CHECK_VALID(handle_watcher_type); |
| result = Dart_Invoke( |
| handle_watcher_type, |
| Dart_NewStringFromCString("_start"), |
| 0, |
| nullptr); |
| DART_CHECK_VALID(result); |
| |
| // RunLoop until the handle watcher isolate is spun-up. |
| result = Dart_RunLoop(); |
| DART_CHECK_VALID(result); |
| |
| // Load the root library into the builtin library so that main can be found. |
| Dart_Handle builtin_lib = |
| Builtin::GetLibrary(Builtin::kBuiltinLibrary); |
| DART_CHECK_VALID(builtin_lib); |
| Dart_Handle root_lib = Dart_RootLibrary(); |
| DART_CHECK_VALID(root_lib); |
| result = Dart_LibraryImportLibrary(builtin_lib, root_lib, Dart_Null()); |
| DART_CHECK_VALID(result); |
| |
| if (config.compile_all) { |
| result = Dart_CompileAll(); |
| DART_CHECK_VALID(result); |
| } |
| |
| Dart_Handle main_closure = Dart_Invoke( |
| builtin_lib, |
| Dart_NewStringFromCString("_getMainClosure"), |
| 0, |
| nullptr); |
| DART_CHECK_VALID(main_closure); |
| |
| // Call _startIsolate in the isolate library to enable dispatching the |
| // initial startup message. |
| const intptr_t kNumIsolateArgs = 2; |
| Dart_Handle isolate_args[kNumIsolateArgs]; |
| isolate_args[0] = main_closure; // entryPoint |
| isolate_args[1] = Dart_NewList(2); // args |
| DART_CHECK_VALID(isolate_args[1]); |
| |
| Dart_Handle script_uri = Dart_NewStringFromUTF8( |
| reinterpret_cast<const uint8_t*>(config.script_uri.data()), |
| config.script_uri.length()); |
| Dart_ListSetAt(isolate_args[1], 0, Dart_NewInteger(config.handle)); |
| Dart_ListSetAt(isolate_args[1], 1, script_uri); |
| |
| Dart_Handle isolate_lib = |
| Dart_LookupLibrary(Dart_NewStringFromCString(kIsolateLibURL)); |
| DART_CHECK_VALID(isolate_lib); |
| |
| result = Dart_Invoke(isolate_lib, |
| Dart_NewStringFromCString("_startMainIsolate"), |
| kNumIsolateArgs, |
| isolate_args); |
| DART_CHECK_VALID(result); |
| |
| result = Dart_RunLoop(); |
| DART_CHECK_VALID(result); |
| |
| // Stop the MojoHandleWatcher. |
| result = Dart_Invoke( |
| handle_watcher_type, |
| Dart_NewStringFromCString("_stop"), |
| 0, |
| nullptr); |
| DART_CHECK_VALID(result); |
| |
| result = Dart_RunLoop(); |
| DART_CHECK_VALID(result); |
| |
| Dart_ExitScope(); |
| Dart_ShutdownIsolate(); |
| Dart_Cleanup(); |
| return true; |
| } |
| |
| static bool generateEntropy(uint8_t* buffer, intptr_t length) { |
| crypto::RandBytes(reinterpret_cast<void*>(buffer), length); |
| return true; |
| } |
| |
| bool DartController::Initialize(bool strict_compilation) { |
| char* error; |
| strict_compilation_ = strict_compilation; |
| |
| // No callbacks for root isolate. |
| IsolateCallbacks callbacks; |
| InitVmIfNeeded(generateEntropy, nullptr, 0); |
| root_isolate_ = CreateIsolateHelper( |
| nullptr, false, callbacks, "", "", "", &error); |
| if (root_isolate_ == nullptr) { |
| LOG(ERROR) << error; |
| Dart_Cleanup(); |
| initialized_ = false; |
| return false; |
| } |
| |
| Dart_EnterIsolate(root_isolate_); |
| Dart_Handle result; |
| Dart_EnterScope(); |
| |
| // Start the MojoHandleWatcher. |
| Dart_Handle mojo_internal_lib = |
| Builtin::GetLibrary(Builtin::kMojoInternalLibrary); |
| DART_CHECK_VALID(mojo_internal_lib); |
| Dart_Handle handle_watcher_type = |
| Dart_GetType(mojo_internal_lib, |
| Dart_NewStringFromCString("MojoHandleWatcher"), 0, nullptr); |
| DART_CHECK_VALID(handle_watcher_type); |
| result = Dart_Invoke( |
| handle_watcher_type, |
| Dart_NewStringFromCString("_start"), |
| 0, |
| nullptr); |
| DART_CHECK_VALID(result); |
| |
| // RunLoop until the handle watcher isolate is spun-up. |
| result = Dart_RunLoop(); |
| DART_CHECK_VALID(result); |
| |
| Dart_ExitScope(); |
| Dart_ExitIsolate(); |
| return true; |
| } |
| |
| bool DartController::RunDartScript(const DartControllerConfig& config) { |
| CHECK(root_isolate_ != nullptr); |
| const bool strict = strict_compilation_ || config.strict_compilation; |
| Dart_Isolate isolate = CreateIsolateHelper( |
| config.application_data, strict, config.callbacks, config.script, |
| config.script_uri, config.package_root, config.error); |
| if (isolate == nullptr) { |
| return false; |
| } |
| |
| Dart_EnterIsolate(isolate); |
| Dart_Handle result; |
| Dart_EnterScope(); |
| |
| // Load the root library into the builtin library so that main can be found. |
| Dart_Handle builtin_lib = |
| Builtin::GetLibrary(Builtin::kBuiltinLibrary); |
| DART_CHECK_VALID(builtin_lib); |
| Dart_Handle root_lib = Dart_RootLibrary(); |
| DART_CHECK_VALID(root_lib); |
| result = Dart_LibraryImportLibrary(builtin_lib, root_lib, Dart_Null()); |
| DART_CHECK_VALID(result); |
| |
| if (config.compile_all) { |
| result = Dart_CompileAll(); |
| DART_CHECK_VALID(result); |
| } |
| |
| Dart_Handle main_closure = Dart_Invoke( |
| builtin_lib, |
| Dart_NewStringFromCString("_getMainClosure"), |
| 0, |
| nullptr); |
| DART_CHECK_VALID(main_closure); |
| |
| // Call _startIsolate in the isolate library to enable dispatching the |
| // initial startup message. |
| const intptr_t kNumIsolateArgs = 2; |
| Dart_Handle isolate_args[kNumIsolateArgs]; |
| isolate_args[0] = main_closure; // entryPoint |
| isolate_args[1] = Dart_NewList(2); // args |
| DART_CHECK_VALID(isolate_args[1]); |
| |
| Dart_Handle script_uri = Dart_NewStringFromUTF8( |
| reinterpret_cast<const uint8_t*>(config.script_uri.data()), |
| config.script_uri.length()); |
| Dart_ListSetAt(isolate_args[1], 0, Dart_NewInteger(config.handle)); |
| Dart_ListSetAt(isolate_args[1], 1, script_uri); |
| |
| Dart_Handle isolate_lib = |
| Dart_LookupLibrary(Dart_NewStringFromCString(kIsolateLibURL)); |
| DART_CHECK_VALID(isolate_lib); |
| |
| result = Dart_Invoke(isolate_lib, |
| Dart_NewStringFromCString("_startMainIsolate"), |
| kNumIsolateArgs, |
| isolate_args); |
| DART_CHECK_VALID(result); |
| |
| // Run main until completion. |
| result = Dart_RunLoop(); |
| ReportScriptError(result); |
| |
| Dart_ExitScope(); |
| Dart_ShutdownIsolate(); |
| return true; |
| } |
| |
| void DartController::Shutdown() { |
| CHECK(root_isolate_ != nullptr); |
| Dart_EnterIsolate(root_isolate_); |
| Dart_Handle result; |
| Dart_EnterScope(); |
| |
| // Stop the MojoHandleWatcher. |
| Dart_Handle mojo_internal_lib = |
| Builtin::GetLibrary(Builtin::kMojoInternalLibrary); |
| DART_CHECK_VALID(mojo_internal_lib); |
| Dart_Handle handle_watcher_type = |
| Dart_GetType(mojo_internal_lib, |
| Dart_NewStringFromCString("MojoHandleWatcher"), 0, nullptr); |
| DART_CHECK_VALID(handle_watcher_type); |
| result = Dart_Invoke( |
| handle_watcher_type, |
| Dart_NewStringFromCString("_stop"), |
| 0, |
| nullptr); |
| DART_CHECK_VALID(result); |
| |
| result = Dart_RunLoop(); |
| DART_CHECK_VALID(result); |
| |
| Dart_ExitScope(); |
| Dart_ShutdownIsolate(); |
| Dart_Cleanup(); |
| root_isolate_ = nullptr; |
| initialized_ = false; |
| } |
| |
| } // namespace apps |
| } // namespace mojo |