Chromium Code Reviews| Index: runtime/vm/service.cc |
| diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc |
| index fe8aaa1b197084bb3e0518bcb6461d126f602382..ff8b8e2a9f4a29dee4c0b3df301112a2d8dd4c2f 100644 |
| --- a/runtime/vm/service.cc |
| +++ b/runtime/vm/service.cc |
| @@ -4,28 +4,87 @@ |
| #include "vm/service.h" |
| +#include "include/dart_api.h" |
| + |
| #include "vm/cpu.h" |
| +#include "vm/dart_api_impl.h" |
| #include "vm/dart_entry.h" |
| #include "vm/debugger.h" |
| #include "vm/heap_histogram.h" |
| #include "vm/isolate.h" |
| #include "vm/message.h" |
| +#include "vm/native_entry.h" |
| +#include "vm/native_arguments.h" |
| #include "vm/object.h" |
| #include "vm/object_id_ring.h" |
| #include "vm/object_store.h" |
| #include "vm/port.h" |
| #include "vm/profiler.h" |
| -namespace dart { |
| -typedef void (*ServiceMessageHandler)(Isolate* isolate, JSONStream* stream); |
| +namespace dart { |
| -struct ServiceMessageHandlerEntry { |
| - const char* command; |
| - ServiceMessageHandler handler; |
| +struct ResourcesEntry { |
| + const char* path_; |
| + const char* resource_; |
| + int length_; |
| }; |
| -static ServiceMessageHandler FindServiceMessageHandler(const char* command); |
| +extern ResourcesEntry __service_resources_[]; |
| + |
| +class Resources { |
| + public: |
| + static const int kNoSuchInstance = -1; |
| + static int ResourceLookup(const char* path, const char** resource) { |
| + ResourcesEntry* table = get_resources_table(); |
| + 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* get_resource_path(int idx) { |
|
siva
2014/01/10 00:01:54
ditto comments about the function names as they ar
Cutch
2014/01/10 21:01:42
Done.
|
| + ASSERT(idx >= 0); |
| + ResourcesEntry* entry = get_resource_entry(idx); |
| + if (entry == NULL) { |
| + return NULL; |
| + } |
| + return entry->path_; |
| + } |
| + |
| + static const char* get_resource_resource(int idx) { |
| + ASSERT(idx >= 0); |
| + ResourcesEntry* entry = get_resource_entry(idx); |
| + if (entry == NULL) { |
| + return NULL; |
| + } |
| + return entry->resource_; |
| + } |
| + |
| + private: |
| + static ResourcesEntry* get_resource_entry(int idx) { |
| + ASSERT(idx >= 0); |
| + ResourcesEntry* table = get_resources_table(); |
| + for (int i = 0; table[i].path_ != NULL; i++) { |
| + if (idx == i) { |
| + return &table[i]; |
| + } |
| + } |
| + return NULL; |
| + } |
| + |
| + static ResourcesEntry* get_resources_table() { |
| + 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) { |
| @@ -34,6 +93,300 @@ static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { |
| } |
| +static void SendServiceMessage(Dart_NativeArguments args) { |
| + NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args); |
| + Isolate* isolate = arguments->isolate(); |
| + StackZone zone(isolate); |
| + HANDLESCOPE(isolate); |
| + GET_NON_NULL_NATIVE_ARGUMENT(Instance, sp, arguments->NativeArgAt(0)); |
| + GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(1)); |
| + |
| + // Extract SendPort port id. |
| + const Object& sp_id_obj = Object::Handle(DartLibraryCalls::PortGetId(sp)); |
| + if (sp_id_obj.IsError()) { |
| + Exceptions::PropagateError(Error::Cast(sp_id_obj)); |
| + } |
| + Integer& id = Integer::Handle(); |
| + id ^= sp_id_obj.raw(); |
| + Dart_Port sp_id = static_cast<Dart_Port>(id.AsInt64Value()); |
| + ASSERT(sp_id != ILLEGAL_PORT); |
| + |
| + // Serialize message. |
| + uint8_t* data = NULL; |
| + MessageWriter writer(&data, &allocator); |
| + 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)); |
| +} |
| + |
| + |
| +struct VmServiceNativeEntry { |
| + const char* name; |
| + int num_arguments; |
| + Dart_NativeFunction function; |
| +}; |
| + |
| + |
| +static VmServiceNativeEntry _VmServiceNativeEntries[] = { |
| + {"VMService_SendServiceMessage", 2, SendServiceMessage} |
| +}; |
| + |
| + |
| +static Dart_NativeFunction VmServiceNativeResolver(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(_VmServiceNativeEntries) / sizeof(_VmServiceNativeEntries[0]); |
| + for (intptr_t i = 0; i < n; i++) { |
| + VmServiceNativeEntry entry = _VmServiceNativeEntries[i]; |
| + if (!strcmp(function_name, entry.name) && |
| + (num_arguments == entry.num_arguments)) { |
| + return entry.function; |
| + } |
| + } |
|
siva
2014/01/10 00:01:54
There is only one entry in the table does it need
Cutch
2014/01/10 21:01:42
There will be more natives later. Todd has a CL wh
|
| + return NULL; |
| +} |
| + |
| +#define SHUTDOWN(error_msg) \ |
| + printf("Service Isolate Error: %s\n", error_msg); \ |
| + Dart_ExitScope(); \ |
| + Dart_ShutdownIsolate(); \ |
| + return NULL |
| + |
| +#define SHUTDOWN_ON_ERROR(handle) \ |
| + if (Dart_IsError(handle)) { \ |
| + SHUTDOWN(Dart_GetError(handle)); \ |
| + } |
| + |
| +Isolate* Service::service_isolate_ = NULL; |
| +Dart_LibraryTagHandler Service::default_handler_ = NULL; |
| +Dart_Port Service::port_ = ILLEGAL_PORT; |
| + |
| +Isolate* Service::GetServiceIsolate(void* callback_data) { |
| + if (service_isolate_ != NULL) { |
| + // Already initialized, return service isolate. |
| + return service_isolate_; |
| + } |
|
siva
2014/01/10 00:01:54
What happens if multiple threads from the embedder
Cutch
2014/01/10 21:01:42
Good point. Do we make thread safety guarantees ab
|
| + Dart_ServiceIsolateCreateCallback create_callback = |
| + Isolate::ServiceCreateCallback(); |
| + if (create_callback == NULL) { |
| + return NULL; |
| + } |
| + if (Dart_CurrentIsolate() != NULL) { |
| + // Clear current isolate. |
| + Dart_ExitIsolate(); |
| + } |
| + char* error = NULL; |
| + Dart_Isolate isolate = create_callback(callback_data, &error); |
| + if (isolate == NULL) { |
| + printf("Service Isolate Error: %s\n", error); |
| + return NULL; |
| + } |
| + Dart_EnterIsolate(isolate); |
| + Dart_EnterScope(); |
| + Dart_Handle result; |
| + Dart_Handle root_library = Dart_RootLibrary(); |
| + SHUTDOWN_ON_ERROR(root_library); |
| + ASSERT(root_library == Dart_Null()); |
| + // Retrieve the embedder default library tag handler. |
| + default_handler_ = reinterpret_cast<Isolate*>(isolate)->library_tag_handler(); |
| + ASSERT(default_handler_ != NULL); |
| + // Temporarily install our own. |
| + Dart_SetLibraryTagHandler(LibraryTagHandler); |
| + // Load VM service library. |
| + Dart_Handle library; |
| + { |
| + const char* resource = NULL; |
| + const char* path = "/vmservice.dart"; |
| + int r = Resources::ResourceLookup(path, &resource); |
| + ASSERT(r != Resources::kNoSuchInstance); |
| + ASSERT(resource != NULL); |
| + Dart_Handle url = Dart_NewStringFromCString("dart:vmservice"); |
| + SHUTDOWN_ON_ERROR(url); |
| + Dart_Handle source = Dart_NewStringFromCString(resource); |
| + SHUTDOWN_ON_ERROR(source); |
| + library = Dart_LoadLibrary(url, source); |
| + SHUTDOWN_ON_ERROR(library); |
| + result = Dart_SetNativeResolver(library, VmServiceNativeResolver); |
| + SHUTDOWN_ON_ERROR(result); |
| + } |
| + // Install embedder default library tag handler again. |
| + Dart_SetLibraryTagHandler(default_handler_); |
| + default_handler_ = NULL; |
| + // Boot the service. |
| + { |
| + result = Dart_Invoke(library, Dart_NewStringFromCString("boot"), 0, NULL); |
| + SHUTDOWN_ON_ERROR(result); |
| + HANDLESCOPE(Isolate::Current()); |
| + const Object& unwrapped_rp = Object::Handle(Api::UnwrapHandle(result)); |
| + const Instance& rp = Instance::Cast(unwrapped_rp); |
| + // Extract RawReceivePort port id. |
| + const Object& rp_id_obj = Object::Handle(DartLibraryCalls::PortGetId(rp)); |
| + if (rp_id_obj.IsError()) { |
| + const Error& error = Error::Cast(rp_id_obj); |
| + SHUTDOWN(error.ToErrorCString()); |
| + } |
| + ASSERT(rp_id_obj.IsSmi() || rp_id_obj.IsMint()); |
| + Integer& id = Integer::Handle(); |
| + id ^= rp_id_obj.raw(); |
|
siva
2014/01/10 00:01:54
Since you are asserting that rp_id_obj is a Smi or
Cutch
2014/01/10 21:01:42
Done.
|
| + port_ = static_cast<Dart_Port>(id.AsInt64Value()); |
| + } |
| + Dart_ExitScope(); |
| + Dart_ExitIsolate(); |
| + service_isolate_ = reinterpret_cast<Isolate*>(isolate); |
| + return service_isolate_; |
| +} |
| + |
| + |
| +// 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 Dart_Handle MakeServiceControlMessage(Dart_Port port_id, intptr_t code, |
| + Dart_Handle name) { |
| + Dart_Handle result; |
| + Dart_Handle list = Dart_NewList(4); |
| + ASSERT(!Dart_IsError(list)); |
| + Dart_Handle code_handle = Dart_NewInteger(code); |
| + ASSERT(!Dart_IsError(code_handle)); |
| + result = Dart_ListSetAt(list, 0, code_handle); |
| + ASSERT(!Dart_IsError(result)); |
| + Dart_Handle port_id_handle = Dart_NewInteger(port_id); |
| + ASSERT(!Dart_IsError(port_id_handle)); |
| + result = Dart_ListSetAt(list, 1, port_id_handle); |
| + ASSERT(!Dart_IsError(result)); |
| + Dart_Handle sendPort = Dart_NewSendPort(port_id); |
| + ASSERT(!Dart_IsError(sendPort)); |
| + result = Dart_ListSetAt(list, 2, sendPort); |
| + ASSERT(!Dart_IsError(result)); |
| + result = Dart_ListSetAt(list, 3, name); |
| + ASSERT(!Dart_IsError(result)); |
| + return list; |
| +} |
| + |
| + |
| +bool Service::SendIsolateStartupMessage() { |
| + if (!IsRunning()) { |
| + return false; |
| + } |
| + Isolate* isolate = Isolate::Current(); |
| + ASSERT(isolate != NULL); |
| + HANDLESCOPE(isolate); |
| + Dart_EnterScope(); |
| + Dart_Handle name = Api::NewHandle(isolate, String::New(isolate->name())); |
| + ASSERT(!Dart_IsError(name)); |
| + Dart_Handle list = |
| + MakeServiceControlMessage(Dart_GetMainPortId(), |
| + VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID, |
| + name); |
| + ASSERT(!Dart_IsError(list)); |
| + bool r = Dart_Post(port_, list); |
| + Dart_ExitScope(); |
| + return r; |
| +} |
| + |
| + |
| +bool Service::SendIsolateShutdownMessage() { |
| + if (!IsRunning()) { |
| + return false; |
| + } |
| + Isolate* isolate = Isolate::Current(); |
| + ASSERT(isolate != NULL); |
| + HANDLESCOPE(isolate); |
| + Dart_EnterScope(); |
| + Dart_Handle list = |
| + MakeServiceControlMessage(Dart_GetMainPortId(), |
| + VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID, |
| + Dart_Null()); |
| + ASSERT(!Dart_IsError(list)); |
| + bool r = Dart_Post(port_, list); |
| + Dart_ExitScope(); |
| + return r; |
| +} |
| + |
| + |
| +bool Service::IsRunning() { |
| + return port_ != ILLEGAL_PORT; |
| +} |
| + |
| + |
| +Dart_Handle Service::GetSource(const char* name) { |
| + ASSERT(name != NULL); |
| + int i = 0; |
| + while (true) { |
| + const char* path = Resources::get_resource_path(i); |
| + if (path == NULL) { |
| + break; |
| + } |
| + ASSERT(*path != '\0'); |
| + // Skip the '/'. |
| + path++; |
| + if (strcmp(name, path) == 0) { |
| + return Dart_NewStringFromCString(Resources::get_resource_resource(i)); |
| + } |
| + i++; |
| + } |
| + return Dart_Null(); |
| +} |
| + |
| + |
| +Dart_Handle Service::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"); |
| + } |
| + const char* url_string = NULL; |
| + Dart_Handle result = Dart_StringToCString(url, &url_string); |
| + if (Dart_IsError(result)) { |
| + return result; |
| + } |
| + Dart_Handle library_url = Dart_LibraryUrl(library); |
| + const char* library_url_string = NULL; |
| + result = Dart_StringToCString(library_url, &library_url_string); |
| + if (Dart_IsError(result)) { |
| + return result; |
| + } |
|
siva
2014/01/10 00:01:54
What is the conversion to C string library_url_str
Cutch
2014/01/10 21:01:42
Done.
|
| + if (tag == Dart_kImportTag) { |
| + // Embedder handles all requests for external libraries. |
| + ASSERT(default_handler_ != NULL); |
| + return default_handler_(tag, library, url); |
| + } |
| + ASSERT((tag == Dart_kSourceTag) || (tag == Dart_kCanonicalizeUrl)); |
| + if (tag == Dart_kCanonicalizeUrl) { |
| + // url is already canonicalized. |
| + return url; |
| + } |
| + Dart_Handle source = GetSource(url_string); |
| + if (Dart_IsError(source)) { |
| + return source; |
| + } |
| + return Dart_LoadSource(library, url, source); |
| +} |
| + |
| + |
| +typedef void (*ServiceMessageHandler)(Isolate* isolate, JSONStream* stream); |
| + |
| +struct ServiceMessageHandlerEntry { |
| + const char* command; |
| + ServiceMessageHandler handler; |
| +}; |
| + |
| +static ServiceMessageHandler FindServiceMessageHandler(const char* command); |
| + |
| static void PostReply(const String& reply, const Instance& reply_port) { |
| const Object& id_obj = Object::Handle( |
| DartLibraryCalls::PortGetId(reply_port)); |