Index: runtime/vm/kernel_isolate.cc |
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8d682ab2cd786aa1a299925801b3a6d94dce674e |
--- /dev/null |
+++ b/runtime/vm/kernel_isolate.cc |
@@ -0,0 +1,266 @@ |
+// 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 "vm/compiler.h" |
+#include "vm/dart_api_impl.h" |
+#include "vm/dart_entry.h" |
+#include "vm/isolate.h" |
+#include "vm/lockers.h" |
+#include "vm/message.h" |
+#include "vm/message_handler.h" |
+#include "vm/native_entry.h" |
+#include "vm/native_arguments.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 { |
+ |
+#if !defined(DART_PRECOMPILED_RUNTIME) |
+ |
+#define Z (T->zone()) |
+ |
+DEFINE_FLAG(bool, trace_kernel, false, "Trace Kernel service requests."); |
+DEFINE_FLAG(bool, |
+ use_dart_frontend, |
+ false, |
+ "Parse scripts with Dart-to-Kernel parser"); |
+ |
+const char* KernelIsolate::kName = "kernel-service"; |
+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); |
+ |
+ if (!FLAG_use_dart_frontend) { |
+ ASSERT(FLAG_use_dart_frontend); |
+ // In release builds, make this a no-op. In debug builds, the |
+ // assert shows that this is not supposed to happen. |
+ return; |
+ } |
+ |
+#ifndef PRODUCT |
+ TimelineDurationScope tds(Timeline::GetVMStream(), "KernelIsolateStartup"); |
+#endif // !PRODUCT |
+ char* error = NULL; |
+ Isolate* isolate = NULL; |
+ |
+ Dart_IsolateCreateCallback create_callback = |
+ KernelIsolate::create_callback(); |
+ |
+ if (create_callback == NULL) { |
+ KernelIsolate::FinishedInitializing(); |
+ return; |
+ } |
+ |
+ Dart_IsolateFlags api_flags; |
+ Isolate::FlagsInitialize(&api_flags); |
+ |
+ isolate = reinterpret_cast<Isolate*>(create_callback( |
+ KernelIsolate::kName, NULL, NULL, NULL, &api_flags, NULL, &error)); |
+ if (isolate == NULL) { |
+ if (FLAG_trace_kernel) { |
+ OS::PrintErr("kernel-service: Isolate creation error: %s\n", error); |
+ } |
+ KernelIsolate::SetKernelIsolate(NULL); |
+ KernelIsolate::FinishedInitializing(); |
+ return; |
+ } |
+ |
+ bool init_success = false; |
+ { |
+ ASSERT(Isolate::Current() == NULL); |
+ StartIsolateScope start_scope(isolate); |
+ init_success = RunMain(isolate); |
+ } |
+ KernelIsolate::FinishedInitializing(); |
+ |
+ if (!init_success) { |
+ ShutdownIsolate(reinterpret_cast<uword>(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<uword>(isolate)); |
+ } |
+ |
+ protected: |
+ static void ShutdownIsolate(uword parameter) { |
+ if (FLAG_trace_kernel) { |
+ OS::Print("kernel-service: ShutdownIsolate\n"); |
+ } |
+ Isolate* I = reinterpret_cast<Isolate*>(parameter); |
+ ASSERT(KernelIsolate::IsKernelIsolate(I)); |
+ KernelIsolate::SetKernelIsolate(NULL); |
+ KernelIsolate::SetLoadPort(ILLEGAL_PORT); |
+ 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("kernel-service: Error: %s\n", error.ToErrorCString()); |
+ } |
+ error = I->sticky_error(); |
+ if (!error.IsNull() && !error.IsUnwindError()) { |
+ OS::PrintErr("kernel-service: Error: %s\n", error.ToErrorCString()); |
+ } |
+ Dart::RunShutdownCallback(); |
+ } |
+ // Shut the isolate down. |
+ Dart::ShutdownIsolate(I); |
+ if (FLAG_trace_kernel) { |
+ OS::Print("kernel-service: 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()) { |
+ if (FLAG_trace_kernel) { |
+ OS::Print("kernel-service: 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. |
+ if (FLAG_trace_kernel) { |
+ OS::Print("kernel-service: 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::Print("kernel-service: Calling main resulted in an error: %s", |
+ error.ToErrorCString()); |
+ } |
+ return false; |
+ } |
+ ASSERT(result.IsReceivePort()); |
+ const ReceivePort& rp = ReceivePort::Cast(result); |
+ KernelIsolate::SetLoadPort(rp.Id()); |
+ return true; |
+ } |
+}; |
+ |
+ |
+void KernelIsolate::Run() { |
+ if (!FLAG_use_dart_frontend) { |
+ return; |
+ } |
+ // 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::InitCallback(Isolate* I) { |
+ Thread* T = Thread::Current(); |
+ ASSERT(I == T->isolate()); |
+ ASSERT(I != NULL); |
+ ASSERT(I->name() != NULL); |
+ if (!FLAG_use_dart_frontend || |
+ (strstr(I->name(), "kernel-service") == NULL)) { |
+ // Not kernel isolate. |
+ return; |
+ } |
+ ASSERT(!Exists()); |
+ if (FLAG_trace_kernel) { |
+ OS::Print("kernel-service: 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::Exists() { |
+ MonitorLocker ml(monitor_); |
+ return isolate_ != NULL; |
+} |
+ |
+ |
+void KernelIsolate::SetKernelIsolate(Isolate* isolate) { |
+ MonitorLocker ml(monitor_); |
+ isolate_ = isolate; |
+} |
+ |
+void KernelIsolate::SetLoadPort(Dart_Port port) { |
+ MonitorLocker ml(monitor_); |
+ kernel_port_ = port; |
+} |
+ |
+void KernelIsolate::FinishedInitializing() { |
+ MonitorLocker ml(monitor_); |
+ initializing_ = false; |
+ ml.NotifyAll(); |
+} |
+ |
+ |
+Dart_Port KernelIsolate::WaitForKernelPort() { |
+ if (!FLAG_use_dart_frontend) { |
+ return ILLEGAL_PORT; |
+ } |
+ MonitorLocker ml(monitor_); |
+ while (initializing_ && (kernel_port_ == ILLEGAL_PORT)) { |
+ ml.Wait(); |
+ } |
+ return kernel_port_; |
+} |
+ |
+#endif // DART_PRECOMPILED_RUNTIME |
+ |
+} // namespace dart |