// 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. #include "vm/kernel_isolate.h" #include "bin/dartutils.h" #include "include/dart_native_api.h" #include "vm/compiler/jit/compiler.h" #include "vm/dart_api_impl.h" #include "vm/dart_entry.h" #include "vm/flags.h" #include "vm/isolate.h" #include "vm/lockers.h" #include "vm/message.h" #include "vm/message_handler.h" #include "vm/native_arguments.h" #include "vm/native_entry.h" #include "vm/object.h" #include "vm/object_store.h" #include "vm/port.h" #include "vm/service.h" #include "vm/symbols.h" #include "vm/thread_pool.h" #include "vm/timeline.h" namespace dart { #define Z (T->zone()) DEFINE_FLAG(bool, trace_kernel, false, "Trace Kernel service requests."); DEFINE_FLAG(bool, suppress_fe_warnings, false, "Suppress warnings from the FE."); DEFINE_FLAG(charp, kernel_multiroot_filepaths, NULL, "Comma-separated list of file paths that should be treated as roots" " by frontend compiler."); DEFINE_FLAG(charp, kernel_multiroot_scheme, NULL, "URI scheme that replaces filepaths prefixes specified" " by kernel_multiroot_filepaths option"); const char* KernelIsolate::kName = DART_KERNEL_ISOLATE_NAME; // Tags used to indicate different requests to the dart frontend. // // Current tags include the following: // 0 - Perform normal compilation. // 1 - Update in-memory file system with in-memory sources (used by tests). // 2 - Accept last compilation result. // 3 - APP JIT snapshot training run for kernel_service. const int KernelIsolate::kCompileTag = 0; const int KernelIsolate::kUpdateSourcesTag = 1; const int KernelIsolate::kAcceptTag = 2; const int KernelIsolate::kTrainTag = 3; const int KernelIsolate::kCompileExpressionTag = 4; const int KernelIsolate::kListDependenciesTag = 5; const int KernelIsolate::kNotifyIsolateShutdown = 6; Dart_IsolateCreateCallback KernelIsolate::create_callback_ = NULL; Monitor* KernelIsolate::monitor_ = new Monitor(); Isolate* KernelIsolate::isolate_ = NULL; bool KernelIsolate::initializing_ = true; Dart_Port KernelIsolate::kernel_port_ = ILLEGAL_PORT; class RunKernelTask : public ThreadPool::Task { public: virtual void Run() { ASSERT(Isolate::Current() == NULL); #ifdef SUPPORT_TIMELINE TimelineDurationScope tds(Timeline::GetVMStream(), "KernelIsolateStartup"); #endif // SUPPORT_TIMELINE char* error = NULL; Isolate* isolate = NULL; Dart_IsolateCreateCallback create_callback = KernelIsolate::create_callback(); if (create_callback == NULL) { KernelIsolate::FinishedInitializing(); return; } // Note: these flags must match those passed to the VM during // the app-jit training run (see //utils/kernel-service/BUILD.gn). Dart_IsolateFlags api_flags; Isolate::FlagsInitialize(&api_flags); api_flags.enable_asserts = false; api_flags.unsafe_trust_strong_mode_types = false; #if !defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_DBC) api_flags.use_field_guards = true; #endif #if !defined(DART_PRECOMPILER) api_flags.use_osr = true; #endif isolate = reinterpret_cast(create_callback( KernelIsolate::kName, NULL, NULL, NULL, &api_flags, NULL, &error)); if (isolate == NULL) { if (FLAG_trace_kernel) { OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Isolate creation error: %s\n", error); } free(error); error = NULL; KernelIsolate::SetKernelIsolate(NULL); KernelIsolate::FinishedInitializing(); return; } bool got_unwind; { ASSERT(Isolate::Current() == NULL); StartIsolateScope start_scope(isolate); got_unwind = RunMain(isolate); } KernelIsolate::FinishedInitializing(); if (got_unwind) { ShutdownIsolate(reinterpret_cast(isolate)); return; } // isolate_ was set as side effect of create callback. ASSERT(KernelIsolate::IsKernelIsolate(isolate)); isolate->message_handler()->Run(Dart::thread_pool(), NULL, ShutdownIsolate, reinterpret_cast(isolate)); } protected: static void ShutdownIsolate(uword parameter) { if (FLAG_trace_kernel) { OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": ShutdownIsolate\n"); } Isolate* I = reinterpret_cast(parameter); I->WaitForOutstandingSpawns(); { // Print the error if there is one. This may execute dart code to // print the exception object, so we need to use a StartIsolateScope. ASSERT(Isolate::Current() == NULL); StartIsolateScope start_scope(I); Thread* T = Thread::Current(); ASSERT(I == T->isolate()); StackZone zone(T); HandleScope handle_scope(T); Error& error = Error::Handle(Z); error = T->sticky_error(); if (!error.IsNull() && !error.IsUnwindError()) { OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Error: %s\n", error.ToErrorCString()); } error = I->sticky_error(); if (!error.IsNull() && !error.IsUnwindError()) { OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Error: %s\n", error.ToErrorCString()); } Dart::RunShutdownCallback(); } ASSERT(KernelIsolate::IsKernelIsolate(I)); KernelIsolate::SetLoadPort(ILLEGAL_PORT); // Shut the isolate down. Dart::ShutdownIsolate(I); if (FLAG_trace_kernel) { OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Shutdown.\n"); } } bool RunMain(Isolate* I) { Thread* T = Thread::Current(); ASSERT(I == T->isolate()); StackZone zone(T); HANDLESCOPE(T); // Invoke main which will return the port to which load requests are sent. const Library& root_library = Library::Handle(Z, I->object_store()->root_library()); if (root_library.IsNull()) { OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Embedder did not install a script."); // Kernel isolate is not supported by embedder. return false; } ASSERT(!root_library.IsNull()); const String& entry_name = String::Handle(Z, String::New("main")); ASSERT(!entry_name.IsNull()); const Function& entry = Function::Handle( Z, root_library.LookupFunctionAllowPrivate(entry_name)); if (entry.IsNull()) { // Kernel isolate is not supported by embedder. OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Embedder did not provide a main function."); return false; } ASSERT(!entry.IsNull()); const Object& result = Object::Handle( Z, DartEntry::InvokeFunction(entry, Object::empty_array())); ASSERT(!result.IsNull()); if (result.IsError()) { // Kernel isolate did not initialize properly. if (FLAG_trace_kernel) { const Error& error = Error::Cast(result); OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": Calling main resulted in an error: %s", error.ToErrorCString()); } if (result.IsUnwindError()) { return true; } return false; } ASSERT(result.IsReceivePort()); const ReceivePort& rp = ReceivePort::Cast(result); KernelIsolate::SetLoadPort(rp.Id()); return false; } }; void KernelIsolate::Run() { MonitorLocker ml(monitor_); initializing_ = true; // Grab the isolate create callback here to avoid race conditions with tests // that change this after Dart_Initialize returns. create_callback_ = Isolate::CreateCallback(); Dart::thread_pool()->Run(new RunKernelTask()); } void KernelIsolate::Shutdown() { MonitorLocker ml(monitor_); while (isolate_ != NULL) { Isolate::KillIfExists(isolate_, Isolate::kInternalKillMsg); ml.Wait(); } } void KernelIsolate::InitCallback(Isolate* I) { Thread* T = Thread::Current(); ASSERT(I == T->isolate()); ASSERT(I != NULL); if (!NameEquals(I->name())) { // Not kernel isolate. return; } ASSERT(!Exists()); if (FLAG_trace_kernel) { OS::PrintErr(DART_KERNEL_ISOLATE_NAME ": InitCallback for %s.\n", I->name()); } SetKernelIsolate(I); } bool KernelIsolate::IsKernelIsolate(const Isolate* isolate) { MonitorLocker ml(monitor_); return isolate == isolate_; } bool KernelIsolate::IsRunning() { MonitorLocker ml(monitor_); return (kernel_port_ != ILLEGAL_PORT) && (isolate_ != NULL); } bool KernelIsolate::NameEquals(const char* name) { ASSERT(name != NULL); return (strcmp(name, DART_KERNEL_ISOLATE_NAME) == 0); } bool KernelIsolate::Exists() { MonitorLocker ml(monitor_); return isolate_ != NULL; } void KernelIsolate::SetKernelIsolate(Isolate* isolate) { MonitorLocker ml(monitor_); if (isolate != nullptr) { isolate->set_is_kernel_isolate(true); } isolate_ = isolate; ml.NotifyAll(); } void KernelIsolate::SetLoadPort(Dart_Port port) { MonitorLocker ml(monitor_); kernel_port_ = port; ml.NotifyAll(); } void KernelIsolate::FinishedInitializing() { MonitorLocker ml(monitor_); initializing_ = false; ml.NotifyAll(); } Dart_Port KernelIsolate::WaitForKernelPort() { VMTagScope tagScope(Thread::Current(), VMTag::kLoadWaitTagId); MonitorLocker ml(monitor_); while (initializing_ && (kernel_port_ == ILLEGAL_PORT)) { ml.Wait(); } return kernel_port_; } static Dart_CObject BuildFilesPairs(int source_files_count, Dart_SourceFile source_files[]) { Dart_CObject files; files.type = Dart_CObject_kArray; files.value.as_array.length = source_files_count * 2; // typedef Dart_CObject* Dart_CObjectPtr; Dart_CObject** fileNamePairs = new Dart_CObject*[source_files_count * 2]; for (int i = 0; i < source_files_count; i++) { Dart_CObject* source_uri = new Dart_CObject(); source_uri->type = Dart_CObject_kString; source_uri->value.as_string = const_cast(source_files[i].uri); fileNamePairs[i * 2] = source_uri; Dart_CObject* source_code = new Dart_CObject(); if (source_files[i].source != NULL) { source_code->type = Dart_CObject_kTypedData; source_code->value.as_typed_data.type = Dart_TypedData_kUint8; source_code->value.as_typed_data.length = strlen(source_files[i].source); source_code->value.as_typed_data.values = reinterpret_cast(const_cast(source_files[i].source)); } else { source_code->type = Dart_CObject_kNull; } fileNamePairs[(i * 2) + 1] = source_code; } files.value.as_array.values = fileNamePairs; return files; } static void ReleaseFilesPairs(const Dart_CObject& files) { for (intptr_t i = 0; i < files.value.as_array.length; i++) { delete files.value.as_array.values[i]; } delete[] files.value.as_array.values; } static void PassThroughFinalizer(void* isolate_callback_data, Dart_WeakPersistentHandle handle, void* peer) {} MallocGrowableArray* KernelIsolate::experimental_flags_ = new MallocGrowableArray(); void KernelIsolate::AddExperimentalFlag(const char* value) { experimental_flags_->Add(strdup(value)); } DEFINE_OPTION_HANDLER(KernelIsolate::AddExperimentalFlag, enable_experiment, "Comma separated list of experimental features."); class KernelCompilationRequest : public ValueObject { public: KernelCompilationRequest() : monitor_(new Monitor()), port_(Dart_NewNativePort("kernel-compilation-port", &HandleResponse, false)), next_(NULL), prev_(NULL) { ASSERT(port_ != ILLEGAL_PORT); RegisterRequest(this); result_.status = Dart_KernelCompilationStatus_Unknown; result_.error = NULL; result_.kernel = NULL; result_.kernel_size = 0; } ~KernelCompilationRequest() { UnregisterRequest(this); Dart_CloseNativePort(port_); delete monitor_; } Dart_KernelCompilationResult SendAndWaitForResponse( Dart_Port kernel_port, const char* expression, const Array& definitions, const Array& type_definitions, char const* library_uri, char const* klass, bool is_static, const MallocGrowableArray* experimental_flags) { Thread* thread = Thread::Current(); TransitionNativeToVM transition(thread); Dart_CObject tag; tag.type = Dart_CObject_kInt32; tag.value.as_int32 = KernelIsolate::kCompileExpressionTag; Dart_CObject send_port; send_port.type = Dart_CObject_kSendPort; send_port.value.as_send_port.id = port_; send_port.value.as_send_port.origin_id = ILLEGAL_PORT; Dart_CObject expression_object; expression_object.type = Dart_CObject_kString; expression_object.value.as_string = const_cast(expression); Dart_CObject definitions_object; intptr_t num_definitions = definitions.Length(); definitions_object.type = Dart_CObject_kArray; definitions_object.value.as_array.length = num_definitions; Dart_CObject** definitions_array = new Dart_CObject*[num_definitions]; for (intptr_t i = 0; i < num_definitions; ++i) { definitions_array[i] = new Dart_CObject; definitions_array[i]->type = Dart_CObject_kString; definitions_array[i]->value.as_string = const_cast( String::CheckedHandle(thread->zone(), definitions.At(i)).ToCString()); } definitions_object.value.as_array.values = definitions_array; Dart_CObject type_definitions_object; intptr_t num_type_definitions = type_definitions.Length(); type_definitions_object.type = Dart_CObject_kArray; type_definitions_object.value.as_array.length = num_type_definitions; Dart_CObject** type_definitions_array = new Dart_CObject*[num_type_definitions]; for (intptr_t i = 0; i < num_type_definitions; ++i) { type_definitions_array[i] = new Dart_CObject; type_definitions_array[i]->type = Dart_CObject_kString; type_definitions_array[i]->value.as_string = const_cast( String::CheckedHandle(thread->zone(), type_definitions.At(i)) .ToCString()); } type_definitions_object.value.as_array.values = type_definitions_array; Dart_CObject library_uri_object; library_uri_object.type = Dart_CObject_kString; library_uri_object.value.as_string = const_cast(library_uri); Dart_CObject class_object; if (klass != NULL) { class_object.type = Dart_CObject_kString; class_object.value.as_string = const_cast(klass); } else { class_object.type = Dart_CObject_kNull; } Dart_CObject is_static_object; is_static_object.type = Dart_CObject_kBool; is_static_object.value.as_bool = is_static; Isolate* isolate = Thread::Current() != NULL ? Thread::Current()->isolate() : NULL; ASSERT(isolate != NULL); Dart_CObject isolate_id; isolate_id.type = Dart_CObject_kInt64; isolate_id.value.as_int64 = isolate != NULL ? static_cast(isolate->main_port()) : 0; Dart_CObject suppress_warnings; suppress_warnings.type = Dart_CObject_kBool; suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings; intptr_t num_experimental_flags = experimental_flags->length(); Dart_CObject** experimental_flags_array = new Dart_CObject*[num_experimental_flags]; for (intptr_t i = 0; i < num_experimental_flags; ++i) { experimental_flags_array[i] = new Dart_CObject; experimental_flags_array[i]->type = Dart_CObject_kString; experimental_flags_array[i]->value.as_string = (*experimental_flags)[i]; } Dart_CObject experimental_flags_object; experimental_flags_object.type = Dart_CObject_kArray; experimental_flags_object.value.as_array.values = experimental_flags_array; experimental_flags_object.value.as_array.length = num_experimental_flags; Dart_CObject message; message.type = Dart_CObject_kArray; Dart_CObject* message_arr[] = {&tag, &send_port, &isolate_id, &expression_object, &definitions_object, &type_definitions_object, &library_uri_object, &class_object, &is_static_object, &suppress_warnings, &experimental_flags_object}; message.value.as_array.values = message_arr; message.value.as_array.length = ARRAY_SIZE(message_arr); { TransitionVMToNative transition(thread); // Send the message. Dart_PostCObject(kernel_port, &message); // Wait for reply to arrive. VMTagScope tagScope(thread, VMTag::kLoadWaitTagId); MonitorLocker ml(monitor_); while (result_.status == Dart_KernelCompilationStatus_Unknown) { ml.Wait(); } } for (intptr_t i = 0; i < num_definitions; ++i) { delete definitions_array[i]; } delete[] definitions_array; for (intptr_t i = 0; i < num_type_definitions; ++i) { delete type_definitions_array[i]; } delete[] type_definitions_array; for (intptr_t i = 0; i < num_experimental_flags; ++i) { delete experimental_flags_array[i]; } delete[] experimental_flags_array; return result_; } Dart_KernelCompilationResult SendAndWaitForResponse( int request_tag, Dart_Port kernel_port, const char* script_uri, const uint8_t* platform_kernel, intptr_t platform_kernel_size, int source_files_count, Dart_SourceFile source_files[], bool incremental_compile, const char* package_config, const char* multiroot_filepaths, const char* multiroot_scheme, const MallocGrowableArray* experimental_flags) { // Build the [null, send_port, script_uri, platform_kernel, // incremental_compile, isolate_id, [files]] message for the Kernel isolate. // tag is used to specify which operation the frontend should perform. Dart_CObject tag; tag.type = Dart_CObject_kInt32; tag.value.as_int32 = request_tag; Dart_CObject send_port; send_port.type = Dart_CObject_kSendPort; send_port.value.as_send_port.id = port_; send_port.value.as_send_port.origin_id = ILLEGAL_PORT; Dart_CObject uri; if (script_uri != NULL) { uri.type = Dart_CObject_kString; uri.value.as_string = const_cast(script_uri); } else { uri.type = Dart_CObject_kNull; } Dart_CObject dart_platform_kernel; if (platform_kernel != NULL) { dart_platform_kernel.type = Dart_CObject_kExternalTypedData; dart_platform_kernel.value.as_external_typed_data.type = Dart_TypedData_kUint8; dart_platform_kernel.value.as_external_typed_data.length = platform_kernel_size; dart_platform_kernel.value.as_external_typed_data.data = const_cast(platform_kernel); dart_platform_kernel.value.as_external_typed_data.peer = const_cast(platform_kernel); dart_platform_kernel.value.as_external_typed_data.callback = PassThroughFinalizer; } else { // If NULL, the kernel service looks up the platform dill file // next to the executable. dart_platform_kernel.type = Dart_CObject_kNull; } Dart_CObject dart_incremental; dart_incremental.type = Dart_CObject_kBool; dart_incremental.value.as_bool = incremental_compile; Dart_CObject dart_strong; dart_strong.type = Dart_CObject_kBool; dart_strong.value.as_bool = true; // TODO(aam): Assert that isolate exists once we move CompileAndReadScript // compilation logic out of CreateIsolateAndSetupHelper and into // IsolateSetupHelper in main.cc. Isolate* isolate = Thread::Current() != NULL ? Thread::Current()->isolate() : NULL; if (incremental_compile) { ASSERT(isolate != NULL); } Dart_CObject isolate_id; isolate_id.type = Dart_CObject_kInt64; isolate_id.value.as_int64 = isolate != NULL ? static_cast(isolate->main_port()) : 0; Dart_CObject message; message.type = Dart_CObject_kArray; Dart_CObject files = BuildFilesPairs(source_files_count, source_files); Dart_CObject suppress_warnings; suppress_warnings.type = Dart_CObject_kBool; suppress_warnings.value.as_bool = FLAG_suppress_fe_warnings; intptr_t num_experimental_flags = experimental_flags->length(); Dart_CObject** experimental_flags_array = new Dart_CObject*[num_experimental_flags]; for (intptr_t i = 0; i < num_experimental_flags; ++i) { experimental_flags_array[i] = new Dart_CObject; experimental_flags_array[i]->type = Dart_CObject_kString; experimental_flags_array[i]->value.as_string = (*experimental_flags)[i]; } Dart_CObject experimental_flags_object; experimental_flags_object.type = Dart_CObject_kArray; experimental_flags_object.value.as_array.values = experimental_flags_array; experimental_flags_object.value.as_array.length = num_experimental_flags; Dart_CObject bytecode; bytecode.type = Dart_CObject_kBool; // Interpreter is supported only on x64 and arm64. #if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64) bytecode.value.as_bool = FLAG_enable_interpreter || FLAG_use_bytecode_compiler; #else bytecode.value.as_bool = FLAG_use_bytecode_compiler && !FLAG_enable_interpreter; #endif Dart_CObject package_config_uri; if (package_config != NULL) { package_config_uri.type = Dart_CObject_kString; package_config_uri.value.as_string = const_cast(package_config); } else { package_config_uri.type = Dart_CObject_kNull; } Dart_CObject multiroot_filepaths_object; { const char* filepaths = multiroot_filepaths != NULL ? multiroot_filepaths : FLAG_kernel_multiroot_filepaths; if (filepaths != NULL) { multiroot_filepaths_object.type = Dart_CObject_kString; multiroot_filepaths_object.value.as_string = const_cast(filepaths); } else { multiroot_filepaths_object.type = Dart_CObject_kNull; } } Dart_CObject multiroot_scheme_object; { const char* scheme = multiroot_scheme != NULL ? multiroot_scheme : FLAG_kernel_multiroot_scheme; if (scheme != NULL) { multiroot_scheme_object.type = Dart_CObject_kString; multiroot_scheme_object.value.as_string = const_cast(scheme); } else { multiroot_scheme_object.type = Dart_CObject_kNull; } } Dart_CObject* message_arr[] = {&tag, &send_port, &uri, &dart_platform_kernel, &dart_incremental, &dart_strong, &isolate_id, &files, &suppress_warnings, &experimental_flags_object, &bytecode, &package_config_uri, &multiroot_filepaths_object, &multiroot_scheme_object}; message.value.as_array.values = message_arr; message.value.as_array.length = ARRAY_SIZE(message_arr); // Send the message. Dart_PostCObject(kernel_port, &message); ReleaseFilesPairs(files); // Wait for reply to arrive. VMTagScope tagScope(Thread::Current(), VMTag::kLoadWaitTagId); MonitorLocker ml(monitor_); while (result_.status == Dart_KernelCompilationStatus_Unknown) { ml.Wait(); } for (intptr_t i = 0; i < num_experimental_flags; ++i) { delete experimental_flags_array[i]; } delete[] experimental_flags_array; return result_; } private: void LoadKernelFromResponse(Dart_CObject* response) { ASSERT((response->type == Dart_CObject_kTypedData) || (response->type == Dart_CObject_kNull)); if (response->type == Dart_CObject_kNull) { return; } ASSERT(response->value.as_typed_data.type == Dart_TypedData_kUint8); result_.kernel_size = response->value.as_typed_data.length; result_.kernel = static_cast(malloc(result_.kernel_size)); memmove(result_.kernel, response->value.as_typed_data.values, result_.kernel_size); } // Possible responses from the Kernel isolate: // // [Ok, Uint8List KernelBinary] // [Error, String error, Uint8List KernelBinary] // [Crash, String error] // void HandleResponseImpl(Dart_CObject* message) { ASSERT(message->type == Dart_CObject_kArray); ASSERT(message->value.as_array.length >= 1); Dart_CObject** response = message->value.as_array.values; MonitorLocker ml(monitor_); ASSERT(response[0]->type == Dart_CObject_kInt32); result_.status = static_cast( message->value.as_array.values[0]->value.as_int32); if (result_.status == Dart_KernelCompilationStatus_Ok) { LoadKernelFromResponse(response[1]); } else { if (result_.status == Dart_KernelCompilationStatus_Error) { LoadKernelFromResponse(response[2]); } // This is an error. ASSERT(response[1]->type == Dart_CObject_kString); result_.error = strdup(response[1]->value.as_string); } ml.Notify(); } static void HandleResponse(Dart_Port port, Dart_CObject* message) { MonitorLocker locker(requests_monitor_); KernelCompilationRequest* rq = FindRequestLocked(port); if (rq == NULL) { return; } rq->HandleResponseImpl(message); } static void RegisterRequest(KernelCompilationRequest* rq) { MonitorLocker locker(requests_monitor_); rq->next_ = requests_; if (requests_ != NULL) { requests_->prev_ = rq; } requests_ = rq; } static void UnregisterRequest(KernelCompilationRequest* rq) { MonitorLocker locker(requests_monitor_); if (rq->next_ != NULL) { rq->next_->prev_ = rq->prev_; } if (rq->prev_ != NULL) { rq->prev_->next_ = rq->next_; } else { requests_ = rq->next_; } } // Note: Caller must hold requests_monitor_. static KernelCompilationRequest* FindRequestLocked(Dart_Port port) { for (KernelCompilationRequest* rq = requests_; rq != NULL; rq = rq->next_) { if (rq->port_ == port) { return rq; } } return NULL; } // This monitor must be held whenever linked list of requests is accessed. static Monitor* requests_monitor_; // Linked list of all active requests. Used to find a request by port number. // Guarded by requests_monitor_ lock. static KernelCompilationRequest* requests_; Monitor* monitor_; Dart_Port port_; // Linked list of active requests. Guarded by requests_monitor_ lock. KernelCompilationRequest* next_; KernelCompilationRequest* prev_; Dart_KernelCompilationResult result_; }; Monitor* KernelCompilationRequest::requests_monitor_ = new Monitor(); KernelCompilationRequest* KernelCompilationRequest::requests_ = NULL; Dart_KernelCompilationResult KernelIsolate::CompileToKernel( const char* script_uri, const uint8_t* platform_kernel, intptr_t platform_kernel_size, int source_file_count, Dart_SourceFile source_files[], bool incremental_compile, const char* package_config, const char* multiroot_filepaths, const char* multiroot_scheme) { // This must be the main script to be loaded. Wait for Kernel isolate // to finish initialization. Dart_Port kernel_port = WaitForKernelPort(); if (kernel_port == ILLEGAL_PORT) { Dart_KernelCompilationResult result; result.status = Dart_KernelCompilationStatus_Unknown; result.error = strdup("Error while initializing Kernel isolate"); return result; } KernelCompilationRequest request; return request.SendAndWaitForResponse( kCompileTag, kernel_port, script_uri, platform_kernel, platform_kernel_size, source_file_count, source_files, incremental_compile, package_config, multiroot_filepaths, multiroot_scheme, experimental_flags_); } Dart_KernelCompilationResult KernelIsolate::ListDependencies() { Dart_Port kernel_port = WaitForKernelPort(); if (kernel_port == ILLEGAL_PORT) { Dart_KernelCompilationResult result; result.status = Dart_KernelCompilationStatus_Unknown; result.error = strdup("Error while initializing Kernel isolate"); return result; } KernelCompilationRequest request; return request.SendAndWaitForResponse(kListDependenciesTag, kernel_port, NULL, NULL, 0, 0, NULL, false, NULL, NULL, NULL, experimental_flags_); } Dart_KernelCompilationResult KernelIsolate::AcceptCompilation() { // This must be the main script to be loaded. Wait for Kernel isolate // to finish initialization. Dart_Port kernel_port = WaitForKernelPort(); if (kernel_port == ILLEGAL_PORT) { Dart_KernelCompilationResult result; result.status = Dart_KernelCompilationStatus_Unknown; result.error = strdup("Error while initializing Kernel isolate"); return result; } KernelCompilationRequest request; return request.SendAndWaitForResponse(kAcceptTag, kernel_port, NULL, NULL, 0, 0, NULL, true, NULL, NULL, NULL, experimental_flags_); } Dart_KernelCompilationResult KernelIsolate::CompileExpressionToKernel( const char* expression, const Array& definitions, const Array& type_definitions, const char* library_url, const char* klass, bool is_static) { Dart_Port kernel_port = WaitForKernelPort(); if (kernel_port == ILLEGAL_PORT) { Dart_KernelCompilationResult result; result.status = Dart_KernelCompilationStatus_Unknown; result.error = strdup("Error while initializing Kernel isolate"); return result; } TransitionVMToNative transition(Thread::Current()); KernelCompilationRequest request; return request.SendAndWaitForResponse(kernel_port, expression, definitions, type_definitions, library_url, klass, is_static, experimental_flags_); } Dart_KernelCompilationResult KernelIsolate::UpdateInMemorySources( int source_files_count, Dart_SourceFile source_files[]) { // This must be the main script to be loaded. Wait for Kernel isolate // to finish initialization. Dart_Port kernel_port = WaitForKernelPort(); if (kernel_port == ILLEGAL_PORT) { Dart_KernelCompilationResult result; result.status = Dart_KernelCompilationStatus_Unknown; result.error = strdup("Error while initializing Kernel isolate"); return result; } KernelCompilationRequest request; return request.SendAndWaitForResponse( kUpdateSourcesTag, kernel_port, NULL, NULL, 0, source_files_count, source_files, true, NULL, NULL, NULL, experimental_flags_); } void KernelIsolate::NotifyAboutIsolateShutdown(const Isolate* isolate) { if (!KernelIsolate::IsRunning()) { return; } Dart_Port kernel_port = WaitForKernelPort(); if (kernel_port == ILLEGAL_PORT) { return; } Dart_CObject tag; tag.type = Dart_CObject_kInt32; tag.value.as_int32 = KernelIsolate::kNotifyIsolateShutdown; Dart_CObject isolate_id; isolate_id.type = Dart_CObject_kInt64; isolate_id.value.as_int64 = isolate != NULL ? static_cast(isolate->main_port()) : 0; Dart_CObject message; message.type = Dart_CObject_kArray; Dart_CObject* message_arr[] = {&tag, &isolate_id}; message.value.as_array.values = message_arr; message.value.as_array.length = ARRAY_SIZE(message_arr); // Send the message. Dart_PostCObject(kernel_port, &message); } } // namespace dart