| Index: runtime/bin/builtin.dart
|
| diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
|
| index feb26a91a6d65f89a1dbc7b561ca2f5c5992868e..8ee15ce85e8f0cc82716c0d4a651d91fefaf26ed 100644
|
| --- a/runtime/bin/builtin.dart
|
| +++ b/runtime/bin/builtin.dart
|
| @@ -71,8 +71,7 @@ bool _traceLoading = false;
|
| SendPort _loadPort;
|
| // The receive port for a load request. Multiple sources can be fetched in
|
| // a single load request.
|
| -RawReceivePort _receivePort;
|
| -SendPort _sendPort;
|
| +RawReceivePort _dataPort;
|
| // A request id valid only for the current load cycle (while the number of
|
| // outstanding load requests is greater than 0). Can be reset when loading is
|
| // completed.
|
| @@ -125,17 +124,16 @@ class _LoadError extends Error {
|
|
|
| // Class collecting all of the information about a particular load request.
|
| class _LoadRequest {
|
| - final int _id;
|
| + final int _id = _reqId++;
|
| final int _tag;
|
| final String _uri;
|
| final Uri _resourceUri;
|
| final _context;
|
|
|
| - _LoadRequest(this._id,
|
| - this._tag,
|
| - this._uri,
|
| - this._resourceUri,
|
| - this._context);
|
| + _LoadRequest(this._tag, this._uri, this._resourceUri, this._context) {
|
| + assert(_reqMap[_id] == null);
|
| + _reqMap[_id] = this;
|
| + }
|
|
|
| toString() => "LoadRequest($_id, $_tag, $_uri, $_resourceUri, $_context)";
|
| }
|
| @@ -320,13 +318,13 @@ void _finishLoadRequest(_LoadRequest req) {
|
| }
|
| }
|
|
|
| - if (!_pendingLoads()) {
|
| + if (!_pendingLoads() && (_dataPort != null)) {
|
| + // Close the _dataPort now that there are no more requests outstanding.
|
| if (_traceLoading) {
|
| _log("Closing loading port.");
|
| }
|
| - _receivePort.close();
|
| - _receivePort = null;
|
| - _sendPort = null;
|
| + _dataPort.close();
|
| + _dataPort = null;
|
| _reqId = 0;
|
| _signalDoneLoading();
|
| }
|
| @@ -367,33 +365,26 @@ void _handleLoaderReply(msg) {
|
|
|
|
|
| void _startLoadRequest(int tag, String uri, Uri resourceUri, context) {
|
| - if (_receivePort == null) {
|
| + if (_dataPort == null) {
|
| if (_traceLoading) {
|
| _log("Initializing load port.");
|
| }
|
| - assert(_receivePort == null);
|
| - assert(_sendPort == null);
|
| - _receivePort = new RawReceivePort(_handleLoaderReply);
|
| - _sendPort = _receivePort.sendPort;
|
| + assert(_dataPort == null);
|
| + _dataPort = new RawReceivePort(_handleLoaderReply);
|
| }
|
| // Register the load request and send it to the VM service isolate.
|
| - var curId = _reqId++;
|
| -
|
| - assert(_reqMap[curId] == null);
|
| - _reqMap[curId] = new _LoadRequest(curId, tag, uri, resourceUri, context);
|
| -
|
| - assert(_receivePort != null);
|
| - assert(_sendPort != null);
|
| + var req = new _LoadRequest(tag, uri, resourceUri, context);
|
|
|
| + assert(_dataPort != null);
|
| var msg = new List(4);
|
| - msg[0] = _sendPort;
|
| + msg[0] = _dataPort.sendPort;
|
| msg[1] = _traceLoading;
|
| - msg[2] = curId;
|
| + msg[2] = req._id;
|
| msg[3] = resourceUri.toString();
|
| _loadPort.send(msg);
|
|
|
| if (_traceLoading) {
|
| - _log("Loading of $resourceUri for $uri started with id: $curId. "
|
| + _log("Loading of $resourceUri for $uri started with id: ${req._id}. "
|
| "${_reqMap.length} requests remaining, "
|
| "${_pendingPackageLoads.length} packages pending.");
|
| }
|
| @@ -434,17 +425,10 @@ void _handlePackagesReply(msg) {
|
|
|
| // Resolve all pending package loads now that we know how to resolve them.
|
| while (_pendingPackageLoads.length > 0) {
|
| + // Order does not matter as we queue all of the requests up right now.
|
| var req = _pendingPackageLoads.removeLast();
|
| - if (req != null) {
|
| - if (_traceLoading) {
|
| - _log("Handling deferred load request: $req");
|
| - }
|
| - _loadPackage(req._tag, req._uri, req._resourceUri, req._context);
|
| - } else {
|
| - if (_traceLoading) {
|
| - _log("Skipping dummy deferred request.");
|
| - }
|
| - }
|
| + // Call the registered closure, to handle the delayed action.
|
| + req();
|
| }
|
| // Reset the pending package loads to empty. So that we eventually can
|
| // finish loading.
|
| @@ -516,7 +500,13 @@ void _loadPackagesMap(String packagesParam) {
|
|
|
| // Signal that the resolution of the packages map has started. But in this
|
| // case it is not tied to a particular request.
|
| - _pendingPackageLoads.add(null);
|
| + _pendingPackageLoads.add(() {
|
| + // Nothing to be done beyond registering that there is pending package
|
| + // resolution requested by having an empty entry.
|
| + if (_traceLoading) {
|
| + _log("Skipping dummy deferred request.");
|
| + }
|
| + });
|
|
|
| if (_traceLoading) {
|
| _log("Requested packages map at '$packagesUri'.");
|
| @@ -553,8 +543,10 @@ _loadDataFromLoadPort(int tag, String uri, Uri resourceUri, context) {
|
| }
|
| // Wrap inside a _LoadError unless we are already propagating a previously
|
| // seen _LoadError.
|
| - var error = (e is _LoadError) ? e : new _LoadError(e.toString());
|
| - _asyncLoadError(tag, uri, context, error, s);
|
| + var error = (e is _LoadError) ? e : new _LoadError(uri, e.toString());
|
| + // Register a dummy load request and fail to load it.
|
| + var req = new _LoadRequest(tag, uri, resourceUri, context);
|
| + _asyncLoadError(req, error, s);
|
| }
|
| }
|
|
|
| @@ -570,8 +562,15 @@ _loadPackage(int tag, String uri, Uri resourceUri, context) {
|
| // request for package resolution & loading.
|
| _requestPackagesMap();
|
| }
|
| - var req = new _LoadRequest(-1, tag, uri, resourceUri, context);
|
| - _pendingPackageLoads.add(req);
|
| + // Register the action of loading this package once the package resolution
|
| + // is ready.
|
| + _pendingPackageLoads.add(() {
|
| + if (_traceLoading) {
|
| + _log("Handling deferred package request: "
|
| + "$tag, $uri, $resourceUri, $context");
|
| + }
|
| + _loadPackage(tag, uri, resourceUri, context);
|
| + });
|
| if (_traceLoading) {
|
| _log("Pending package load of '$uri': "
|
| "${_pendingPackageLoads.length} pending");
|
| @@ -635,6 +634,48 @@ String _resolveUri(String base, String userString) {
|
| }
|
|
|
|
|
| +// Handling of access to the package root or package map from user code.
|
| +_triggerPackageResolution(action) {
|
| + if (_packagesReady()) {
|
| + // Packages are ready. Execute the action now.
|
| + action();
|
| + } else {
|
| + if (_pendingPackageLoads.isEmpty) {
|
| + // Package resolution has not been setup yet, and this is the first
|
| + // request for package resolution & loading.
|
| + _requestPackagesMap();
|
| + }
|
| + // Register the action for when the package resolution is ready.
|
| + _pendingPackageLoads.add(action);
|
| + }
|
| +}
|
| +
|
| +
|
| +Future<Uri> _getPackageRoot() {
|
| + if (_traceLoading) {
|
| + _log("Request for package root from user code.");
|
| + }
|
| + var completer = new Completer<Uri>();
|
| + _triggerPackageResolution(() {
|
| + completer.complete(_packageRoot);
|
| + });
|
| + return completer.future;
|
| +}
|
| +
|
| +
|
| +Future<Map<String, Uri>> _getPackageMap() {
|
| + if (_traceLoading) {
|
| + _log("Request for package map from user code.");
|
| + }
|
| + var completer = new Completer<Map<String, Uri>>();
|
| + _triggerPackageResolution(() {
|
| + var result = (_packageMap != null) ? new Map.from(_packageMap) : {};
|
| + completer.complete(result);
|
| + });
|
| + return completer.future;
|
| +}
|
| +
|
| +
|
| // Handling of Resource class by dispatching to the load port.
|
| Future<List<int>> _resourceReadAsBytes(Uri uri) {
|
| var completer = new Completer<List<int>>();
|
| @@ -762,4 +803,6 @@ _extensionPathFromUri(String userUri) {
|
| _setupHooks() {
|
| _setupCompleted = true;
|
| VMLibraryHooks.resourceReadAsBytes = _resourceReadAsBytes;
|
| + VMLibraryHooks.getPackageRoot = _getPackageRoot;
|
| + VMLibraryHooks.getPackageMap = _getPackageMap;
|
| }
|
|
|