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 |