Index: runtime/bin/vmservice_impl.cc |
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc |
index 9e738cdfe883e783fea8ac8d966ababec00cf923..b35c67e00ed72a974a17a9be38bdfd6fb11efb87 100644 |
--- a/runtime/bin/vmservice_impl.cc |
+++ b/runtime/bin/vmservice_impl.cc |
@@ -9,25 +9,11 @@ |
#include "bin/builtin.h" |
#include "bin/dartutils.h" |
#include "bin/isolate_data.h" |
-#include "bin/resources.h" |
#include "bin/thread.h" |
-#include "vm/dart_api_impl.h" |
-#include "vm/dart_entry.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/port.h" |
-#include "vm/snapshot.h" |
- |
namespace dart { |
namespace bin { |
-// snapshot_buffer points to a snapshot if we link in a snapshot otherwise |
-// it is initialized to NULL. |
-extern const uint8_t* snapshot_buffer; |
#define RETURN_ERROR_HANDLE(handle) \ |
if (Dart_IsError(handle)) { \ |
return handle; \ |
@@ -41,143 +27,110 @@ extern const uint8_t* snapshot_buffer; |
return false; \ |
} |
-#define kLibraryResourceNamePrefix "/vmservice" |
-static const char* kVMServiceIOLibraryScriptResourceName = |
- kLibraryResourceNamePrefix "/vmservice_io.dart"; |
-static const char* kVMServiceLibraryName = |
- kLibraryResourceNamePrefix "/vmservice.dart"; |
- |
+#define kLibrarySourceNamePrefix "/vmservice" |
+static const char* kVMServiceIOLibraryScriptResourceName = "vmservice_io.dart"; |
#define kClientResourceNamePrefix "/vmservice/client/deployed/web" |
-Dart_Isolate VmService::isolate_ = NULL; |
-Dart_Port VmService::port_ = ILLEGAL_PORT; |
-dart::Monitor* VmService::monitor_ = NULL; |
-const char* VmService::error_msg_ = NULL; |
+struct ResourcesEntry { |
+ const char* path_; |
+ const char* resource_; |
+ int length_; |
+}; |
-// These must be kept in sync with vmservice/constants.dart |
-#define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1 |
-#define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2 |
+extern ResourcesEntry __service_bin_resources_[]; |
+ |
+class Resources { |
+ public: |
+ static const int kNoSuchInstance = -1; |
+ static int ResourceLookup(const char* path, const char** resource) { |
+ ResourcesEntry* table = ResourcesTable(); |
+ 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_; |
+ } |
+ |
+ private: |
+ static ResourcesEntry* At(int idx) { |
+ ASSERT(idx >= 0); |
+ ResourcesEntry* table = ResourcesTable(); |
+ for (int i = 0; table[i].path_ != NULL; i++) { |
+ if (idx == i) { |
+ return &table[i]; |
+ } |
+ } |
+ return NULL; |
+ } |
+ static ResourcesEntry* ResourcesTable() { |
+ return &__service_bin_resources_[0]; |
+ } |
-static Dart_NativeFunction VmServiceNativeResolver(Dart_Handle name, |
- int num_arguments, |
- bool* auto_setup_scope); |
+ DISALLOW_ALLOCATION(); |
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Resources); |
+}; |
+const char* VmService::error_msg_ = NULL; |
bool VmService::Start(intptr_t server_port) { |
- monitor_ = new dart::Monitor(); |
- ASSERT(monitor_ != NULL); |
- error_msg_ = NULL; |
- |
- |
- { |
- // Take lock before spawning new thread. |
- MonitorLocker ml(monitor_); |
- // Spawn new thread. |
- dart::Thread::Start(ThreadMain, server_port); |
- // Wait until service is running on spawned thread. |
- ml.Wait(); |
+ bool r = _Start(server_port); |
+ if (!r) { |
+ return r; |
} |
- return port_ != ILLEGAL_PORT; |
+ // Start processing messages in a new thread. |
+ dart::Thread::Start(ThreadMain, NULL); |
+ return true; |
} |
bool VmService::_Start(intptr_t server_port) { |
- ASSERT(isolate_ == NULL); |
- char* error = NULL; |
- const char* script_uri = "vmservice:"; |
- IsolateData* isolate_data = new IsolateData(script_uri); |
- isolate_ = Dart_CreateIsolate(script_uri, "main", snapshot_buffer, |
- isolate_data, |
- &error); |
- if (isolate_ == NULL) { |
- error_msg_ = error; |
+ ASSERT(Dart_CurrentIsolate() == NULL); |
+ Dart_Isolate isolate = Dart_GetServiceIsolate(NULL); |
+ if (isolate == NULL) { |
+ error_msg_ = "Internal error."; |
return false; |
} |
- |
+ Dart_EnterIsolate(isolate); |
Dart_EnterScope(); |
- |
- if (snapshot_buffer != NULL) { |
- // Setup the native resolver as the snapshot does not carry it. |
- Builtin::SetNativeResolver(Builtin::kBuiltinLibrary); |
- Builtin::SetNativeResolver(Builtin::kIOLibrary); |
- } |
- |
- // Set up the library tag handler for this isolate. |
- Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler); |
- SHUTDOWN_ON_ERROR(result); |
- |
- // Load the specified application script into the newly created isolate. |
- |
- // Prepare builtin and its dependent libraries for use to resolve URIs. |
- // The builtin library is part of the core snapshot and would already be |
- // available here in the case of script snapshot loading. |
- Dart_Handle builtin_lib = |
- Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary); |
- SHUTDOWN_ON_ERROR(builtin_lib); |
- |
- // Prepare for script loading by setting up the 'print' and 'timer' |
- // closures and setting up 'package root' for URI resolution. |
- result = DartUtils::PrepareForScriptLoading("", builtin_lib); |
- SHUTDOWN_ON_ERROR(result); |
- |
- { |
- // Load source into service isolate. |
- Dart_Handle library = LoadScript(kVMServiceIOLibraryScriptResourceName); |
- SHUTDOWN_ON_ERROR(library); |
- } |
- |
- // Make the isolate runnable so that it is ready to handle messages. |
+ // Install our own library tag handler. |
+ Dart_SetLibraryTagHandler(LibraryTagHandler); |
+ Dart_Handle result; |
+ Dart_Handle library = LoadScript(kVMServiceIOLibraryScriptResourceName); |
+ // Expect a library. |
+ ASSERT(library != Dart_Null()); |
+ SHUTDOWN_ON_ERROR(library); |
Dart_ExitScope(); |
Dart_ExitIsolate(); |
- |
- bool retval = Dart_IsolateMakeRunnable(isolate_); |
+ bool retval = Dart_IsolateMakeRunnable(isolate); |
if (!retval) { |
- Dart_EnterIsolate(isolate_); |
+ Dart_EnterIsolate(isolate); |
Dart_ShutdownIsolate(); |
error_msg_ = "Invalid isolate state - Unable to make it runnable."; |
return false; |
} |
- Dart_EnterIsolate(isolate_); |
+ Dart_EnterIsolate(isolate); |
Dart_EnterScope(); |
- |
- |
- Dart_Handle library = Dart_RootLibrary(); |
+ library = Dart_RootLibrary(); |
// Set requested TCP port. |
DartUtils::SetIntegerField(library, "_port", server_port); |
result = Dart_Invoke(library, DartUtils::NewString("main"), 0, NULL); |
SHUTDOWN_ON_ERROR(result); |
- |
- // Retrieve the ReceivePort that the service is waiting on. The _receivePort |
- // variable is setup in the call to main. |
- Dart_Handle receivePort = Dart_GetField(library, |
- DartUtils::NewString("_receivePort")); |
- SHUTDOWN_ON_ERROR(receivePort); |
- |
- { |
- // Extract the Dart_Port from the receive port. |
- HANDLESCOPE(Isolate::Current()); |
- const Object& unwrapped_rp = Object::Handle(Api::UnwrapHandle(receivePort)); |
- const Instance& rp = Instance::Cast(unwrapped_rp); |
- // Extract ReceivePort 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); |
- error_msg_ = strdup(error.ToErrorCString()); |
- Dart_ExitScope(); |
- Dart_ShutdownIsolate(); |
- return false; |
- } |
- ASSERT(rp_id_obj.IsSmi() || rp_id_obj.IsMint()); |
- Integer& id = Integer::Handle(); |
- id ^= rp_id_obj.raw(); |
- port_ = static_cast<Dart_Port>(id.AsInt64Value()); |
- } |
- |
- Dart_Handle library_name = Dart_NewStringFromCString(kVMServiceLibraryName); |
- library = Dart_LookupLibrary(library_name); |
- SHUTDOWN_ON_ERROR(library); |
+ // Load resources. |
result = LoadResources(library); |
SHUTDOWN_ON_ERROR(result); |
@@ -188,36 +141,24 @@ bool VmService::_Start(intptr_t server_port) { |
} |
-void VmService::_Stop() { |
- port_ = ILLEGAL_PORT; |
-} |
- |
- |
const char* VmService::GetErrorMessage() { |
return error_msg_ == NULL ? "No error." : error_msg_; |
} |
-Dart_Port VmService::port() { |
- return port_; |
-} |
- |
- |
-bool VmService::IsRunning() { |
- return port_ != ILLEGAL_PORT; |
-} |
- |
- |
Dart_Handle VmService::GetSource(const char* name) { |
+ const intptr_t kBufferSize = 512; |
+ char buffer[kBufferSize]; |
+ snprintf(&buffer[0], kBufferSize-1, "%s/%s", kLibrarySourceNamePrefix, name); |
const char* vmservice_source = NULL; |
- int r = Resources::ResourceLookup(name, &vmservice_source); |
+ int r = Resources::ResourceLookup(buffer, &vmservice_source); |
ASSERT(r != Resources::kNoSuchInstance); |
return Dart_NewStringFromCString(vmservice_source); |
} |
Dart_Handle VmService::LoadScript(const char* name) { |
- Dart_Handle url = Dart_NewStringFromCString(name); |
+ Dart_Handle url = Dart_NewStringFromCString("dart:vmservice_io"); |
Dart_Handle source = GetSource(name); |
return Dart_LoadScript(url, source, 0, 0); |
} |
@@ -230,18 +171,6 @@ Dart_Handle VmService::LoadSource(Dart_Handle library, const char* name) { |
} |
-Dart_Handle VmService::LoadSources(Dart_Handle library, const char* names[]) { |
- Dart_Handle result = Dart_Null(); |
- for (int i = 0; names[i] != NULL; i++) { |
- result = LoadSource(library, names[i]); |
- if (Dart_IsError(result)) { |
- break; |
- } |
- } |
- return result; |
-} |
- |
- |
Dart_Handle VmService::LoadResource(Dart_Handle library, |
const char* resource_name, |
const char* prefix) { |
@@ -285,8 +214,8 @@ Dart_Handle VmService::LoadResource(Dart_Handle library, |
Dart_Handle VmService::LoadResources(Dart_Handle library) { |
Dart_Handle result = Dart_Null(); |
intptr_t prefixLen = strlen(kClientResourceNamePrefix); |
- for (intptr_t i = 0; i < Resources::get_resource_count(); i++) { |
- const char* path = Resources::get_resource_path(i); |
+ for (intptr_t i = 0; Resources::Path(i) != NULL; i++) { |
+ const char* path = Resources::Path(i); |
if (!strncmp(path, kClientResourceNamePrefix, prefixLen)) { |
result = LoadResource(library, path, kClientResourceNamePrefix); |
if (Dart_IsError(result)) { |
@@ -298,19 +227,6 @@ Dart_Handle VmService::LoadResources(Dart_Handle library) { |
} |
-static bool IsVMServiceURL(const char* url) { |
- static const intptr_t kLibraryResourceNamePrefixLen = |
- strlen(kLibraryResourceNamePrefix); |
- return 0 == strncmp(kLibraryResourceNamePrefix, url, |
- kLibraryResourceNamePrefixLen); |
-} |
- |
- |
-static bool IsVMServiceLibrary(const char* url) { |
- return 0 == strcmp(kVMServiceLibraryName, url); |
-} |
- |
- |
Dart_Handle VmService::LibraryTagHandler(Dart_LibraryTag tag, |
Dart_Handle library, |
Dart_Handle url) { |
@@ -331,224 +247,37 @@ Dart_Handle VmService::LibraryTagHandler(Dart_LibraryTag tag, |
if (Dart_IsError(result)) { |
return result; |
} |
- bool is_vm_service_url = IsVMServiceURL(url_string); |
- if (!is_vm_service_url) { |
- // Pass to DartUtils. |
+ if (tag == Dart_kImportTag) { |
+ // Embedder handles all requests for external libraries. |
return DartUtils::LibraryTagHandler(tag, library, url); |
} |
- switch (tag) { |
- case Dart_kCanonicalizeUrl: |
- // The URL is already canonicalized. |
- return url; |
- break; |
- case Dart_kImportTag: { |
- Dart_Handle source = GetSource(url_string); |
- if (Dart_IsError(source)) { |
- return source; |
- } |
- Dart_Handle lib = Dart_LoadLibrary(url, source); |
- if (Dart_IsError(lib)) { |
- return lib; |
- } |
- if (IsVMServiceLibrary(url_string)) { |
- // Install native resolver for this library. |
- result = Dart_SetNativeResolver(lib, VmServiceNativeResolver); |
- if (Dart_IsError(result)) { |
- return result; |
- } |
- } |
- return lib; |
- } |
- break; |
- case Dart_kSourceTag: { |
- Dart_Handle source = GetSource(url_string); |
- if (Dart_IsError(source)) { |
- return source; |
- } |
- return Dart_LoadSource(library, url, source); |
- } |
- break; |
- default: |
- UNIMPLEMENTED(); |
- break; |
+ ASSERT((tag == Dart_kSourceTag) || (tag == Dart_kCanonicalizeUrl)); |
+ if (tag == Dart_kCanonicalizeUrl) { |
+ // url is already canonicalized. |
+ return url; |
} |
- UNREACHABLE(); |
- return result; |
+ Dart_Handle source = GetSource(url_string); |
+ if (Dart_IsError(source)) { |
+ return source; |
+ } |
+ return Dart_LoadSource(library, url, source); |
} |
void VmService::ThreadMain(uword parameters) { |
ASSERT(Dart_CurrentIsolate() == NULL); |
- ASSERT(isolate_ == NULL); |
- |
- intptr_t server_port = static_cast<intptr_t>(parameters); |
- ASSERT(server_port >= 0); |
- |
- // Lock scope. |
- { |
- MonitorLocker ml(monitor_); |
- bool r = _Start(server_port); |
- if (!r) { |
- port_ = ILLEGAL_PORT; |
- monitor_->Notify(); |
- return; |
- } |
- |
- Dart_EnterIsolate(isolate_); |
- Dart_EnterScope(); |
- |
- Dart_Handle receievePort = Dart_GetReceivePort(port_); |
- ASSERT(!Dart_IsError(receievePort)); |
- monitor_->Notify(); |
- } |
- |
- // Keep handling messages until the last active receive port is closed. |
+ Dart_Isolate service_isolate = Dart_GetServiceIsolate(NULL); |
+ Dart_EnterIsolate(service_isolate); |
+ Dart_EnterScope(); |
Dart_Handle result = Dart_RunLoop(); |
if (Dart_IsError(result)) { |
- printf("VmService has exited with an error:\n%s\n", Dart_GetError(result)); |
+ printf("Service exited with an error:\n%s\n", Dart_GetError(result)); |
} |
- |
- _Stop(); |
- |
Dart_ExitScope(); |
Dart_ExitIsolate(); |
} |
-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 VmService::SendIsolateStartupMessage() { |
- if (!IsRunning()) { |
- return false; |
- } |
- Isolate* isolate = Isolate::Current(); |
- ASSERT(isolate != NULL); |
- HANDLESCOPE(isolate); |
- 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)); |
- return Dart_Post(port_, list); |
-} |
- |
- |
-bool VmService::SendIsolateShutdownMessage() { |
- if (!IsRunning()) { |
- return false; |
- } |
- Isolate* isolate = Isolate::Current(); |
- ASSERT(isolate != NULL); |
- HANDLESCOPE(isolate); |
- Dart_Handle list = |
- MakeServiceControlMessage(Dart_GetMainPortId(), |
- VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID, |
- Dart_Null()); |
- ASSERT(!Dart_IsError(list)); |
- return Dart_Post(port_, list); |
-} |
- |
- |
-void VmService::VmServiceShutdownCallback(void* callback_data) { |
- ASSERT(Dart_CurrentIsolate() != NULL); |
- Dart_EnterScope(); |
- VmService::SendIsolateShutdownMessage(); |
- Dart_ExitScope(); |
-} |
- |
- |
-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 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; |
-} |
} // namespace bin |
} // namespace dart |