Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(304)

Unified Diff: Source/bindings/dart/DartService.cpp

Issue 104433004: Enable VM service inside Dartium Renderer processes (Closed) Base URL: svn://svn.chromium.org/multivm/branches/1650/blink
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/bindings/dart/DartService.cpp
diff --git a/Source/bindings/dart/DartService.cpp b/Source/bindings/dart/DartService.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..95090f338de37cd909a31cf7f52c7b29a7bd2919
--- /dev/null
+++ b/Source/bindings/dart/DartService.cpp
@@ -0,0 +1,532 @@
+// Copyright (c) 2013, 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 "config.h"
+
+#include "bindings/dart/DartService.h"
+
+#include "DartApplicationLoader.h"
+#include "DartController.h"
+#include "DartDocument.h"
+#include "DartServiceInternal.h"
+#include "DartUtilities.h"
+#include "DartWindow.h"
+
+
+// These must be kept in sync with vmservice/constants.dart
+// TODO(johnmccutchan): Put these constants in one place.
+#define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1
+#define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2
+
+// The following Resources class is used in combination with a generated
+// source file that expects underscores in names. The NOLINT tags are
+// used to suppress the errors.
+// TODO(johnmccutchan): Move VM service source into runtime and out of bin.
+namespace dart {
+namespace bin {
+class Resources {
+public:
+ static const int kNoSuchInstance = -1;
+
+ static int ResourceLookup(const char* path, const char** resource)
+ {
+ for (int i = 0; i < get_resource_count(); i++) {
+ resource_map_entry* entry = get_resource(i);
+ if (!strcmp(path, entry->path_)) {
+ *resource = entry->resource_;
+ ASSERT(entry->length_ > 0);
+ return entry->length_;
+ }
+ }
+ return kNoSuchInstance;
+ }
+
+ static intptr_t get_resource_count() // NOLINT.
+ {
+ return builtin_resources_count_;
+ }
+
+ static const char* get_resource_path(intptr_t i) // NOLINT.
+ {
+ return get_resource(i)->path_;
+ }
+
+private:
+ struct resource_map_entry { // NOLINT.
+ const char* path_; // NOLINT.
+ const char* resource_; // NOLINT.
+ intptr_t length_; // NOLINT.
+ };
+
+ // These fields are generated by resources_gen.cc.
+ static resource_map_entry builtin_resources_[]; // NOLINT.
+ static const intptr_t builtin_resources_count_; // NOLINT.
+
+ static resource_map_entry* get_resource(int i) // NOLINT.
+ {
+ ASSERT(i >= 0 && i < builtin_resources_count_);
+ return &builtin_resources_[i];
+ }
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Resources);
+};
+
+}
+}
+namespace WebCore {
+
+#define SHUTDOWN_ON_ERROR(handle) \
+ if (Dart_IsError(handle)) { \
+ m_errorMsg = strdup(Dart_GetError(handle)); \
+ goto error; \
+ }
+
+static const char* kScriptUri = "vmservice:";
+#define kLibraryResourceNamePrefix "/vmservice"
+static const char* kVMServiceDartiumLibraryScriptResourceName =
+ kLibraryResourceNamePrefix "/vmservice_dartium.dart";
+static const char* kVMServiceLibraryName =
+ kLibraryResourceNamePrefix "/vmservice.dart";
+
+
+Dart_Isolate DartService::m_isolate = 0;
+Dart_Port DartService::m_port = ILLEGAL_PORT;
+Dart_Port DartService::m_requestPort = ILLEGAL_PORT;
+Dart_Port DartService::m_nativePort = ILLEGAL_PORT;
+const char* DartService::m_errorMsg = 0;
+
+
+bool DartService::Start(Document* document)
+{
+ if (m_isolate) {
+ // Already running.
+ return true;
+ }
+ {
+ char* error = 0;
+
+ m_isolate = DartController::createIsolate(kScriptUri, "main", document, true, &error);
+ if (!m_isolate) {
+ m_errorMsg = error;
+ return false;
Jacob 2013/12/05 19:31:31 Use Scope auto close opbjects here and elsewhere t
Cutch 2013/12/05 22:48:15 Everywhere but the startup and shutdown of the VM
+ }
+
+ Dart_EnterScope();
+ // Set up the library tag handler for this isolate.
+ Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler);
+ SHUTDOWN_ON_ERROR(result);
+
+ {
+ // Load source into service isolate.
+ Dart_Handle library =
+ LoadScript(kVMServiceDartiumLibraryScriptResourceName);
+ SHUTDOWN_ON_ERROR(library);
+ }
+ // Make the isolate runnable so that it is ready to handle messages.
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+
+ bool retval = Dart_IsolateMakeRunnable(m_isolate);
+ if (!retval) {
+ Dart_EnterIsolate(m_isolate);
+ Dart_ShutdownIsolate();
+ m_errorMsg = "Invalid isolate state - Unable to make it runnable.";
+ return false;
+ }
+
+ Dart_EnterIsolate(m_isolate);
+ Dart_EnterScope();
+
+ // Invoke main.
+ Dart_Handle library = Dart_RootLibrary();
+ Dart_Handle entryFunctioName = Dart_NewStringFromCString("main");
+ SHUTDOWN_ON_ERROR(entryFunctioName);
+ result = Dart_Invoke(library, entryFunctioName, 0, 0);
+ 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 portFieldName = Dart_NewStringFromCString("_receivePort");
+ SHUTDOWN_ON_ERROR(portFieldName);
+ Dart_Handle receivePort = Dart_GetField(library, portFieldName);
+ SHUTDOWN_ON_ERROR(receivePort);
+
+ m_port = DartServiceInternal::GetPortIdFromPort(receivePort);
+ if (m_port == ILLEGAL_PORT) {
+ Dart_ExitScope();
+ Dart_ShutdownIsolate();
+ m_errorMsg = "Invalid isolate state - Unable to get receivePort";
+ return false;
+ }
+
+ {
+ // Retrieve the ReceivePort that the service is waiting on. The _receivePort
+ // variable is setup in the call to main.
+ Dart_Handle portFieldName = Dart_NewStringFromCString("_requestPort");
+ SHUTDOWN_ON_ERROR(portFieldName);
+ Dart_Handle receivePort = Dart_GetField(library, portFieldName);
+ SHUTDOWN_ON_ERROR(receivePort);
+ m_requestPort = DartServiceInternal::GetPortIdFromPort(receivePort);
+ ASSERT(m_requestPort != ILLEGAL_PORT);
+ }
+
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+ SetupNativePort();
+ return true;
+ }
+error:
+ Dart_ExitScope();
+ Dart_ShutdownIsolate();
+ m_isolate = 0;
+ m_port = ILLEGAL_PORT;
+ m_requestPort = ILLEGAL_PORT;
+ return false;
+}
+
+
+bool DartService::Stop()
+{
Jacob 2013/12/05 19:31:31 remove return values that provide no value.
+ if (!m_isolate) {
+ // Already shutdown.
+ return true;
+ }
+ ShutdownNativePort();
+ m_port = ILLEGAL_PORT;
+ m_requestPort = ILLEGAL_PORT;
+ Dart_Isolate isolate = m_isolate;
+ m_isolate = 0;
+ Dart_EnterIsolate(isolate);
+ DartController::shutdownIsolate(isolate);
+ return true;
+}
+
+
+void DartService::SetupNativePort()
+{
+ if (m_nativePort != ILLEGAL_PORT) {
+ // Already running.
+ return;
+ }
+ const char* nativePortName = "VMServiceNativePort";
+ m_nativePort = Dart_NewNativePort(nativePortName, NativePortMessageHandler, false);
+ ASSERT(m_nativePort != ILLEGAL_PORT);
+}
+
+
+void DartService::ShutdownNativePort()
+{
+ if (m_nativePort == ILLEGAL_PORT) {
+ return;
+ }
+ Dart_CloseNativePort(m_nativePort);
+ m_nativePort = ILLEGAL_PORT;
+}
+
+
+const char* DartService::GetErrorMessage()
+{
+ return m_errorMsg ? m_errorMsg : "No error.";
+}
+
+
+Dart_Port DartService::port()
+{
+ return m_port;
+}
+
+
+bool DartService::IsRunning()
+{
+ return m_port != ILLEGAL_PORT;
+}
+
+
+static Dart_Handle MakeServiceControlMessage(Dart_Port portId, intptr_t code, Dart_Handle name)
+{
+ Dart_Handle result;
+ Dart_Handle list = Dart_NewList(4);
+ ASSERT(!Dart_IsError(list));
+ Dart_Handle codeHandle = Dart_NewInteger(code);
+ ASSERT(!Dart_IsError(codeHandle));
+ result = Dart_ListSetAt(list, 0, codeHandle);
+ ASSERT(!Dart_IsError(result));
+ Dart_Handle portIdHandle = Dart_NewInteger(portId);
+ ASSERT(!Dart_IsError(portIdHandle));
+ result = Dart_ListSetAt(list, 1, portIdHandle);
+ ASSERT(!Dart_IsError(result));
+ Dart_Handle sendPort = Dart_NewSendPort(portId);
+ 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 DartService::SendIsolateStartupMessage()
+{
+ if (!IsRunning()) {
+ return false;
+ }
+ Dart_Handle name = Dart_DebugName();
+ ASSERT(!Dart_IsError(name));
+ Dart_Handle list = MakeServiceControlMessage(Dart_GetMainPortId(), VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID, name);
+ ASSERT(!Dart_IsError(list));
+ return Dart_Post(m_port, list);
+}
+
+
+bool DartService::SendIsolateShutdownMessage()
+{
+ if (!IsRunning())
+ return false;
+ Dart_Handle list = MakeServiceControlMessage(Dart_GetMainPortId(), VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID, Dart_Null());
+ ASSERT(!Dart_IsError(list));
+ return Dart_Post(m_port, list);
+}
+
+
+DartServiceRequest::DartServiceRequest(const char* request)
+{
+ ASSERT(request);
+ m_request = strdup(request);
+ ASSERT(m_request);
+}
+
+DartServiceRequest::~DartServiceRequest()
+{
+ free(m_request);
+}
+
+
+
+// The format of the message is:
+// [send port, request string, address of DartServiceRequest].
+static Dart_Handle MakeServiceRequestMessage(Dart_Port port, DartServiceRequest* request)
+{
+ intptr_t requestAddress = reinterpret_cast<intptr_t>(request);
+ int64_t requestAddress64 = static_cast<int64_t>(requestAddress);
+ Dart_Handle result;
+ Dart_Handle list = Dart_NewList(3);
+ ASSERT(!Dart_IsError(list));
+ Dart_Handle portHandle = Dart_NewSendPort(port);
+ ASSERT(!Dart_IsError(portHandle));
+ Dart_Handle requestHandle = Dart_NewStringFromCString(request->GetRequestString());
+ ASSERT(!Dart_IsError(requestHandle));
+ Dart_Handle addressHandle = Dart_NewInteger(requestAddress64);
+ ASSERT(!Dart_IsError(addressHandle));
+ result = Dart_ListSetAt(list, 0, portHandle);
+ ASSERT(!Dart_IsError(result));
+ result = Dart_ListSetAt(list, 1, requestHandle);
+ ASSERT(!Dart_IsError(result));
+ result = Dart_ListSetAt(list, 2, addressHandle);
+ ASSERT(!Dart_IsError(result));
+ return list;
+}
+
+
+void DartService::MakeServiceRequest(DartServiceRequest* request)
+{
+ // TODO(johnmccutchan): Once the VM service is no longer a DOM isolate,
+ // we must be careful about entering the isolate.
+ DartIsolateScope isolateScope(m_isolate);
+ {
Jacob 2013/12/05 19:31:31 no need for the extra { } here.
Cutch 2013/12/05 22:48:15 Done.
+ DartApiScope apiScope;
+ Dart_Handle message = MakeServiceRequestMessage(m_nativePort, request);
+ Dart_Post(m_requestPort, message);
+ }
+}
+
+
+void DartService::NativePortMessageHandler(Dart_Port destPortId, Dart_CObject* message)
+{
+ // The format of the reply message is:
+ // [response string, address of DartServiceRequest].
+ ASSERT(destPortId == m_nativePort);
+ ASSERT(message->type == Dart_CObject_kArray);
+ ASSERT(message->value.as_array.length == 2);
+ ASSERT(message->value.as_array.values[0]->type == Dart_CObject_kString);
+ intptr_t requestAddress = 0;
+ if (message->value.as_array.values[1]->type == Dart_CObject_kInt32) {
+ requestAddress = static_cast<intptr_t>(message->value.as_array.values[1]->value.as_int32);
+ } else {
+ ASSERT(message->value.as_array.values[1]->type == Dart_CObject_kInt64);
+ requestAddress = static_cast<intptr_t>(message->value.as_array.values[1]->value.as_int64);
+ }
+ ASSERT(request_address);
+ DartServiceRequest* request = reinterpret_cast<DartServiceRequest*>(requestAddress);
+ request->ResponseReady(message->value.as_array.values[0]->value.as_string);
+}
+
+
+Dart_Handle DartService::GetSource(const char* name)
+{
+ const char* vmserviceSource = 0;
+ int r = dart::bin::Resources::ResourceLookup(name, &vmserviceSource);
+ ASSERT(r != dart::bin::Resources::kNoSuchInstance);
+ return Dart_NewStringFromCString(vmserviceSource);
+}
+
+
+Dart_Handle DartService::LoadScript(const char* name)
+{
+ Dart_Handle url = Dart_NewStringFromCString(name);
+ Dart_Handle source = GetSource(name);
+ return Dart_LoadScript(url, source, 0, 0);
+}
+
+
+Dart_Handle DartService::LoadSource(Dart_Handle library, const char* name)
+{
+ Dart_Handle url = Dart_NewStringFromCString(name);
+ Dart_Handle source = GetSource(name);
+ return Dart_LoadSource(library, url, source);
+}
+
+
+Dart_Handle DartService::LoadSources(Dart_Handle library, const char* names[])
+{
+ Dart_Handle result = Dart_Null();
+ for (int i = 0; names[i]; i++) {
+ result = LoadSource(library, names[i]);
+ if (Dart_IsError(result))
+ break;
+ }
+ return result;
+}
+
+
+static bool IsVMServiceURL(const char* url)
+{
+ static const intptr_t kLibraryResourceNamePrefixLen = strlen(kLibraryResourceNamePrefix);
+ return !strncmp(kLibraryResourceNamePrefix, url, kLibraryResourceNamePrefixLen);
+}
+
+
+static bool IsVMServiceLibrary(const char* url)
+{
+ return !strcmp(kVMServiceLibraryName, url);
+}
+
+static bool IsDartLibrary(const char* url)
+{
+ static const char* kDartPrefix = "dart:";
+ static const intptr_t kDartPrefixLen = strlen(kDartPrefix);
+ return !strncmp(kDartPrefix, url, kDartPrefixLen);
+}
+
+static Dart_Handle Canonicalize(const char* url)
+{
+ if (IsVMServiceURL(url)) {
+ // Already canonicalized.
+ return Dart_NewStringFromCString(url);
+ }
+ // FIXME(johnmccutchan): Remove hard coded 1024 character limit.
+ char buffer[1024];
+ snprintf(&buffer[0], sizeof(buffer), "%s/%s", kLibraryResourceNamePrefix, url);
+ return Dart_NewStringFromCString(buffer);
+}
+
+
+Dart_Handle DartService::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* urlString = 0;
+ Dart_Handle result = Dart_StringToCString(url, &urlString);
+ if (Dart_IsError(result))
+ return result;
+ Dart_Handle libraryUrl = Dart_LibraryUrl(library);
+ const char* libraryUrlString = 0;
+ result = Dart_StringToCString(libraryUrl, &libraryUrlString);
+ if (Dart_IsError(result))
+ return result;
+ if (IsDartLibrary(urlString))
+ return DartApplicationLoader::libraryTagHandlerCallback(tag, library, url);
+ switch (tag) {
+ case Dart_kCanonicalizeUrl:
+ return Canonicalize(urlString);
+ break;
+ case Dart_kImportTag: {
+ Dart_Handle source = GetSource(urlString);
+ if (Dart_IsError(source))
+ return source;
+ Dart_Handle lib = Dart_LoadLibrary(url, source);
+ if (Dart_IsError(lib))
+ return lib;
+ if (IsVMServiceLibrary(urlString)) {
+ // Install native resolver for this library.
+ result = Dart_SetNativeResolver(lib, DartService::NativeResolver);
+ if (Dart_IsError(result))
+ return result;
+ }
+ return lib;
+ }
+ break;
+ case Dart_kSourceTag: {
+ Dart_Handle source = GetSource(urlString);
+ if (Dart_IsError(source))
+ return source;
+ return Dart_LoadSource(library, url, source);
+ }
+ break;
+ default:
+ DART_UNIMPLEMENTED();
+ break;
+ }
+ ASSERT_NOT_REACHED();
+ return result;
+}
+
+
+void DartService::VmServiceShutdownCallback(void* callbackData)
+{
+ ASSERT(Dart_CurrentIsolate());
+ Dart_EnterScope();
+ SendIsolateShutdownMessage();
+ Dart_ExitScope();
+}
+
+static void SendServiceMessage(Dart_NativeArguments args)
+{
+ Dart_Handle sp = Dart_GetNativeArgument(args, 0);
+ Dart_Handle rp = Dart_GetNativeArgument(args, 1);
+ Dart_Handle message = Dart_GetNativeArgument(args, 2);
+ DartServiceInternal::PostOOB(sp, rp, message);
+}
+
+
+struct VmServiceNativeEntry {
+ const char* name;
+ int numArguments;
+ Dart_NativeFunction function;
+};
+
+
+static VmServiceNativeEntry VmServiceNativeEntries[] = {
+ {"SendServiceMessage", 3, SendServiceMessage}
+};
+
+
+Dart_NativeFunction DartService::NativeResolver(Dart_Handle name, int numArguments)
+{
+ const char* functionName = 0;
+ Dart_Handle result = Dart_StringToCString(name, &functionName);
+ ASSERT(!Dart_IsError(result));
+ ASSERT(functionName);
+ intptr_t n = sizeof(VmServiceNativeEntries) / sizeof(VmServiceNativeEntries[0]);
+ for (intptr_t i = 0; i < n; i++) {
+ VmServiceNativeEntry entry = VmServiceNativeEntries[i];
+ if (!strcmp(functionName, entry.name) && (numArguments == entry.numArguments)) {
+ return entry.function;
+ }
+ }
+ return 0;
+}
+
+}

Powered by Google App Engine
This is Rietveld 408576698