| Index: runtime/bin/builtin.dart
|
| diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
|
| index 155dc1fe4bf98b9fda561e7c62f2475090805ee9..f0db3762e9f6193a3f59bffb807cf2325414d329 100644
|
| --- a/runtime/bin/builtin.dart
|
| +++ b/runtime/bin/builtin.dart
|
| @@ -3,9 +3,20 @@
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| library builtin;
|
| -import 'dart:io';
|
| import 'dart:async';
|
| import 'dart:convert';
|
| +import 'dart:isolate';
|
| +
|
| +
|
| +/* See Dart_LibraryTag in dart_api.h */
|
| +const Dart_kScriptTag = null;
|
| +const Dart_kImportTag = 0;
|
| +const Dart_kSourceTag = 1;
|
| +const Dart_kCanonicalizeUrl = 2;
|
| +
|
| +// Dart native extension scheme.
|
| +const _DART_EXT = 'dart-ext:';
|
| +
|
| // import 'root_library'; happens here from C Code
|
|
|
| // The root library (aka the script) is imported into this library. The
|
| @@ -13,28 +24,29 @@ import 'dart:convert';
|
| // root library's namespace.
|
| Function _getMainClosure() => main;
|
|
|
| +// A port for communicating with the service isolate for I/O.
|
| +SendPort _loadPort;
|
| +
|
| +const _logBuiltin = false;
|
|
|
| // Corelib 'print' implementation.
|
| void _print(arg) {
|
| _Logger._printString(arg.toString());
|
| }
|
|
|
| -
|
| class _Logger {
|
| static void _printString(String s) native "Logger_PrintString";
|
| }
|
|
|
| -
|
| _getPrintClosure() => _print;
|
|
|
| -const _logBuiltin = false;
|
| +_getCurrentDirectoryPath() native "Directory_Current";
|
|
|
| // Corelib 'Uri.base' implementation.
|
| Uri _uriBase() {
|
| - return new Uri.file(Directory.current.path + "/");
|
| + return new Uri.file(_getCurrentDirectoryPath() + "/");
|
| }
|
|
|
| -
|
| _getUriBaseClosure() => _uriBase;
|
|
|
|
|
| @@ -126,6 +138,26 @@ _setPackageRoot(String packageRoot) {
|
| }
|
|
|
|
|
| +// Given a uri with a 'package' scheme, return a Uri that is prefixed with
|
| +// the package root.
|
| +Uri _resolvePackageUri(Uri uri) {
|
| + if (!uri.host.isEmpty) {
|
| + var path = '${uri.host}${uri.path}';
|
| + var right = 'package:$path';
|
| + var wrong = 'package://$path';
|
| +
|
| + throw "URIs using the 'package:' scheme should look like "
|
| + "'$right', not '$wrong'.";
|
| + }
|
| +
|
| + var packageRoot = _packageRoot == null ?
|
| + _entryPointScript.resolve('packages/') :
|
| + _packageRoot;
|
| + return packageRoot.resolve(uri.path);
|
| +}
|
| +
|
| +
|
| +
|
| String _resolveScriptUri(String scriptName) {
|
| if (_workingDirectoryUri == null) {
|
| throw 'No current working directory set.';
|
| @@ -147,8 +179,8 @@ String _resolveScriptUri(String scriptName) {
|
| return _entryPointScript.toString();
|
| }
|
|
|
| -const _DART_EXT = 'dart-ext:';
|
|
|
| +// Function called by standalone embedder to resolve uris.
|
| String _resolveUri(String base, String userString) {
|
| if (_logBuiltin) {
|
| _print('# Resolving: $userString from $base');
|
| @@ -162,26 +194,18 @@ String _resolveUri(String base, String userString) {
|
| }
|
| }
|
|
|
| -
|
| -// Returns either a file path or a URI starting with http[s]:, as a String.
|
| -String _filePathFromUri(String userUri) {
|
| +Uri _createUri(String userUri) {
|
| var uri = Uri.parse(userUri);
|
| - if (_logBuiltin) {
|
| - _print('# Getting file path from: $uri');
|
| - }
|
| -
|
| - var path;
|
| switch (uri.scheme) {
|
| case '':
|
| case 'file':
|
| - return uri.toFilePath();
|
| - case 'package':
|
| - return _filePathFromUri(_resolvePackageUri(uri).toString());
|
| case 'http':
|
| case 'https':
|
| - return uri.toString();
|
| + return uri;
|
| + case 'package':
|
| + return _resolvePackageUri(uri);
|
| default:
|
| - // Only handling file, http, and package URIs
|
| + // Only handling file, http[s], and package URIs
|
| // in standalone binary.
|
| if (_logBuiltin) {
|
| _print('# Unknown scheme (${uri.scheme}) in $uri.');
|
| @@ -190,124 +214,114 @@ String _filePathFromUri(String userUri) {
|
| }
|
| }
|
|
|
| -
|
| -Uri _resolvePackageUri(Uri uri) {
|
| - if (!uri.host.isEmpty) {
|
| - var path = '${uri.host}${uri.path}';
|
| - var right = 'package:$path';
|
| - var wrong = 'package://$path';
|
| -
|
| - throw "URIs using the 'package:' scheme should look like "
|
| - "'$right', not '$wrong'.";
|
| +int _numOutstandingLoadRequests = 0;
|
| +void _finishedOneLoadRequest(String uri) {
|
| + assert(_numOutstandingLoadRequests > 0);
|
| + _numOutstandingLoadRequests--;
|
| + if (_logBuiltin) {
|
| + _print("Loading of $uri finished, "
|
| + "${_numOutstandingLoadRequests} requests remaining");
|
| + }
|
| + if (_numOutstandingLoadRequests == 0) {
|
| + _signalDoneLoading();
|
| }
|
| -
|
| - var packageRoot = _packageRoot == null ?
|
| - _entryPointScript.resolve('packages/') :
|
| - _packageRoot;
|
| - return packageRoot.resolve(uri.path);
|
| }
|
|
|
| -
|
| -int _numOutstandingLoadRequests = 0;
|
| -var _httpClient;
|
| -
|
| -void _httpGet(Uri uri, String libraryUri, loadCallback(List<int> data)) {
|
| - if (_httpClient == null) {
|
| - _httpClient = new HttpClient()..maxConnectionsPerHost = 6;
|
| +void _startingOneLoadRequest(String uri) {
|
| + assert(_numOutstandingLoadRequests >= 0);
|
| + _numOutstandingLoadRequests++;
|
| + if (_logBuiltin) {
|
| + _print("Loading of $uri started, "
|
| + "${_numOutstandingLoadRequests} requests outstanding");
|
| }
|
| - _httpClient.getUrl(uri)
|
| - .then((HttpClientRequest request) => request.close())
|
| - .then((HttpClientResponse response) {
|
| - var builder = new BytesBuilder(copy: false);
|
| - response.listen(
|
| - builder.add,
|
| - onDone: () {
|
| - if (response.statusCode != 200) {
|
| - var msg = 'Failure getting $uri: '
|
| - '${response.statusCode} ${response.reasonPhrase}';
|
| - _asyncLoadError(uri.toString(), libraryUri, msg);
|
| - }
|
| - loadCallback(builder.takeBytes());
|
| - },
|
| - onError: (error) {
|
| - _asyncLoadError(uri.toString(), libraryUri, error);
|
| - });
|
| - })
|
| - .catchError((error) {
|
| - _asyncLoadError(uri.toString(), libraryUri, error);
|
| - });
|
| - // TODO(floitsch): remove this line. It's just here to push an event on the
|
| - // event loop so that we invoke the scheduled microtasks. Also remove the
|
| - // import of dart:async when this line is not needed anymore.
|
| - Timer.run(() {});
|
| }
|
|
|
| +class LoadError extends Error {
|
| + final String message;
|
| + LoadError(this.message);
|
|
|
| -void _signalDoneLoading() native "Builtin_DoneLoading";
|
| -
|
| -void _cleanup() {
|
| - if (_httpClient != null) {
|
| - _httpClient.close();
|
| - _httpClient = null;
|
| - }
|
| + String toString() => 'Load Error: $message';
|
| }
|
|
|
| +void _signalDoneLoading() native "Builtin_DoneLoading";
|
| void _loadScriptCallback(int tag, String uri, String libraryUri, List<int> data)
|
| native "Builtin_LoadScript";
|
| +void _asyncLoadErrorCallback(uri, libraryUri, error)
|
| + native "Builtin_AsyncLoadError";
|
|
|
| void _loadScript(int tag, String uri, String libraryUri, List<int> data) {
|
| // TODO: Currently a compilation error while loading the script is
|
| // fatal for the isolate. _loadScriptCallback() does not return and
|
| // the _numOutstandingLoadRequests counter remains out of sync.
|
| _loadScriptCallback(tag, uri, libraryUri, data);
|
| - assert(_numOutstandingLoadRequests > 0);
|
| - _numOutstandingLoadRequests--;
|
| + _finishedOneLoadRequest(uri);
|
| +}
|
| +
|
| +void _asyncLoadError(tag, uri, libraryUri, error) {
|
| if (_logBuiltin) {
|
| - _print("native Builtin_LoadScript($uri) completed, "
|
| - "${_numOutstandingLoadRequests} requests remaining");
|
| + _print("_asyncLoadError($uri), error: $error");
|
| }
|
| - if (_numOutstandingLoadRequests == 0) {
|
| - _signalDoneLoading();
|
| - _cleanup();
|
| + if (tag == Dart_kImportTag) {
|
| + // When importing a library, the libraryUri is the imported
|
| + // uri.
|
| + libraryUri = uri;
|
| }
|
| + _asyncLoadErrorCallback(uri, libraryUri, new LoadError(error));
|
| + _finishedOneLoadRequest(uri);
|
| }
|
|
|
|
|
| -void _asyncLoadErrorCallback(uri, libraryUri, error)
|
| - native "Builtin_AsyncLoadError";
|
| -
|
| -void _asyncLoadError(uri, libraryUri, error) {
|
| - assert(_numOutstandingLoadRequests > 0);
|
| - if (_logBuiltin) {
|
| - _print("_asyncLoadError($uri), error: $error");
|
| +// Asynchronously loads script data through a http[s] or file uri.
|
| +_loadDataAsync(int tag, String uri, String libraryUri) {
|
| + if (tag == Dart_kScriptTag) {
|
| + uri = _resolveScriptUri(uri);
|
| }
|
| - _numOutstandingLoadRequests--;
|
| - _asyncLoadErrorCallback(uri, libraryUri, error);
|
| - if (_numOutstandingLoadRequests == 0) {
|
| - _signalDoneLoading();
|
| - _cleanup();
|
| +
|
| + Uri resourceUri = _createUri(uri);
|
| +
|
| + var receivePort = new ReceivePort();
|
| + receivePort.first.then((dataOrError) {
|
| + if (dataOrError is List<int>) {
|
| + _loadScript(tag, uri, libraryUri, dataOrError);
|
| + } else {
|
| + _asyncLoadError(tag, uri, libraryUri, dataOrError);
|
| + }
|
| + }).catchError((e) {
|
| + _asyncLoadError(tag, uri, libraryUri, e.toString());
|
| + });
|
| +
|
| + try {
|
| + var msg = [receivePort.sendPort, resourceUri.toString()];
|
| + _loadPort.send(msg);
|
| + _startingOneLoadRequest(uri);
|
| + } catch (e) {
|
| + if (_logBuiltin) {
|
| + _print("Exception when communicating with service isolate: $e");
|
| + }
|
| + _asyncLoadError(tag, uri, libraryUri, e.toString());
|
| + receivePort.close();
|
| }
|
| }
|
|
|
| -
|
| -// Create a Uri of 'userUri'. If the input uri is a package uri, then the
|
| -// package uri is resolved.
|
| -Uri _createUri(String userUri) {
|
| +// Returns either a file path or a URI starting with http[s]:, as a String.
|
| +String _filePathFromUri(String userUri) {
|
| var uri = Uri.parse(userUri);
|
| if (_logBuiltin) {
|
| - _print('# Creating uri for: $uri');
|
| + _print('# Getting file path from: $uri');
|
| }
|
|
|
| + var path;
|
| switch (uri.scheme) {
|
| case '':
|
| case 'file':
|
| + return uri.toFilePath();
|
| + case 'package':
|
| + return _filePathFromUri(_resolvePackageUri(uri).toString());
|
| case 'http':
|
| case 'https':
|
| - return uri;
|
| - case 'package':
|
| - return _resolvePackageUri(uri);
|
| + return uri.toString();
|
| default:
|
| - // Only handling file, http[s], and package URIs
|
| + // Only handling file, http, and package URIs
|
| // in standalone binary.
|
| if (_logBuiltin) {
|
| _print('# Unknown scheme (${uri.scheme}) in $uri.');
|
| @@ -316,30 +330,15 @@ Uri _createUri(String userUri) {
|
| }
|
| }
|
|
|
| +String _nativeLibraryExtension() native "Builtin_NativeLibraryExtension";
|
|
|
| -// Asynchronously loads script data through a http[s] or file uri.
|
| -_loadDataAsync(int tag, String uri, String libraryUri) {
|
| - if (tag == null) {
|
| - uri = _resolveScriptUri(uri);
|
| - }
|
| - Uri resourceUri = _createUri(uri);
|
| - _numOutstandingLoadRequests++;
|
| - if (_logBuiltin) {
|
| - _print("_loadDataAsync($uri), "
|
| - "${_numOutstandingLoadRequests} requests outstanding");
|
| - }
|
| - if ((resourceUri.scheme == 'http') || (resourceUri.scheme == 'https')) {
|
| - _httpGet(resourceUri, libraryUri, (data) {
|
| - _loadScript(tag, uri, libraryUri, data);
|
| - });
|
| +String _platformExtensionFileName(String name) {
|
| + var extension = _nativeLibraryExtension();
|
| +
|
| + if (_isWindows) {
|
| + return '$name.$extension';
|
| } else {
|
| - var sourceFile = new File(resourceUri.toFilePath());
|
| - sourceFile.readAsBytes().then((data) {
|
| - _loadScript(tag, uri, libraryUri, data);
|
| - },
|
| - onError: (e) {
|
| - _asyncLoadError(uri, libraryUri, e);
|
| - });
|
| + return 'lib$name.$extension';
|
| }
|
| }
|
|
|
| @@ -358,7 +357,7 @@ _extensionPathFromUri(String userUri) {
|
| throw 'Unexpected internal error: Extension URI $userUri contains \\';
|
| }
|
|
|
| - String filename;
|
| +
|
| String name;
|
| String path; // Will end in '/'.
|
| int index = userUri.lastIndexOf('/');
|
| @@ -373,19 +372,7 @@ _extensionPathFromUri(String userUri) {
|
| }
|
|
|
| path = _filePathFromUri(path);
|
| -
|
| - if (Platform.isLinux || Platform.isAndroid) {
|
| - filename = 'lib$name.so';
|
| - } else if (Platform.isMacOS) {
|
| - filename = 'lib$name.dylib';
|
| - } else if (Platform.isWindows) {
|
| - filename = '$name.dll';
|
| - } else {
|
| - if (_logBuiltin) {
|
| - _print('Native extensions not supported on ${Platform.operatingSystem}');
|
| - }
|
| - throw 'Native extensions not supported on ${Platform.operatingSystem}';
|
| - }
|
| + var filename = _platformExtensionFileName(name);
|
|
|
| return [path, filename, name];
|
| }
|
|
|