| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include "config.h" |
| 6 |
| 7 #include "bindings/dart/DartService.h" |
| 8 |
| 9 #include "DartApplicationLoader.h" |
| 10 #include "DartController.h" |
| 11 #include "DartDocument.h" |
| 12 #include "DartServiceInternal.h" |
| 13 #include "DartUtilities.h" |
| 14 #include "DartWindow.h" |
| 15 |
| 16 |
| 17 // These must be kept in sync with vmservice/constants.dart |
| 18 // TODO(johnmccutchan): Put these constants in one place. |
| 19 #define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1 |
| 20 #define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2 |
| 21 |
| 22 // The following Resources class is used in combination with a generated |
| 23 // source file that expects underscores in names. The NOLINT tags are |
| 24 // used to suppress the errors. |
| 25 // TODO(johnmccutchan): Move VM service source into runtime and out of bin. |
| 26 namespace dart { |
| 27 namespace bin { |
| 28 class Resources { |
| 29 public: |
| 30 static const int kNoSuchInstance = -1; |
| 31 |
| 32 static int ResourceLookup(const char* path, const char** resource) |
| 33 { |
| 34 for (int i = 0; i < get_resource_count(); i++) { |
| 35 resource_map_entry* entry = get_resource(i); |
| 36 if (!strcmp(path, entry->path_)) { |
| 37 *resource = entry->resource_; |
| 38 ASSERT(entry->length_ > 0); |
| 39 return entry->length_; |
| 40 } |
| 41 } |
| 42 return kNoSuchInstance; |
| 43 } |
| 44 |
| 45 static intptr_t get_resource_count() // NOLINT. |
| 46 { |
| 47 return builtin_resources_count_; |
| 48 } |
| 49 |
| 50 static const char* get_resource_path(intptr_t i) // NOLINT. |
| 51 { |
| 52 return get_resource(i)->path_; |
| 53 } |
| 54 |
| 55 private: |
| 56 struct resource_map_entry { // NOLINT. |
| 57 const char* path_; // NOLINT. |
| 58 const char* resource_; // NOLINT. |
| 59 intptr_t length_; // NOLINT. |
| 60 }; |
| 61 |
| 62 // These fields are generated by resources_gen.cc. |
| 63 static resource_map_entry builtin_resources_[]; // NOLINT. |
| 64 static const intptr_t builtin_resources_count_; // NOLINT. |
| 65 |
| 66 static resource_map_entry* get_resource(int i) // NOLINT. |
| 67 { |
| 68 ASSERT(i >= 0 && i < builtin_resources_count_); |
| 69 return &builtin_resources_[i]; |
| 70 } |
| 71 |
| 72 DISALLOW_IMPLICIT_CONSTRUCTORS(Resources); |
| 73 }; |
| 74 |
| 75 } |
| 76 } |
| 77 namespace WebCore { |
| 78 |
| 79 #define SHUTDOWN_ON_ERROR(handle) \ |
| 80 if (Dart_IsError(handle)) { \ |
| 81 m_errorMsg = strdup(Dart_GetError(handle)); \ |
| 82 goto error; \ |
| 83 } |
| 84 |
| 85 static const char* kScriptUri = "vmservice:"; |
| 86 #define kLibraryResourceNamePrefix "/vmservice" |
| 87 static const char* kVMServiceDartiumLibraryScriptResourceName = |
| 88 kLibraryResourceNamePrefix "/vmservice_dartium.dart"; |
| 89 static const char* kVMServiceLibraryName = |
| 90 kLibraryResourceNamePrefix "/vmservice.dart"; |
| 91 |
| 92 |
| 93 Dart_Isolate DartService::m_isolate = 0; |
| 94 Dart_Port DartService::m_port = ILLEGAL_PORT; |
| 95 Dart_Port DartService::m_requestPort = ILLEGAL_PORT; |
| 96 const char* DartService::m_errorMsg = 0; |
| 97 |
| 98 |
| 99 bool DartService::Start(Document* document) |
| 100 { |
| 101 if (m_isolate) { |
| 102 // Already running. |
| 103 return true; |
| 104 } |
| 105 { |
| 106 char* error = 0; |
| 107 |
| 108 m_isolate = DartController::createIsolate(kScriptUri, "main", document,
true, &error); |
| 109 if (!m_isolate) { |
| 110 m_errorMsg = error; |
| 111 return false; |
| 112 } |
| 113 |
| 114 Dart_EnterScope(); |
| 115 // Set up the library tag handler for this isolate. |
| 116 Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler); |
| 117 SHUTDOWN_ON_ERROR(result); |
| 118 |
| 119 { |
| 120 // Load source into service isolate. |
| 121 Dart_Handle library = |
| 122 LoadScript(kVMServiceDartiumLibraryScriptResourceName); |
| 123 SHUTDOWN_ON_ERROR(library); |
| 124 result = Dart_SetNativeResolver(library, DartService::NativeResolver
); |
| 125 SHUTDOWN_ON_ERROR(result); |
| 126 } |
| 127 // Make the isolate runnable so that it is ready to handle messages. |
| 128 Dart_ExitScope(); |
| 129 Dart_ExitIsolate(); |
| 130 |
| 131 bool retval = Dart_IsolateMakeRunnable(m_isolate); |
| 132 if (!retval) { |
| 133 Dart_EnterIsolate(m_isolate); |
| 134 Dart_ShutdownIsolate(); |
| 135 m_errorMsg = "Invalid isolate state - Unable to make it runnable."; |
| 136 return false; |
| 137 } |
| 138 |
| 139 Dart_EnterIsolate(m_isolate); |
| 140 Dart_EnterScope(); |
| 141 |
| 142 // Invoke main. |
| 143 Dart_Handle library = Dart_RootLibrary(); |
| 144 Dart_Handle entryFunctioName = Dart_NewStringFromCString("main"); |
| 145 SHUTDOWN_ON_ERROR(entryFunctioName); |
| 146 result = Dart_Invoke(library, entryFunctioName, 0, 0); |
| 147 SHUTDOWN_ON_ERROR(result); |
| 148 |
| 149 // Retrieve the ReceivePort that the service is waiting on. The _receive
Port |
| 150 // variable is setup in the call to main. |
| 151 Dart_Handle portFieldName = Dart_NewStringFromCString("_receivePort"); |
| 152 SHUTDOWN_ON_ERROR(portFieldName); |
| 153 Dart_Handle receivePort = Dart_GetField(library, portFieldName); |
| 154 SHUTDOWN_ON_ERROR(receivePort); |
| 155 |
| 156 m_port = DartServiceInternal::GetPortIdFromPort(receivePort); |
| 157 if (m_port == ILLEGAL_PORT) { |
| 158 Dart_ExitScope(); |
| 159 Dart_ShutdownIsolate(); |
| 160 m_errorMsg = "Invalid isolate state - Unable to get receivePort"; |
| 161 return false; |
| 162 } |
| 163 |
| 164 { |
| 165 // Retrieve the ReceivePort that the service is waiting on. The _rec
eivePort |
| 166 // variable is setup in the call to main. |
| 167 Dart_Handle portFieldName = Dart_NewStringFromCString("_requestPort"
); |
| 168 SHUTDOWN_ON_ERROR(portFieldName); |
| 169 Dart_Handle receivePort = Dart_GetField(library, portFieldName); |
| 170 SHUTDOWN_ON_ERROR(receivePort); |
| 171 m_requestPort = DartServiceInternal::GetPortIdFromPort(receivePort); |
| 172 ASSERT(m_requestPort != ILLEGAL_PORT); |
| 173 } |
| 174 |
| 175 Dart_ExitScope(); |
| 176 Dart_ExitIsolate(); |
| 177 return true; |
| 178 } |
| 179 error: |
| 180 Dart_ExitScope(); |
| 181 Dart_ShutdownIsolate(); |
| 182 m_isolate = 0; |
| 183 m_port = ILLEGAL_PORT; |
| 184 m_requestPort = ILLEGAL_PORT; |
| 185 return false; |
| 186 } |
| 187 |
| 188 |
| 189 bool DartService::Stop() |
| 190 { |
| 191 if (!m_isolate) { |
| 192 // Already shutdown. |
| 193 return true; |
| 194 } |
| 195 m_port = ILLEGAL_PORT; |
| 196 m_requestPort = ILLEGAL_PORT; |
| 197 Dart_Isolate isolate = m_isolate; |
| 198 m_isolate = 0; |
| 199 Dart_EnterIsolate(isolate); |
| 200 DartController::shutdownIsolate(isolate); |
| 201 return true; |
| 202 } |
| 203 |
| 204 |
| 205 const char* DartService::GetErrorMessage() |
| 206 { |
| 207 return m_errorMsg ? m_errorMsg : "No error."; |
| 208 } |
| 209 |
| 210 |
| 211 Dart_Port DartService::port() |
| 212 { |
| 213 return m_port; |
| 214 } |
| 215 |
| 216 |
| 217 bool DartService::IsRunning() |
| 218 { |
| 219 return m_port != ILLEGAL_PORT; |
| 220 } |
| 221 |
| 222 |
| 223 static Dart_Handle MakeServiceControlMessage(Dart_Port portId, intptr_t code, Da
rt_Handle name) |
| 224 { |
| 225 Dart_Handle result; |
| 226 Dart_Handle list = Dart_NewList(4); |
| 227 ASSERT(!Dart_IsError(list)); |
| 228 Dart_Handle codeHandle = Dart_NewInteger(code); |
| 229 ASSERT(!Dart_IsError(codeHandle)); |
| 230 result = Dart_ListSetAt(list, 0, codeHandle); |
| 231 ASSERT(!Dart_IsError(result)); |
| 232 Dart_Handle portIdHandle = Dart_NewInteger(portId); |
| 233 ASSERT(!Dart_IsError(portIdHandle)); |
| 234 result = Dart_ListSetAt(list, 1, portIdHandle); |
| 235 ASSERT(!Dart_IsError(result)); |
| 236 Dart_Handle sendPort = Dart_NewSendPort(portId); |
| 237 ASSERT(!Dart_IsError(sendPort)); |
| 238 result = Dart_ListSetAt(list, 2, sendPort); |
| 239 ASSERT(!Dart_IsError(result)); |
| 240 result = Dart_ListSetAt(list, 3, name); |
| 241 ASSERT(!Dart_IsError(result)); |
| 242 return list; |
| 243 } |
| 244 |
| 245 |
| 246 bool DartService::SendIsolateStartupMessage() |
| 247 { |
| 248 if (!IsRunning()) { |
| 249 return false; |
| 250 } |
| 251 Dart_Handle name = Dart_DebugName(); |
| 252 ASSERT(!Dart_IsError(name)); |
| 253 Dart_Handle list = MakeServiceControlMessage(Dart_GetMainPortId(), VM_SERVIC
E_ISOLATE_STARTUP_MESSAGE_ID, name); |
| 254 ASSERT(!Dart_IsError(list)); |
| 255 return Dart_Post(m_port, list); |
| 256 } |
| 257 |
| 258 |
| 259 bool DartService::SendIsolateShutdownMessage() |
| 260 { |
| 261 if (!IsRunning()) |
| 262 return false; |
| 263 Dart_Handle list = MakeServiceControlMessage(Dart_GetMainPortId(), VM_SERVIC
E_ISOLATE_SHUTDOWN_MESSAGE_ID, Dart_Null()); |
| 264 ASSERT(!Dart_IsError(list)); |
| 265 return Dart_Post(m_port, list); |
| 266 } |
| 267 |
| 268 |
| 269 DartServiceRequest::DartServiceRequest(const String& request) : m_request(reques
t) |
| 270 { |
| 271 } |
| 272 |
| 273 DartServiceRequest::~DartServiceRequest() |
| 274 { |
| 275 } |
| 276 |
| 277 |
| 278 |
| 279 // The format of the message is: |
| 280 // [request string, address of DartServiceRequest]. |
| 281 static Dart_Handle MakeServiceRequestMessage(DartServiceRequest* request) |
| 282 { |
| 283 intptr_t requestAddress = reinterpret_cast<intptr_t>(request); |
| 284 int64_t requestAddress64 = static_cast<int64_t>(requestAddress); |
| 285 Dart_Handle result; |
| 286 Dart_Handle list = Dart_NewList(2); |
| 287 ASSERT(!Dart_IsError(list)); |
| 288 Dart_Handle requestHandle = DartUtilities::stringToDartString(request->GetRe
questString()); |
| 289 ASSERT(!Dart_IsError(requestHandle)); |
| 290 Dart_Handle addressHandle = Dart_NewInteger(requestAddress64); |
| 291 ASSERT(!Dart_IsError(addressHandle)); |
| 292 result = Dart_ListSetAt(list, 0, requestHandle); |
| 293 ASSERT(!Dart_IsError(result)); |
| 294 result = Dart_ListSetAt(list, 1, addressHandle); |
| 295 ASSERT(!Dart_IsError(result)); |
| 296 return list; |
| 297 } |
| 298 |
| 299 |
| 300 void DartService::MakeServiceRequest(DartServiceRequest* request) |
| 301 { |
| 302 // TODO(johnmccutchan): Once the VM service is no longer a DOM isolate, |
| 303 // we must be careful about entering the isolate. |
| 304 DartIsolateScope isolateScope(m_isolate); |
| 305 DartApiScope apiScope; |
| 306 Dart_Handle message = MakeServiceRequestMessage(request); |
| 307 Dart_Post(m_requestPort, message); |
| 308 } |
| 309 |
| 310 |
| 311 Dart_Handle DartService::GetSource(const char* name) |
| 312 { |
| 313 const char* vmserviceSource = 0; |
| 314 int r = dart::bin::Resources::ResourceLookup(name, &vmserviceSource); |
| 315 ASSERT(r != dart::bin::Resources::kNoSuchInstance); |
| 316 return Dart_NewStringFromCString(vmserviceSource); |
| 317 } |
| 318 |
| 319 |
| 320 Dart_Handle DartService::LoadScript(const char* name) |
| 321 { |
| 322 Dart_Handle url = Dart_NewStringFromCString(name); |
| 323 Dart_Handle source = GetSource(name); |
| 324 return Dart_LoadScript(url, source, 0, 0); |
| 325 } |
| 326 |
| 327 |
| 328 Dart_Handle DartService::LoadSource(Dart_Handle library, const char* name) |
| 329 { |
| 330 Dart_Handle url = Dart_NewStringFromCString(name); |
| 331 Dart_Handle source = GetSource(name); |
| 332 return Dart_LoadSource(library, url, source); |
| 333 } |
| 334 |
| 335 |
| 336 Dart_Handle DartService::LoadSources(Dart_Handle library, const char* names[]) |
| 337 { |
| 338 Dart_Handle result = Dart_Null(); |
| 339 for (int i = 0; names[i]; i++) { |
| 340 result = LoadSource(library, names[i]); |
| 341 if (Dart_IsError(result)) |
| 342 break; |
| 343 } |
| 344 return result; |
| 345 } |
| 346 |
| 347 |
| 348 static bool IsVMServiceURL(const char* url) |
| 349 { |
| 350 static const intptr_t kLibraryResourceNamePrefixLen = strlen(kLibraryResourc
eNamePrefix); |
| 351 return !strncmp(kLibraryResourceNamePrefix, url, kLibraryResourceNamePrefixL
en); |
| 352 } |
| 353 |
| 354 |
| 355 static bool IsVMServiceLibrary(const char* url) |
| 356 { |
| 357 return !strcmp(kVMServiceLibraryName, url); |
| 358 } |
| 359 |
| 360 static bool IsDartLibrary(const char* url) |
| 361 { |
| 362 static const char* kDartPrefix = "dart:"; |
| 363 static const intptr_t kDartPrefixLen = strlen(kDartPrefix); |
| 364 return !strncmp(kDartPrefix, url, kDartPrefixLen); |
| 365 } |
| 366 |
| 367 static Dart_Handle Canonicalize(const char* url) |
| 368 { |
| 369 if (IsVMServiceURL(url)) { |
| 370 // Already canonicalized. |
| 371 return Dart_NewStringFromCString(url); |
| 372 } |
| 373 // FIXME(johnmccutchan): Remove hard coded 1024 character limit. |
| 374 char buffer[1024]; |
| 375 snprintf(&buffer[0], sizeof(buffer), "%s/%s", kLibraryResourceNamePrefix, ur
l); |
| 376 return Dart_NewStringFromCString(buffer); |
| 377 } |
| 378 |
| 379 |
| 380 Dart_Handle DartService::LibraryTagHandler(Dart_LibraryTag tag, Dart_Handle libr
ary, Dart_Handle url) |
| 381 { |
| 382 if (!Dart_IsLibrary(library)) |
| 383 return Dart_NewApiError("not a library"); |
| 384 if (!Dart_IsString(url)) |
| 385 return Dart_NewApiError("url is not a string"); |
| 386 const char* urlString = 0; |
| 387 Dart_Handle result = Dart_StringToCString(url, &urlString); |
| 388 if (Dart_IsError(result)) |
| 389 return result; |
| 390 Dart_Handle libraryUrl = Dart_LibraryUrl(library); |
| 391 const char* libraryUrlString = 0; |
| 392 result = Dart_StringToCString(libraryUrl, &libraryUrlString); |
| 393 if (Dart_IsError(result)) |
| 394 return result; |
| 395 if (IsDartLibrary(urlString)) |
| 396 return DartApplicationLoader::libraryTagHandlerCallback(tag, library, ur
l); |
| 397 switch (tag) { |
| 398 case Dart_kCanonicalizeUrl: |
| 399 return Canonicalize(urlString); |
| 400 break; |
| 401 case Dart_kImportTag: { |
| 402 Dart_Handle source = GetSource(urlString); |
| 403 if (Dart_IsError(source)) |
| 404 return source; |
| 405 Dart_Handle lib = Dart_LoadLibrary(url, source); |
| 406 if (Dart_IsError(lib)) |
| 407 return lib; |
| 408 if (IsVMServiceLibrary(urlString)) { |
| 409 // Install native resolver for this library. |
| 410 result = Dart_SetNativeResolver(lib, DartService::NativeResolver); |
| 411 if (Dart_IsError(result)) |
| 412 return result; |
| 413 } |
| 414 return lib; |
| 415 } |
| 416 break; |
| 417 case Dart_kSourceTag: { |
| 418 Dart_Handle source = GetSource(urlString); |
| 419 if (Dart_IsError(source)) |
| 420 return source; |
| 421 return Dart_LoadSource(library, url, source); |
| 422 } |
| 423 break; |
| 424 default: |
| 425 DART_UNIMPLEMENTED(); |
| 426 break; |
| 427 } |
| 428 ASSERT_NOT_REACHED(); |
| 429 return result; |
| 430 } |
| 431 |
| 432 |
| 433 void DartService::VmServiceShutdownCallback(void* callbackData) |
| 434 { |
| 435 ASSERT(Dart_CurrentIsolate()); |
| 436 DartApiScope apiScope; |
| 437 SendIsolateShutdownMessage(); |
| 438 } |
| 439 |
| 440 static void SendServiceMessage(Dart_NativeArguments args) |
| 441 { |
| 442 Dart_Handle sp = Dart_GetNativeArgument(args, 0); |
| 443 Dart_Handle rp = Dart_GetNativeArgument(args, 1); |
| 444 Dart_Handle message = Dart_GetNativeArgument(args, 2); |
| 445 DartServiceInternal::PostOOB(sp, rp, message); |
| 446 } |
| 447 |
| 448 static void PostResponse(Dart_NativeArguments args) |
| 449 { |
| 450 Dart_Handle result; |
| 451 Dart_Handle response = Dart_GetNativeArgument(args, 0); |
| 452 ASSERT(!Dart_IsError(response)); |
| 453 Dart_Handle cookie = Dart_GetNativeArgument(args, 1); |
| 454 ASSERT(!Dart_IsError(cookie)); |
| 455 int64_t requestAddress64 = 0; |
| 456 result = Dart_IntegerToInt64(cookie, &requestAddress64); |
| 457 ASSERT(!Dart_IsError(result)); |
| 458 ASSERT(requestAddress64); |
| 459 intptr_t requestAddress = static_cast<intptr_t>(requestAddress64); |
| 460 ASSERT(requestAddress); |
| 461 DartServiceRequest* request = reinterpret_cast<DartServiceRequest*>(requestA
ddress); |
| 462 const char* responseString = 0; |
| 463 result = Dart_StringToCString(response, &responseString); |
| 464 ASSERT(!Dart_IsError(result)); |
| 465 ASSERT(responseString); |
| 466 request->ResponseReady(responseString); |
| 467 } |
| 468 |
| 469 struct VmServiceNativeEntry { |
| 470 const char* name; |
| 471 int numArguments; |
| 472 Dart_NativeFunction function; |
| 473 }; |
| 474 |
| 475 |
| 476 static VmServiceNativeEntry VmServiceNativeEntries[] = { |
| 477 {"SendServiceMessage", 3, SendServiceMessage}, |
| 478 {"PostResponse", 2, PostResponse} |
| 479 }; |
| 480 |
| 481 |
| 482 Dart_NativeFunction DartService::NativeResolver(Dart_Handle name, int numArgumen
ts) |
| 483 { |
| 484 const char* functionName = 0; |
| 485 Dart_Handle result = Dart_StringToCString(name, &functionName); |
| 486 ASSERT(!Dart_IsError(result)); |
| 487 ASSERT(functionName); |
| 488 intptr_t n = sizeof(VmServiceNativeEntries) / sizeof(VmServiceNativeEntries[
0]); |
| 489 for (intptr_t i = 0; i < n; i++) { |
| 490 VmServiceNativeEntry entry = VmServiceNativeEntries[i]; |
| 491 if (!strcmp(functionName, entry.name) && (numArguments == entry.numArgum
ents)) { |
| 492 return entry.function; |
| 493 } |
| 494 } |
| 495 return 0; |
| 496 } |
| 497 |
| 498 } |
| OLD | NEW |