| Index: runtime/vm/service_isolate.cc
|
| diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..19b0f5becd266afa41dfd6459675e01701890468
|
| --- /dev/null
|
| +++ b/runtime/vm/service_isolate.cc
|
| @@ -0,0 +1,685 @@
|
| +// Copyright (c) 2015, 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/service_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"
|
| +
|
| +namespace dart {
|
| +
|
| +DEFINE_FLAG(bool, trace_service, false, "Trace VM service requests.");
|
| +DEFINE_FLAG(bool, trace_service_pause_events, false,
|
| + "Trace VM service isolate pause events.");
|
| +
|
| +struct ResourcesEntry {
|
| + const char* path_;
|
| + const char* resource_;
|
| + int length_;
|
| +};
|
| +
|
| +extern ResourcesEntry __service_resources_[];
|
| +
|
| +class Resources {
|
| + public:
|
| + static const int kNoSuchInstance = -1;
|
| + static int ResourceLookup(const char* path, const char** resource) {
|
| + ResourcesEntry* table = ResourceTable();
|
| + for (int i = 0; table[i].path_ != NULL; i++) {
|
| + const ResourcesEntry& entry = table[i];
|
| + if (strcmp(path, entry.path_) == 0) {
|
| + *resource = entry.resource_;
|
| + ASSERT(entry.length_ > 0);
|
| + return entry.length_;
|
| + }
|
| + }
|
| + return kNoSuchInstance;
|
| + }
|
| +
|
| + static const char* Path(int idx) {
|
| + ASSERT(idx >= 0);
|
| + ResourcesEntry* entry = At(idx);
|
| + if (entry == NULL) {
|
| + return NULL;
|
| + }
|
| + ASSERT(entry->path_ != NULL);
|
| + return entry->path_;
|
| + }
|
| +
|
| + static int Length(int idx) {
|
| + ASSERT(idx >= 0);
|
| + ResourcesEntry* entry = At(idx);
|
| + if (entry == NULL) {
|
| + return kNoSuchInstance;
|
| + }
|
| + ASSERT(entry->path_ != NULL);
|
| + return entry->length_;
|
| + }
|
| +
|
| + static const uint8_t* Resource(int idx) {
|
| + ASSERT(idx >= 0);
|
| + ResourcesEntry* entry = At(idx);
|
| + if (entry == NULL) {
|
| + return NULL;
|
| + }
|
| + return reinterpret_cast<const uint8_t*>(entry->resource_);
|
| + }
|
| +
|
| + private:
|
| + static ResourcesEntry* At(int idx) {
|
| + ASSERT(idx >= 0);
|
| + ResourcesEntry* table = ResourceTable();
|
| + for (int i = 0; table[i].path_ != NULL; i++) {
|
| + if (idx == i) {
|
| + return &table[i];
|
| + }
|
| + }
|
| + return NULL;
|
| + }
|
| +
|
| + static ResourcesEntry* ResourceTable() {
|
| + return &__service_resources_[0];
|
| + }
|
| +
|
| + DISALLOW_ALLOCATION();
|
| + DISALLOW_IMPLICIT_CONSTRUCTORS(Resources);
|
| +};
|
| +
|
| +
|
| +static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
|
| + void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
|
| + return reinterpret_cast<uint8_t*>(new_ptr);
|
| +}
|
| +
|
| +
|
| +static Dart_Port ExtractPort(Isolate* isolate, Dart_Handle receivePort) {
|
| + const ReceivePort& rp = Api::UnwrapReceivePortHandle(isolate, receivePort);
|
| + if (rp.IsNull()) {
|
| + return ILLEGAL_PORT;
|
| + }
|
| + return rp.Id();
|
| +}
|
| +
|
| +
|
| +// These must be kept in sync with service/constants.dart
|
| +#define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1
|
| +#define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2
|
| +
|
| +static RawArray* MakeServiceControlMessage(Dart_Port port_id, intptr_t code,
|
| + const String& name) {
|
| + const Array& list = Array::Handle(Array::New(4));
|
| + ASSERT(!list.IsNull());
|
| + const Integer& code_int = Integer::Handle(Integer::New(code));
|
| + const Integer& port_int = Integer::Handle(Integer::New(port_id));
|
| + const SendPort& send_port = SendPort::Handle(SendPort::New(port_id));
|
| + list.SetAt(0, code_int);
|
| + list.SetAt(1, port_int);
|
| + list.SetAt(2, send_port);
|
| + list.SetAt(3, name);
|
| + return list.raw();
|
| +}
|
| +
|
| +
|
| +const char* ServiceIsolate::kName = "vm-service";
|
| +Isolate* ServiceIsolate::isolate_ = NULL;
|
| +Dart_Port ServiceIsolate::port_ = ILLEGAL_PORT;
|
| +Dart_Port ServiceIsolate::load_port_ = ILLEGAL_PORT;
|
| +Dart_IsolateCreateCallback ServiceIsolate::create_callback_ = NULL;
|
| +Monitor* ServiceIsolate::monitor_ = NULL;
|
| +bool ServiceIsolate::initializing_ = true;
|
| +
|
| +
|
| +class RegisterRunningIsolatesVisitor : public IsolateVisitor {
|
| + public:
|
| + explicit RegisterRunningIsolatesVisitor(Isolate* service_isolate)
|
| + : IsolateVisitor(),
|
| + register_function_(Function::Handle(service_isolate)),
|
| + service_isolate_(service_isolate) {
|
| + ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
|
| + // Get library.
|
| + const String& library_url = Symbols::DartVMService();
|
| + ASSERT(!library_url.IsNull());
|
| + const Library& library =
|
| + Library::Handle(Library::LookupLibrary(library_url));
|
| + ASSERT(!library.IsNull());
|
| + // Get function.
|
| + const String& function_name =
|
| + String::Handle(String::New("_registerIsolate"));
|
| + ASSERT(!function_name.IsNull());
|
| + register_function_ = library.LookupFunctionAllowPrivate(function_name);
|
| + ASSERT(!register_function_.IsNull());
|
| + }
|
| +
|
| + virtual void VisitIsolate(Isolate* isolate) {
|
| + ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
|
| + if (ServiceIsolate::IsServiceIsolate(isolate) ||
|
| + (isolate == Dart::vm_isolate())) {
|
| + // We do not register the service or vm isolate.
|
| + return;
|
| + }
|
| + // Setup arguments for call.
|
| + Dart_Port port_id = isolate->main_port();
|
| + const Integer& port_int = Integer::Handle(Integer::New(port_id));
|
| + ASSERT(!port_int.IsNull());
|
| + const SendPort& send_port = SendPort::Handle(SendPort::New(port_id));
|
| + const String& name = String::Handle(String::New(isolate->name()));
|
| + ASSERT(!name.IsNull());
|
| + const Array& args = Array::Handle(Array::New(3));
|
| + ASSERT(!args.IsNull());
|
| + args.SetAt(0, port_int);
|
| + args.SetAt(1, send_port);
|
| + args.SetAt(2, name);
|
| + Object& r = Object::Handle(service_isolate_);
|
| + r = DartEntry::InvokeFunction(register_function_, args);
|
| + if (FLAG_trace_service) {
|
| + OS::Print("vm-service: Isolate %s %" Pd64 " registered.\n",
|
| + name.ToCString(),
|
| + port_id);
|
| + }
|
| + ASSERT(!r.IsError());
|
| + }
|
| +
|
| + private:
|
| + Function& register_function_;
|
| + Isolate* service_isolate_;
|
| +};
|
| +
|
| +
|
| +
|
| +class ServiceIsolateNatives : public AllStatic {
|
| + public:
|
| + static void SendIsolateServiceMessage(Dart_NativeArguments args) {
|
| + NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
|
| + Isolate* isolate = arguments->isolate();
|
| + StackZone zone(isolate);
|
| + HANDLESCOPE(isolate);
|
| + GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
|
| + GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
|
| +
|
| + // Set the type of the OOB message.
|
| + message.SetAt(0, Smi::Handle(isolate, Smi::New(Message::kServiceOOBMsg)));
|
| +
|
| + // Serialize message.
|
| + uint8_t* data = NULL;
|
| + MessageWriter writer(&data, &allocator, false);
|
| + writer.WriteMessage(message);
|
| +
|
| + // TODO(turnidge): Throw an exception when the return value is false?
|
| + PortMap::PostMessage(new Message(sp.Id(), data, writer.BytesWritten(),
|
| + Message::kOOBPriority));
|
| + }
|
| +
|
| + static void SendRootServiceMessage(Dart_NativeArguments args) {
|
| + NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
|
| + Isolate* isolate = arguments->isolate();
|
| + StackZone zone(isolate);
|
| + HANDLESCOPE(isolate);
|
| + GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
|
| + Service::HandleRootMessage(message);
|
| + }
|
| +
|
| + static void SetEventMask(Dart_NativeArguments args) {
|
| + NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
|
| + Isolate* isolate = arguments->isolate();
|
| + StackZone zone(isolate);
|
| + HANDLESCOPE(isolate);
|
| + GET_NON_NULL_NATIVE_ARGUMENT(Integer, mask, arguments->NativeArgAt(0));
|
| + Service::SetEventMask(mask.AsTruncatedUint32Value());
|
| + }
|
| +
|
| + static void OnStart(Dart_NativeArguments args) {
|
| + NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
|
| + Isolate* isolate = arguments->isolate();
|
| + StackZone zone(isolate);
|
| + HANDLESCOPE(isolate);
|
| + {
|
| + if (FLAG_trace_service) {
|
| + OS::Print("vm-service: Booting dart:vmservice library.\n");
|
| + }
|
| + // Boot the dart:vmservice library.
|
| + Dart_EnterScope();
|
| + Dart_Handle url_str =
|
| + Dart_NewStringFromCString(Symbols::Name(Symbols::kDartVMServiceId));
|
| + Dart_Handle library = Dart_LookupLibrary(url_str);
|
| + ASSERT(Dart_IsLibrary(library));
|
| + Dart_Handle result =
|
| + Dart_Invoke(library, Dart_NewStringFromCString("boot"), 0, NULL);
|
| + ASSERT(!Dart_IsError(result));
|
| + Dart_Port port = ExtractPort(isolate, result);
|
| + ASSERT(port != ILLEGAL_PORT);
|
| + ServiceIsolate::SetServicePort(port);
|
| + Dart_ExitScope();
|
| + }
|
| +
|
| + {
|
| + if (FLAG_trace_service) {
|
| + OS::Print("vm-service: Registering running isolates.\n");
|
| + }
|
| + // Register running isolates with service.
|
| + RegisterRunningIsolatesVisitor register_isolates(isolate);
|
| + Isolate::VisitIsolates(®ister_isolates);
|
| + }
|
| + }
|
| +};
|
| +
|
| +
|
| +struct ServiceNativeEntry {
|
| + const char* name;
|
| + int num_arguments;
|
| + Dart_NativeFunction function;
|
| +};
|
| +
|
| +
|
| +static ServiceNativeEntry _ServiceNativeEntries[] = {
|
| + {"VMService_SendIsolateServiceMessage", 2,
|
| + ServiceIsolateNatives::SendIsolateServiceMessage},
|
| + {"VMService_SendRootServiceMessage", 1,
|
| + ServiceIsolateNatives::SendRootServiceMessage},
|
| + {"VMService_SetEventMask", 1,
|
| + ServiceIsolateNatives::SetEventMask},
|
| + {"VMService_OnStart", 0,
|
| + ServiceIsolateNatives::OnStart },
|
| +};
|
| +
|
| +
|
| +static Dart_NativeFunction ServiceNativeResolver(Dart_Handle name,
|
| + int num_arguments,
|
| + bool* auto_setup_scope) {
|
| + const Object& obj = Object::Handle(Api::UnwrapHandle(name));
|
| + if (!obj.IsString()) {
|
| + return NULL;
|
| + }
|
| + const char* function_name = obj.ToCString();
|
| + ASSERT(function_name != NULL);
|
| + ASSERT(auto_setup_scope != NULL);
|
| + *auto_setup_scope = true;
|
| + intptr_t n = sizeof(_ServiceNativeEntries) /
|
| + sizeof(_ServiceNativeEntries[0]);
|
| + for (intptr_t i = 0; i < n; i++) {
|
| + ServiceNativeEntry entry = _ServiceNativeEntries[i];
|
| + if ((strcmp(function_name, entry.name) == 0) &&
|
| + (num_arguments == entry.num_arguments)) {
|
| + return entry.function;
|
| + }
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +bool ServiceIsolate::NameEquals(const char* name) {
|
| + ASSERT(name != NULL);
|
| + return strcmp(name, kName) == 0;
|
| +}
|
| +
|
| +
|
| +bool ServiceIsolate::Exists() {
|
| + MonitorLocker ml(monitor_);
|
| + return isolate_ != NULL;
|
| +}
|
| +
|
| +
|
| +bool ServiceIsolate::IsRunning() {
|
| + MonitorLocker ml(monitor_);
|
| + return (port_ != ILLEGAL_PORT) && (isolate_ != NULL);
|
| +}
|
| +
|
| +
|
| +bool ServiceIsolate::IsServiceIsolate(Isolate* isolate) {
|
| + MonitorLocker ml(monitor_);
|
| + return isolate == isolate_;
|
| +}
|
| +
|
| +
|
| +Dart_Port ServiceIsolate::Port() {
|
| + MonitorLocker ml(monitor_);
|
| + return port_;
|
| +}
|
| +
|
| +
|
| +Dart_Port ServiceIsolate::WaitForLoadPort() {
|
| + MonitorLocker ml(monitor_);
|
| +
|
| + while (initializing_ && (load_port_ == ILLEGAL_PORT)) {
|
| + ml.Wait();
|
| + }
|
| +
|
| + return load_port_;
|
| +}
|
| +
|
| +
|
| +Dart_Port ServiceIsolate::LoadPort() {
|
| + MonitorLocker ml(monitor_);
|
| + return load_port_;
|
| +}
|
| +
|
| +
|
| +bool ServiceIsolate::SendIsolateStartupMessage() {
|
| + if (!IsRunning()) {
|
| + return false;
|
| + }
|
| + Isolate* isolate = Isolate::Current();
|
| + if (IsServiceIsolate(isolate)) {
|
| + return false;
|
| + }
|
| + ASSERT(isolate != NULL);
|
| + HANDLESCOPE(isolate);
|
| + const String& name = String::Handle(String::New(isolate->name()));
|
| + ASSERT(!name.IsNull());
|
| + const Array& list = Array::Handle(
|
| + MakeServiceControlMessage(Dart_GetMainPortId(),
|
| + VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID,
|
| + name));
|
| + ASSERT(!list.IsNull());
|
| + uint8_t* data = NULL;
|
| + MessageWriter writer(&data, &allocator, false);
|
| + writer.WriteMessage(list);
|
| + intptr_t len = writer.BytesWritten();
|
| + if (FLAG_trace_service) {
|
| + OS::Print("vm-service: Isolate %s %" Pd64 " registered.\n",
|
| + name.ToCString(),
|
| + Dart_GetMainPortId());
|
| + }
|
| + return PortMap::PostMessage(
|
| + new Message(port_, data, len, Message::kNormalPriority));
|
| +}
|
| +
|
| +
|
| +bool ServiceIsolate::SendIsolateShutdownMessage() {
|
| + if (!IsRunning()) {
|
| + return false;
|
| + }
|
| + Isolate* isolate = Isolate::Current();
|
| + if (IsServiceIsolate(isolate)) {
|
| + return false;
|
| + }
|
| + ASSERT(isolate != NULL);
|
| + HANDLESCOPE(isolate);
|
| + const String& name = String::Handle(String::New(isolate->name()));
|
| + ASSERT(!name.IsNull());
|
| + const Array& list = Array::Handle(
|
| + MakeServiceControlMessage(Dart_GetMainPortId(),
|
| + VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID,
|
| + name));
|
| + ASSERT(!list.IsNull());
|
| + uint8_t* data = NULL;
|
| + MessageWriter writer(&data, &allocator, false);
|
| + writer.WriteMessage(list);
|
| + intptr_t len = writer.BytesWritten();
|
| + if (FLAG_trace_service) {
|
| + OS::Print("vm-service: Isolate %s %" Pd64 " deregistered.\n",
|
| + name.ToCString(),
|
| + Dart_GetMainPortId());
|
| + }
|
| + return PortMap::PostMessage(
|
| + new Message(port_, data, len, Message::kNormalPriority));
|
| +}
|
| +
|
| +
|
| +void ServiceIsolate::SetServicePort(Dart_Port port) {
|
| + MonitorLocker ml(monitor_);
|
| + port_ = port;
|
| +}
|
| +
|
| +
|
| +void ServiceIsolate::SetServiceIsolate(Isolate* isolate) {
|
| + MonitorLocker ml(monitor_);
|
| + isolate_ = isolate;
|
| + if (isolate_ != NULL) {
|
| + isolate_->is_service_isolate_ = true;
|
| + }
|
| +}
|
| +
|
| +void ServiceIsolate::SetLoadPort(Dart_Port port) {
|
| + MonitorLocker ml(monitor_);
|
| + load_port_ = port;
|
| +}
|
| +
|
| +
|
| +void ServiceIsolate::MaybeInjectVMServiceLibrary(Isolate* isolate) {
|
| + ASSERT(isolate != NULL);
|
| + ASSERT(isolate->name() != NULL);
|
| + if (!ServiceIsolate::NameEquals(isolate->name())) {
|
| + // Not service isolate.
|
| + return;
|
| + }
|
| + if (Exists()) {
|
| + // Service isolate already exists.
|
| + return;
|
| + }
|
| + SetServiceIsolate(isolate);
|
| +
|
| + StackZone zone(isolate);
|
| + HANDLESCOPE(isolate);
|
| +
|
| + // Register dart:vmservice library.
|
| + const String& url_str = String::Handle(Symbols::DartVMService().raw());
|
| + const Library& library = Library::Handle(Library::New(url_str));
|
| + library.Register();
|
| + library.set_native_entry_resolver(ServiceNativeResolver);
|
| +
|
| + // Temporarily install our library tag handler.
|
| + isolate->set_library_tag_handler(LibraryTagHandler);
|
| +
|
| + // Get script source.
|
| + const char* resource = NULL;
|
| + const char* path = "/vmservice.dart";
|
| + intptr_t r = Resources::ResourceLookup(path, &resource);
|
| + ASSERT(r != Resources::kNoSuchInstance);
|
| + ASSERT(resource != NULL);
|
| + const String& source_str = String::Handle(
|
| + String::FromUTF8(reinterpret_cast<const uint8_t*>(resource), r));
|
| + ASSERT(!source_str.IsNull());
|
| + const Script& script = Script::Handle(
|
| + isolate, Script::New(url_str, source_str, RawScript::kLibraryTag));
|
| +
|
| + // Compile script.
|
| + Dart_EnterScope(); // Need to enter scope for tag handler.
|
| + library.SetLoadInProgress();
|
| + const Error& error = Error::Handle(isolate,
|
| + Compiler::Compile(library, script));
|
| + ASSERT(error.IsNull());
|
| + Dart_Handle result = Dart_FinalizeLoading(false);
|
| + ASSERT(!Dart_IsError(result));
|
| + Dart_ExitScope();
|
| +
|
| + // Uninstall our library tag handler.
|
| + isolate->set_library_tag_handler(NULL);
|
| +}
|
| +
|
| +
|
| +void ServiceIsolate::FinishedInitializing() {
|
| + MonitorLocker ml(monitor_);
|
| + initializing_ = false;
|
| + ml.NotifyAll();
|
| +}
|
| +
|
| +
|
| +class RunServiceTask : public ThreadPool::Task {
|
| + public:
|
| + virtual void Run() {
|
| + ASSERT(Isolate::Current() == NULL);
|
| + char* error = NULL;
|
| + Isolate* isolate = NULL;
|
| +
|
| + Dart_IsolateCreateCallback create_callback =
|
| + ServiceIsolate::create_callback();
|
| + // TODO(johnmccutchan): Support starting up service isolate without embedder
|
| + // provided isolate creation callback.
|
| + if (create_callback == NULL) {
|
| + ServiceIsolate::FinishedInitializing();
|
| + return;
|
| + }
|
| +
|
| + isolate =
|
| + reinterpret_cast<Isolate*>(create_callback(ServiceIsolate::kName,
|
| + NULL,
|
| + NULL,
|
| + NULL,
|
| + &error));
|
| + if (isolate == NULL) {
|
| + OS::PrintErr("vm-service: Isolate creation error: %s\n", error);
|
| + ServiceIsolate::FinishedInitializing();
|
| + return;
|
| + }
|
| +
|
| + Isolate::SetCurrent(NULL);
|
| +
|
| + RunMain(isolate);
|
| +
|
| + ServiceIsolate::FinishedInitializing();
|
| +
|
| + isolate->message_handler()->Run(Dart::thread_pool(),
|
| + NULL,
|
| + ShutdownIsolate,
|
| + reinterpret_cast<uword>(isolate));
|
| + }
|
| +
|
| + protected:
|
| + static void ShutdownIsolate(uword parameter) {
|
| + Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
|
| + ASSERT(ServiceIsolate::IsServiceIsolate(isolate));
|
| + {
|
| + // Print the error if there is one. This may execute dart code to
|
| + // print the exception object, so we need to use a StartIsolateScope.
|
| + StartIsolateScope start_scope(isolate);
|
| + StackZone zone(isolate);
|
| + HandleScope handle_scope(isolate);
|
| + Error& error = Error::Handle();
|
| + error = isolate->object_store()->sticky_error();
|
| + if (!error.IsNull()) {
|
| + OS::PrintErr("vm-service: Error: %s\n", error.ToErrorCString());
|
| + }
|
| + Dart::RunShutdownCallback();
|
| + }
|
| + {
|
| + // Shut the isolate down.
|
| + SwitchIsolateScope switch_scope(isolate);
|
| + Dart::ShutdownIsolate();
|
| + }
|
| + ServiceIsolate::SetServiceIsolate(NULL);
|
| + ServiceIsolate::SetServicePort(ILLEGAL_PORT);
|
| + if (FLAG_trace_service) {
|
| + OS::Print("vm-service: Shutdown.\n");
|
| + }
|
| + }
|
| +
|
| + void RunMain(Isolate* isolate) {
|
| + StartIsolateScope iso_scope(isolate);
|
| + StackZone zone(isolate);
|
| + HANDLESCOPE(isolate);
|
| + // Invoke main which will return the loadScriptPort.
|
| + const Library& root_library =
|
| + Library::Handle(isolate, isolate->object_store()->root_library());
|
| + if (root_library.IsNull()) {
|
| + if (FLAG_trace_service) {
|
| + OS::Print("vm-service: Embedder did not install a script.");
|
| + }
|
| + // Service isolate is not supported by embedder.
|
| + return;
|
| + }
|
| + ASSERT(!root_library.IsNull());
|
| + const String& entry_name = String::Handle(isolate, String::New("main"));
|
| + ASSERT(!entry_name.IsNull());
|
| + const Function& entry =
|
| + Function::Handle(isolate,
|
| + root_library.LookupFunctionAllowPrivate(entry_name));
|
| + if (entry.IsNull()) {
|
| + // Service isolate is not supported by embedder.
|
| + if (FLAG_trace_service) {
|
| + OS::Print("vm-service: Embedder did not provide a main function.");
|
| + }
|
| + return;
|
| + }
|
| + ASSERT(!entry.IsNull());
|
| + const Object& result =
|
| + Object::Handle(isolate,
|
| + DartEntry::InvokeFunction(entry,
|
| + Object::empty_array()));
|
| + ASSERT(!result.IsNull());
|
| + if (result.IsError()) {
|
| + // Service isolate did not initialize properly.
|
| + if (FLAG_trace_service) {
|
| + const Error& error = Error::Cast(result);
|
| + OS::Print("vm-service: Calling main resulted in an error: %s",
|
| + error.ToErrorCString());
|
| + }
|
| + return;
|
| + }
|
| + ASSERT(result.IsReceivePort());
|
| + const ReceivePort& rp = ReceivePort::Cast(result);
|
| + ServiceIsolate::SetLoadPort(rp.Id());
|
| + }
|
| +};
|
| +
|
| +
|
| +void ServiceIsolate::Run() {
|
| + ASSERT(monitor_ == NULL);
|
| + monitor_ = new Monitor();
|
| + ASSERT(monitor_ != NULL);
|
| + // 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 RunServiceTask());
|
| +}
|
| +
|
| +
|
| +Dart_Handle ServiceIsolate::GetSource(const char* name) {
|
| + ASSERT(name != NULL);
|
| + int i = 0;
|
| + while (true) {
|
| + const char* path = Resources::Path(i);
|
| + if (path == NULL) {
|
| + break;
|
| + }
|
| + ASSERT(*path != '\0');
|
| + // Skip the '/'.
|
| + path++;
|
| + if (strcmp(name, path) == 0) {
|
| + const uint8_t* str = Resources::Resource(i);
|
| + intptr_t length = Resources::Length(i);
|
| + return Dart_NewStringFromUTF8(str, length);
|
| + }
|
| + i++;
|
| + }
|
| + return Dart_Null();
|
| +}
|
| +
|
| +
|
| +Dart_Handle ServiceIsolate::LibraryTagHandler(Dart_LibraryTag tag,
|
| + Dart_Handle library,
|
| + Dart_Handle url) {
|
| + if (tag == Dart_kCanonicalizeUrl) {
|
| + // url is already canonicalized.
|
| + return url;
|
| + }
|
| + if (tag != Dart_kSourceTag) {
|
| + FATAL("ServiceIsolate::LibraryTagHandler encountered an unexpected tag.");
|
| + }
|
| + ASSERT(tag == Dart_kSourceTag);
|
| + const char* url_string = NULL;
|
| + Dart_Handle result = Dart_StringToCString(url, &url_string);
|
| + if (Dart_IsError(result)) {
|
| + return result;
|
| + }
|
| + Dart_Handle source = GetSource(url_string);
|
| + if (Dart_IsError(source)) {
|
| + return source;
|
| + }
|
| + return Dart_LoadSource(library, url, source, 0, 0);
|
| +}
|
| +
|
| +} // namespace dart
|
|
|