| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library builtin; | 5 library builtin; |
| 6 // NOTE: Do not import 'dart:io' in builtin. | 6 // NOTE: Do not import 'dart:io' in builtin. |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:_internal'; | 9 import 'dart:_internal'; |
| 10 import 'dart:isolate'; | 10 import 'dart:isolate'; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 const _Dart_kResourceLoad = 3; | 64 const _Dart_kResourceLoad = 3; |
| 65 | 65 |
| 66 // Embedder sets this to true if the --trace-loading flag was passed on the | 66 // Embedder sets this to true if the --trace-loading flag was passed on the |
| 67 // command line. | 67 // command line. |
| 68 bool _traceLoading = false; | 68 bool _traceLoading = false; |
| 69 | 69 |
| 70 // A port for communicating with the service isolate for I/O. | 70 // A port for communicating with the service isolate for I/O. |
| 71 SendPort _loadPort; | 71 SendPort _loadPort; |
| 72 // The receive port for a load request. Multiple sources can be fetched in | 72 // The receive port for a load request. Multiple sources can be fetched in |
| 73 // a single load request. | 73 // a single load request. |
| 74 RawReceivePort _receivePort; | 74 RawReceivePort _dataPort; |
| 75 SendPort _sendPort; | |
| 76 // A request id valid only for the current load cycle (while the number of | 75 // A request id valid only for the current load cycle (while the number of |
| 77 // outstanding load requests is greater than 0). Can be reset when loading is | 76 // outstanding load requests is greater than 0). Can be reset when loading is |
| 78 // completed. | 77 // completed. |
| 79 int _reqId = 0; | 78 int _reqId = 0; |
| 80 // An unordered hash map mapping from request id to a particular load request. | 79 // An unordered hash map mapping from request id to a particular load request. |
| 81 // Once there are no outstanding load requests the current load has finished. | 80 // Once there are no outstanding load requests the current load has finished. |
| 82 HashMap _reqMap = new HashMap(); | 81 HashMap _reqMap = new HashMap(); |
| 83 | 82 |
| 84 // The current working directory when the embedder was launched. | 83 // The current working directory when the embedder was launched. |
| 85 Uri _workingDirectory; | 84 Uri _workingDirectory; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 class _LoadError extends Error { | 117 class _LoadError extends Error { |
| 119 final String message; | 118 final String message; |
| 120 final String uri; | 119 final String uri; |
| 121 _LoadError(this.uri, this.message); | 120 _LoadError(this.uri, this.message); |
| 122 | 121 |
| 123 String toString() => 'Load Error for "$uri": $message'; | 122 String toString() => 'Load Error for "$uri": $message'; |
| 124 } | 123 } |
| 125 | 124 |
| 126 // Class collecting all of the information about a particular load request. | 125 // Class collecting all of the information about a particular load request. |
| 127 class _LoadRequest { | 126 class _LoadRequest { |
| 128 final int _id; | 127 final int _id = _reqId++; |
| 129 final int _tag; | 128 final int _tag; |
| 130 final String _uri; | 129 final String _uri; |
| 131 final Uri _resourceUri; | 130 final Uri _resourceUri; |
| 132 final _context; | 131 final _context; |
| 133 | 132 |
| 134 _LoadRequest(this._id, | 133 _LoadRequest(this._tag, this._uri, this._resourceUri, this._context) { |
| 135 this._tag, | 134 assert(_reqMap[_id] == null); |
| 136 this._uri, | 135 _reqMap[_id] = this; |
| 137 this._resourceUri, | 136 } |
| 138 this._context); | |
| 139 | 137 |
| 140 toString() => "LoadRequest($_id, $_tag, $_uri, $_resourceUri, $_context)"; | 138 toString() => "LoadRequest($_id, $_tag, $_uri, $_resourceUri, $_context)"; |
| 141 } | 139 } |
| 142 | 140 |
| 143 | 141 |
| 144 // Native calls provided by the embedder. | 142 // Native calls provided by the embedder. |
| 145 void _signalDoneLoading() native "Builtin_DoneLoading"; | 143 void _signalDoneLoading() native "Builtin_DoneLoading"; |
| 146 void _loadScriptCallback(int tag, String uri, String libraryUri, Uint8List data) | 144 void _loadScriptCallback(int tag, String uri, String libraryUri, Uint8List data) |
| 147 native "Builtin_LoadSource"; | 145 native "Builtin_LoadSource"; |
| 148 void _asyncLoadErrorCallback(uri, libraryUri, error) | 146 void _asyncLoadErrorCallback(uri, libraryUri, error) |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 // Now that we are done with loading remove the request from the map. | 311 // Now that we are done with loading remove the request from the map. |
| 314 var tmp = _reqMap.remove(req._id); | 312 var tmp = _reqMap.remove(req._id); |
| 315 assert(tmp == req); | 313 assert(tmp == req); |
| 316 if (_traceLoading) { | 314 if (_traceLoading) { |
| 317 _log("Loading of ${req._uri} finished: " | 315 _log("Loading of ${req._uri} finished: " |
| 318 "${_reqMap.length} requests remaining, " | 316 "${_reqMap.length} requests remaining, " |
| 319 "${_pendingPackageLoads.length} packages pending."); | 317 "${_pendingPackageLoads.length} packages pending."); |
| 320 } | 318 } |
| 321 } | 319 } |
| 322 | 320 |
| 323 if (!_pendingLoads()) { | 321 if (!_pendingLoads() && (_dataPort != null)) { |
| 322 // Close the _dataPort now that there are no more requests outstanding. |
| 324 if (_traceLoading) { | 323 if (_traceLoading) { |
| 325 _log("Closing loading port."); | 324 _log("Closing loading port."); |
| 326 } | 325 } |
| 327 _receivePort.close(); | 326 _dataPort.close(); |
| 328 _receivePort = null; | 327 _dataPort = null; |
| 329 _sendPort = null; | |
| 330 _reqId = 0; | 328 _reqId = 0; |
| 331 _signalDoneLoading(); | 329 _signalDoneLoading(); |
| 332 } | 330 } |
| 333 } | 331 } |
| 334 | 332 |
| 335 | 333 |
| 336 void _handleLoaderReply(msg) { | 334 void _handleLoaderReply(msg) { |
| 337 int id = msg[0]; | 335 int id = msg[0]; |
| 338 var dataOrError = msg[1]; | 336 var dataOrError = msg[1]; |
| 339 assert((id >= 0) && (id < _reqId)); | 337 assert((id >= 0) && (id < _reqId)); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 360 // Wrap inside a _LoadError unless we are already propagating a | 358 // Wrap inside a _LoadError unless we are already propagating a |
| 361 // previous _LoadError. | 359 // previous _LoadError. |
| 362 var error = (e is _LoadError) ? e : new _LoadError(req._uri, e.toString()); | 360 var error = (e is _LoadError) ? e : new _LoadError(req._uri, e.toString()); |
| 363 assert(req != null); | 361 assert(req != null); |
| 364 _asyncLoadError(req, error, s); | 362 _asyncLoadError(req, error, s); |
| 365 } | 363 } |
| 366 } | 364 } |
| 367 | 365 |
| 368 | 366 |
| 369 void _startLoadRequest(int tag, String uri, Uri resourceUri, context) { | 367 void _startLoadRequest(int tag, String uri, Uri resourceUri, context) { |
| 370 if (_receivePort == null) { | 368 if (_dataPort == null) { |
| 371 if (_traceLoading) { | 369 if (_traceLoading) { |
| 372 _log("Initializing load port."); | 370 _log("Initializing load port."); |
| 373 } | 371 } |
| 374 assert(_receivePort == null); | 372 assert(_dataPort == null); |
| 375 assert(_sendPort == null); | 373 _dataPort = new RawReceivePort(_handleLoaderReply); |
| 376 _receivePort = new RawReceivePort(_handleLoaderReply); | |
| 377 _sendPort = _receivePort.sendPort; | |
| 378 } | 374 } |
| 379 // Register the load request and send it to the VM service isolate. | 375 // Register the load request and send it to the VM service isolate. |
| 380 var curId = _reqId++; | 376 var req = new _LoadRequest(tag, uri, resourceUri, context); |
| 381 | 377 |
| 382 assert(_reqMap[curId] == null); | 378 assert(_dataPort != null); |
| 383 _reqMap[curId] = new _LoadRequest(curId, tag, uri, resourceUri, context); | |
| 384 | |
| 385 assert(_receivePort != null); | |
| 386 assert(_sendPort != null); | |
| 387 | |
| 388 var msg = new List(4); | 379 var msg = new List(4); |
| 389 msg[0] = _sendPort; | 380 msg[0] = _dataPort.sendPort; |
| 390 msg[1] = _traceLoading; | 381 msg[1] = _traceLoading; |
| 391 msg[2] = curId; | 382 msg[2] = req._id; |
| 392 msg[3] = resourceUri.toString(); | 383 msg[3] = resourceUri.toString(); |
| 393 _loadPort.send(msg); | 384 _loadPort.send(msg); |
| 394 | 385 |
| 395 if (_traceLoading) { | 386 if (_traceLoading) { |
| 396 _log("Loading of $resourceUri for $uri started with id: $curId. " | 387 _log("Loading of $resourceUri for $uri started with id: ${req._id}. " |
| 397 "${_reqMap.length} requests remaining, " | 388 "${_reqMap.length} requests remaining, " |
| 398 "${_pendingPackageLoads.length} packages pending."); | 389 "${_pendingPackageLoads.length} packages pending."); |
| 399 } | 390 } |
| 400 } | 391 } |
| 401 | 392 |
| 402 | 393 |
| 403 RawReceivePort _packagesPort; | 394 RawReceivePort _packagesPort; |
| 404 | 395 |
| 405 void _handlePackagesReply(msg) { | 396 void _handlePackagesReply(msg) { |
| 406 // Make sure to close the _packagePort before any other action. | 397 // Make sure to close the _packagePort before any other action. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 427 // TODO(iposva): Complain about duplicate entries. | 418 // TODO(iposva): Complain about duplicate entries. |
| 428 _packageMap[msg[i]] = Uri.parse(msg[i+1]); | 419 _packageMap[msg[i]] = Uri.parse(msg[i+1]); |
| 429 } | 420 } |
| 430 if (_traceLoading) { | 421 if (_traceLoading) { |
| 431 _log("Setup package map: $_packageMap"); | 422 _log("Setup package map: $_packageMap"); |
| 432 } | 423 } |
| 433 } | 424 } |
| 434 | 425 |
| 435 // Resolve all pending package loads now that we know how to resolve them. | 426 // Resolve all pending package loads now that we know how to resolve them. |
| 436 while (_pendingPackageLoads.length > 0) { | 427 while (_pendingPackageLoads.length > 0) { |
| 428 // Order does not matter as we queue all of the requests up right now. |
| 437 var req = _pendingPackageLoads.removeLast(); | 429 var req = _pendingPackageLoads.removeLast(); |
| 438 if (req != null) { | 430 // Call the registered closure, to handle the delayed action. |
| 439 if (_traceLoading) { | 431 req(); |
| 440 _log("Handling deferred load request: $req"); | |
| 441 } | |
| 442 _loadPackage(req._tag, req._uri, req._resourceUri, req._context); | |
| 443 } else { | |
| 444 if (_traceLoading) { | |
| 445 _log("Skipping dummy deferred request."); | |
| 446 } | |
| 447 } | |
| 448 } | 432 } |
| 449 // Reset the pending package loads to empty. So that we eventually can | 433 // Reset the pending package loads to empty. So that we eventually can |
| 450 // finish loading. | 434 // finish loading. |
| 451 _pendingPackageLoads = []; | 435 _pendingPackageLoads = []; |
| 452 // Make sure that the receive port is closed if no other loads are pending. | 436 // Make sure that the receive port is closed if no other loads are pending. |
| 453 _finishLoadRequest(null); | 437 _finishLoadRequest(null); |
| 454 } | 438 } |
| 455 | 439 |
| 456 | 440 |
| 457 void _requestPackagesMap() { | 441 void _requestPackagesMap() { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 | 493 |
| 510 var msg = new List(4); | 494 var msg = new List(4); |
| 511 msg[0] = sp; | 495 msg[0] = sp; |
| 512 msg[1] = _traceLoading; | 496 msg[1] = _traceLoading; |
| 513 msg[2] = -2; | 497 msg[2] = -2; |
| 514 msg[3] = packagesUri.toString(); | 498 msg[3] = packagesUri.toString(); |
| 515 _loadPort.send(msg); | 499 _loadPort.send(msg); |
| 516 | 500 |
| 517 // Signal that the resolution of the packages map has started. But in this | 501 // Signal that the resolution of the packages map has started. But in this |
| 518 // case it is not tied to a particular request. | 502 // case it is not tied to a particular request. |
| 519 _pendingPackageLoads.add(null); | 503 _pendingPackageLoads.add(() { |
| 504 // Nothing to be done beyond registering that there is pending package |
| 505 // resolution requested by having an empty entry. |
| 506 if (_traceLoading) { |
| 507 _log("Skipping dummy deferred request."); |
| 508 } |
| 509 }); |
| 520 | 510 |
| 521 if (_traceLoading) { | 511 if (_traceLoading) { |
| 522 _log("Requested packages map at '$packagesUri'."); | 512 _log("Requested packages map at '$packagesUri'."); |
| 523 } | 513 } |
| 524 } | 514 } |
| 525 | 515 |
| 526 | 516 |
| 527 void _asyncLoadError(_LoadRequest req, _LoadError error, StackTrace stack) { | 517 void _asyncLoadError(_LoadRequest req, _LoadError error, StackTrace stack) { |
| 528 if (_traceLoading) { | 518 if (_traceLoading) { |
| 529 _log("_asyncLoadError(${req._uri}), error: $error\nstack: $stack"); | 519 _log("_asyncLoadError(${req._uri}), error: $error\nstack: $stack"); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 546 | 536 |
| 547 _loadDataFromLoadPort(int tag, String uri, Uri resourceUri, context) { | 537 _loadDataFromLoadPort(int tag, String uri, Uri resourceUri, context) { |
| 548 try { | 538 try { |
| 549 _startLoadRequest(tag, uri, resourceUri, context); | 539 _startLoadRequest(tag, uri, resourceUri, context); |
| 550 } catch (e, s) { | 540 } catch (e, s) { |
| 551 if (_traceLoading) { | 541 if (_traceLoading) { |
| 552 _log("Exception when communicating with service isolate: $e"); | 542 _log("Exception when communicating with service isolate: $e"); |
| 553 } | 543 } |
| 554 // Wrap inside a _LoadError unless we are already propagating a previously | 544 // Wrap inside a _LoadError unless we are already propagating a previously |
| 555 // seen _LoadError. | 545 // seen _LoadError. |
| 556 var error = (e is _LoadError) ? e : new _LoadError(e.toString()); | 546 var error = (e is _LoadError) ? e : new _LoadError(uri, e.toString()); |
| 557 _asyncLoadError(tag, uri, context, error, s); | 547 // Register a dummy load request and fail to load it. |
| 548 var req = new _LoadRequest(tag, uri, resourceUri, context); |
| 549 _asyncLoadError(req, error, s); |
| 558 } | 550 } |
| 559 } | 551 } |
| 560 | 552 |
| 561 | 553 |
| 562 // Loading a package URI needs to first map the package name to a loadable | 554 // Loading a package URI needs to first map the package name to a loadable |
| 563 // URI. | 555 // URI. |
| 564 _loadPackage(int tag, String uri, Uri resourceUri, context) { | 556 _loadPackage(int tag, String uri, Uri resourceUri, context) { |
| 565 if (_packagesReady()) { | 557 if (_packagesReady()) { |
| 566 _loadData(tag, uri, _resolvePackageUri(resourceUri), context); | 558 _loadData(tag, uri, _resolvePackageUri(resourceUri), context); |
| 567 } else { | 559 } else { |
| 568 if (_pendingPackageLoads.isEmpty) { | 560 if (_pendingPackageLoads.isEmpty) { |
| 569 // Package resolution has not been setup yet, and this is the first | 561 // Package resolution has not been setup yet, and this is the first |
| 570 // request for package resolution & loading. | 562 // request for package resolution & loading. |
| 571 _requestPackagesMap(); | 563 _requestPackagesMap(); |
| 572 } | 564 } |
| 573 var req = new _LoadRequest(-1, tag, uri, resourceUri, context); | 565 // Register the action of loading this package once the package resolution |
| 574 _pendingPackageLoads.add(req); | 566 // is ready. |
| 567 _pendingPackageLoads.add(() { |
| 568 if (_traceLoading) { |
| 569 _log("Handling deferred package request: " |
| 570 "$tag, $uri, $resourceUri, $context"); |
| 571 } |
| 572 _loadPackage(tag, uri, resourceUri, context); |
| 573 }); |
| 575 if (_traceLoading) { | 574 if (_traceLoading) { |
| 576 _log("Pending package load of '$uri': " | 575 _log("Pending package load of '$uri': " |
| 577 "${_pendingPackageLoads.length} pending"); | 576 "${_pendingPackageLoads.length} pending"); |
| 578 } | 577 } |
| 579 } | 578 } |
| 580 } | 579 } |
| 581 | 580 |
| 582 | 581 |
| 583 // Load the data associated with the resourceUri. | 582 // Load the data associated with the resourceUri. |
| 584 _loadData(int tag, String uri, Uri resourceUri, context) { | 583 _loadData(int tag, String uri, Uri resourceUri, context) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 } else { | 627 } else { |
| 629 result = baseUri.resolve(userString).toString(); | 628 result = baseUri.resolve(userString).toString(); |
| 630 } | 629 } |
| 631 if (_traceLoading) { | 630 if (_traceLoading) { |
| 632 _log('Resolved $userString in $base to $result'); | 631 _log('Resolved $userString in $base to $result'); |
| 633 } | 632 } |
| 634 return result; | 633 return result; |
| 635 } | 634 } |
| 636 | 635 |
| 637 | 636 |
| 637 // Handling of access to the package root or package map from user code. |
| 638 _triggerPackageResolution(action) { |
| 639 if (_packagesReady()) { |
| 640 // Packages are ready. Execute the action now. |
| 641 action(); |
| 642 } else { |
| 643 if (_pendingPackageLoads.isEmpty) { |
| 644 // Package resolution has not been setup yet, and this is the first |
| 645 // request for package resolution & loading. |
| 646 _requestPackagesMap(); |
| 647 } |
| 648 // Register the action for when the package resolution is ready. |
| 649 _pendingPackageLoads.add(action); |
| 650 } |
| 651 } |
| 652 |
| 653 |
| 654 Future<Uri> _getPackageRoot() { |
| 655 if (_traceLoading) { |
| 656 _log("Request for package root from user code."); |
| 657 } |
| 658 var completer = new Completer<Uri>(); |
| 659 _triggerPackageResolution(() { |
| 660 completer.complete(_packageRoot); |
| 661 }); |
| 662 return completer.future; |
| 663 } |
| 664 |
| 665 |
| 666 Future<Map<String, Uri>> _getPackageMap() { |
| 667 if (_traceLoading) { |
| 668 _log("Request for package map from user code."); |
| 669 } |
| 670 var completer = new Completer<Map<String, Uri>>(); |
| 671 _triggerPackageResolution(() { |
| 672 var result = (_packageMap != null) ? new Map.from(_packageMap) : {}; |
| 673 completer.complete(result); |
| 674 }); |
| 675 return completer.future; |
| 676 } |
| 677 |
| 678 |
| 638 // Handling of Resource class by dispatching to the load port. | 679 // Handling of Resource class by dispatching to the load port. |
| 639 Future<List<int>> _resourceReadAsBytes(Uri uri) { | 680 Future<List<int>> _resourceReadAsBytes(Uri uri) { |
| 640 var completer = new Completer<List<int>>(); | 681 var completer = new Completer<List<int>>(); |
| 641 // Request the load of the resource associating the completer as the context | 682 // Request the load of the resource associating the completer as the context |
| 642 // for the load. | 683 // for the load. |
| 643 _loadData(_Dart_kResourceLoad, uri.toString(), uri, completer); | 684 _loadData(_Dart_kResourceLoad, uri.toString(), uri, completer); |
| 644 // Return the future that will be triggered once the resource has been loaded. | 685 // Return the future that will be triggered once the resource has been loaded. |
| 645 return completer.future; | 686 return completer.future; |
| 646 } | 687 } |
| 647 | 688 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 755 var filename = _platformExtensionFileName(name); | 796 var filename = _platformExtensionFileName(name); |
| 756 | 797 |
| 757 return [path, filename, name]; | 798 return [path, filename, name]; |
| 758 } | 799 } |
| 759 | 800 |
| 760 | 801 |
| 761 // Register callbacks and hooks with the rest of the core libraries. | 802 // Register callbacks and hooks with the rest of the core libraries. |
| 762 _setupHooks() { | 803 _setupHooks() { |
| 763 _setupCompleted = true; | 804 _setupCompleted = true; |
| 764 VMLibraryHooks.resourceReadAsBytes = _resourceReadAsBytes; | 805 VMLibraryHooks.resourceReadAsBytes = _resourceReadAsBytes; |
| 806 VMLibraryHooks.getPackageRoot = _getPackageRoot; |
| 807 VMLibraryHooks.getPackageMap = _getPackageMap; |
| 765 } | 808 } |
| OLD | NEW |