Index: runtime/vm/service.cc |
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc |
index fe8aaa1b197084bb3e0518bcb6461d126f602382..8d2c49488e03ee2664f55d5a7786289ff6c968c0 100644 |
--- a/runtime/vm/service.cc |
+++ b/runtime/vm/service.cc |
@@ -4,28 +4,100 @@ |
#include "vm/service.h" |
+#include "include/dart_api.h" |
+ |
+#include "vm/compiler.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" |
+#include "vm/symbols.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 = 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) { |
@@ -34,6 +106,303 @@ 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; |
+ } |
+ } |
+ return NULL; |
+} |
+ |
+ |
+Isolate* Service::service_isolate_ = NULL; |
+Dart_LibraryTagHandler Service::default_handler_ = NULL; |
+Dart_Port Service::port_ = ILLEGAL_PORT; |
+ |
+static Dart_Port ExtractPort(Dart_Handle receivePort) { |
+ HANDLESCOPE(Isolate::Current()); |
+ const Object& unwrapped_rp = Object::Handle(Api::UnwrapHandle(receivePort)); |
+ 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()) { |
+ return ILLEGAL_PORT; |
+ } |
+ ASSERT(rp_id_obj.IsSmi() || rp_id_obj.IsMint()); |
+ const Integer& id = Integer::Cast(rp_id_obj); |
+ return static_cast<Dart_Port>(id.AsInt64Value()); |
+} |
+ |
+ |
+Isolate* Service::GetServiceIsolate(void* callback_data) { |
+ if (service_isolate_ != NULL) { |
+ // Already initialized, return service isolate. |
+ return service_isolate_; |
+ } |
+ Dart_ServiceIsolateCreateCalback create_callback = |
+ Isolate::ServiceCreateCallback(); |
+ if (create_callback == NULL) { |
+ return NULL; |
+ } |
+ Isolate::SetCurrent(NULL); |
+ char* error = NULL; |
+ Isolate* isolate = reinterpret_cast<Isolate*>( |
+ create_callback(callback_data, &error)); |
+ if (isolate == NULL) { |
+ return NULL; |
+ } |
+ Isolate::SetCurrent(isolate); |
+ { |
+ // Install the dart:vmservice library. |
+ StackZone zone(isolate); |
+ HANDLESCOPE(isolate); |
+ Library& library = |
+ Library::Handle(isolate, isolate->object_store()->root_library()); |
+ // Isolate is empty. |
+ ASSERT(library.IsNull()); |
+ // Grab embedder tag handler. |
+ default_handler_ = isolate->library_tag_handler(); |
+ ASSERT(default_handler_ != NULL); |
+ // Temporarily install our own. |
+ isolate->set_library_tag_handler(LibraryTagHandler); |
+ // Get script resource. |
+ 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 String& url_str = String::Handle(Symbols::DartVMService().raw()); |
+ library ^= Library::LookupLibrary(url_str); |
+ ASSERT(library.IsNull()); |
+ // Setup library. |
+ library = Library::New(url_str); |
+ library.Register(); |
+ const Script& script = Script::Handle( |
+ isolate, Script::New(url_str, source_str, RawScript::kLibraryTag)); |
+ library.SetLoadInProgress(); |
+ Dart_EnterScope(); // Need to enter scope for tag handler. |
+ const Error& error = Error::Handle(isolate, |
+ Compiler::Compile(library, script)); |
+ ASSERT(error.IsNull()); |
+ Dart_ExitScope(); |
+ library.SetLoaded(); |
+ // Install embedder default library tag handler again. |
+ isolate->set_library_tag_handler(default_handler_); |
+ default_handler_ = NULL; |
+ library.set_native_entry_resolver(VmServiceNativeResolver); |
+ } |
+ { |
+ // Boot the dart:vmservice library. |
+ Dart_EnterScope(); |
+ Dart_Handle result; |
+ Dart_Handle url_str = |
+ Dart_NewStringFromCString(Symbols::Name(Symbols::kDartVMServiceId)); |
+ Dart_Handle library = Dart_LookupLibrary(url_str); |
+ ASSERT(Dart_IsLibrary(library)); |
+ result = Dart_Invoke(library, Dart_NewStringFromCString("boot"), 0, NULL); |
+ ASSERT(!Dart_IsError(result)); |
+ port_ = ExtractPort(result); |
+ ASSERT(port_ != ILLEGAL_PORT); |
+ Dart_ExitScope(); |
+ } |
+ Isolate::SetCurrent(NULL); |
+ 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 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 Object& send_port = Object::Handle( |
+ DartLibraryCalls::NewSendPort(port_id)); |
+ ASSERT(!send_port.IsNull()); |
+ list.SetAt(0, code_int); |
+ list.SetAt(1, port_int); |
+ list.SetAt(2, send_port); |
+ list.SetAt(3, name); |
+ return list.raw(); |
+} |
+ |
+ |
+bool Service::SendIsolateStartupMessage() { |
+ if (!IsRunning()) { |
+ return false; |
+ } |
+ Isolate* isolate = Isolate::Current(); |
+ 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); |
+ writer.WriteMessage(list); |
+ intptr_t len = writer.BytesWritten(); |
+ return PortMap::PostMessage( |
+ new Message(port_, data, len, Message::kNormalPriority)); |
+} |
+ |
+ |
+bool Service::SendIsolateShutdownMessage() { |
+ if (!IsRunning()) { |
+ return false; |
+ } |
+ Isolate* isolate = Isolate::Current(); |
+ ASSERT(isolate != NULL); |
+ HANDLESCOPE(isolate); |
+ const Array& list = Array::Handle( |
+ MakeServiceControlMessage(Dart_GetMainPortId(), |
+ VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID, |
+ String::Handle(String::null()))); |
+ ASSERT(!list.IsNull()); |
+ uint8_t* data = NULL; |
+ MessageWriter writer(&data, &allocator); |
+ writer.WriteMessage(list); |
+ intptr_t len = writer.BytesWritten(); |
+ return PortMap::PostMessage( |
+ new Message(port_, data, len, Message::kNormalPriority)); |
+} |
+ |
+ |
+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::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 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; |
+ } |
+ 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)); |