Chromium Code Reviews| 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..40781112d15df42af9355f410977493ac16974d6 |
| --- /dev/null |
| +++ b/Source/bindings/dart/DartService.cpp |
| @@ -0,0 +1,433 @@ |
| +// 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 |
|
Jacob
2013/12/04 20:39:52
nit: these could be kept in sync automatically by
Cutch
2013/12/04 21:20:50
Done.
|
| +#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. |
| +namespace dart { |
|
Jacob
2013/12/04 20:39:52
having files with the namespace dart::bin
seems st
Cutch
2013/12/04 21:20:50
Added TODO. Moving the namespace requires surgery
|
| +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 RETURN_ERROR_HANDLE(handle) \ |
| + if (Dart_IsError(handle)) { \ |
| + return handle; \ |
| + } |
| + |
| +#define SHUTDOWN_ON_ERROR(handle) \ |
| + if (Dart_IsError(handle)) { \ |
| + m_errorMsg = strdup(Dart_GetError(handle)); \ |
| + Dart_ExitScope(); \ |
| + Dart_ShutdownIsolate(); \ |
| + return false; \ |
| + } |
| + |
| +#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; |
| +const char* DartService::m_errorMsg = 0; |
| + |
| + |
| +bool DartService::Start(Document* document) |
| +{ |
| + ASSERT(!m_isolate); |
| + char* error = 0; |
| + const char* scriptUri = "vmservice:"; |
|
Jacob
2013/12/04 20:39:52
move this constant outside of the method
Cutch
2013/12/04 21:20:50
Done.
|
| + m_isolate = DartController::createIsolate(scriptUri, "main", document, true, &error); |
| + if (!m_isolate) { |
| + m_errorMsg = error; |
| + return false; |
| + } |
| + |
| + |
| + Dart_EnterScope(); |
| + |
| + // Set up the library tag handler for this isolate. |
| + Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler); |
| + SHUTDOWN_ON_ERROR(result); |
|
Jacob
2013/12/04 20:39:52
for consistency use the
Scope auto-release helper
Cutch
2013/12/04 21:20:50
Done.
|
| + |
| + { |
| + // 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(); |
| + return true; |
| +} |
| + |
| + |
| +bool DartService::Stop() |
| +{ |
| + // TODO: Properly cleanup VM service isolate. |
| + m_port = ILLEGAL_PORT; |
| + return true; |
| +} |
| + |
| + |
| +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( |
|
Jacob
2013/12/04 20:39:52
there isn't an 80 char line limit in this director
Cutch
2013/12/04 21:20:50
Done.
|
| + 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); |
| +} |
| + |
| + |
| +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; |
|
Jacob
2013/12/04 20:39:52
here and elsewhere, remove {
}
for single line
Cutch
2013/12/04 21:20:50
Done.
|
| + } |
| + } |
| + 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) |
|
Jacob
2013/12/04 20:39:52
I assume this is probably defined somewhere else a
Cutch
2013/12/04 21:20:50
It actually is not.
|
| +{ |
| + 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); |
| + } |
| + char buffer[1024]; |
|
Jacob
2013/12/04 20:39:52
add FIXME to not hardcode 1024 here.
Cutch
2013/12/04 21:20:50
Done.
|
| + 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; |
| + } |
| + DART_UNIMPLEMENTED(); |
|
Jacob
2013/12/04 20:39:52
DART_UNIMPLEMENTED seems wrong here. this is hitti
Cutch
2013/12/04 21:20:50
Replaced with 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; |
| +} |
| + |
| +} |