| Index: runtime/bin/builtin.dart
|
| ===================================================================
|
| --- runtime/bin/builtin.dart (revision 45696)
|
| +++ runtime/bin/builtin.dart (working copy)
|
| @@ -4,68 +4,99 @@
|
|
|
| library builtin;
|
| // NOTE: Do not import 'dart:io' in builtin.
|
| -import 'dart:async';
|
| -import 'dart:convert';
|
| import 'dart:isolate';
|
| +import 'dart:typed_data';
|
|
|
| +// import 'root_library'; happens here from C Code
|
|
|
| -/* See Dart_LibraryTag in dart_api.h */
|
| -const Dart_kScriptTag = null;
|
| -const Dart_kImportTag = 0;
|
| -const Dart_kSourceTag = 1;
|
| -const Dart_kCanonicalizeUrl = 2;
|
| +// Build time flag to enable debug logging of loading code.
|
| +const _logLoading = false;
|
|
|
| -// 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
|
| // standalone embedder uses this to lookup the main entrypoint in the
|
| // root library's namespace.
|
| Function _getMainClosure() => main;
|
|
|
| -// A port for communicating with the service isolate for I/O.
|
| -SendPort _loadPort;
|
|
|
| -const _logBuiltin = false;
|
| +// 'print' implementation.
|
| +// The standalone embedder registers the closurized _print function with the
|
| +// dart:core library.
|
| +void _printString(String s) native "Builtin_PrintString";
|
|
|
| -// Corelib 'print' implementation.
|
| +
|
| void _print(arg) {
|
| - _Logger._printString(arg.toString());
|
| + _printString(arg.toString());
|
| }
|
|
|
| -class _Logger {
|
| - static void _printString(String s) native "Logger_PrintString";
|
| -}
|
|
|
| _getPrintClosure() => _print;
|
|
|
| +
|
| +// Corelib 'Uri.base' implementation.
|
| +// Uri.base is susceptible to changes in the current working directory.
|
| _getCurrentDirectoryPath() native "Builtin_GetCurrentDirectory";
|
|
|
| -// Corelib 'Uri.base' implementation.
|
| +
|
| Uri _uriBase() {
|
| // We are not using Dircetory.current here to limit the dependency
|
| // on dart:io. This code is the same as:
|
| // return new Uri.file(Directory.current.path + "/");
|
| var result = _getCurrentDirectoryPath();
|
| - return new Uri.file(result + "/");
|
| + return new Uri.file("$result/");
|
| }
|
|
|
| +
|
| _getUriBaseClosure() => _uriBase;
|
|
|
|
|
| -// Are we running on Windows?
|
| -var _isWindows;
|
| -var _workingWindowsDrivePrefix;
|
| -// The current working directory
|
| +// Asynchronous loading of resources.
|
| +// The embedder forwards most loading requests to this library.
|
| +
|
| +// See Dart_LibraryTag in dart_api.h
|
| +const Dart_kScriptTag = null;
|
| +const Dart_kImportTag = 0;
|
| +const Dart_kSourceTag = 1;
|
| +const Dart_kCanonicalizeUrl = 2;
|
| +
|
| +// A port for communicating with the service isolate for I/O.
|
| +SendPort _loadPort;
|
| +// Maintain a number of outstanding load requests. Current loading request is
|
| +// finished once there are no outstanding requests.
|
| +int _numOutstandingLoadRequests = 0;
|
| +
|
| +// The current working directory when the embedder was launched.
|
| var _workingDirectoryUri;
|
| // The URI that the entry point script was loaded from. Remembered so that
|
| // package imports can be resolved relative to it.
|
| var _entryPointScript;
|
| -// The directory to look in to resolve "package:" scheme URIs.
|
| -var _packageRoot;
|
| +// The directory to look in to resolve "package:" scheme URIs. By detault it is
|
| +// the 'packages' directory right next to the script.
|
| +var _packageRoot = _entryPointScript.resolve('packages/');
|
|
|
| +// Special handling for Windows paths so that they are compatible with URI
|
| +// handling.
|
| +// Embedder sets whether we are running on Windows.
|
| +var _isWindows;
|
| +
|
| +
|
| +// A class wrapping the load error message in an Error object.
|
| +class LoadError extends Error {
|
| + final String message;
|
| + LoadError(this.message);
|
| +
|
| + String toString() => 'Load Error: $message';
|
| +}
|
| +
|
| +
|
| +// Native calls provided by the embedder.
|
| +void _signalDoneLoading() native "Builtin_DoneLoading";
|
| +void _loadScriptCallback(int tag, String uri, String libraryUri, Uint8List data)
|
| + native "Builtin_LoadSource";
|
| +void _asyncLoadErrorCallback(uri, libraryUri, error)
|
| + native "Builtin_AsyncLoadError";
|
| +
|
| +
|
| _sanitizeWindowsPath(path) {
|
| // For Windows we need to massage the paths a bit according to
|
| // http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx
|
| @@ -90,6 +121,7 @@
|
| return fixedPath;
|
| }
|
|
|
| +
|
| _trimWindowsPath(path) {
|
| // Convert /X:/ to X:/.
|
| if (_isWindows == false) {
|
| @@ -107,8 +139,9 @@
|
| return path;
|
| }
|
|
|
| +
|
| +// Ensure we have a trailing slash character.
|
| _enforceTrailingSlash(uri) {
|
| - // Ensure we have a trailing slash character.
|
| if (!uri.endsWith('/')) {
|
| return '$uri/';
|
| }
|
| @@ -116,28 +149,21 @@
|
| }
|
|
|
|
|
| -_extractDriveLetterPrefix(cwd) {
|
| - if (!_isWindows) {
|
| - return null;
|
| +// Embedder Entrypoint:
|
| +// The embedder calls this method with the current working directory.
|
| +void _setWorkingDirectory(cwd) {
|
| + if (_logLoading) {
|
| + _print('# Setting working directory: $cwd');
|
| }
|
| - if (cwd.length > 1 && cwd[1] == ':') {
|
| - return '/${cwd[0]}:';
|
| + _workingDirectoryUri = new Uri.directory(cwd);
|
| + if (_logLoading) {
|
| + _print('# Working directory URI: $_workingDirectoryUri');
|
| }
|
| - return null;
|
| }
|
|
|
|
|
| -void _setWorkingDirectory(cwd) {
|
| - _workingWindowsDrivePrefix = _extractDriveLetterPrefix(cwd);
|
| - cwd = _sanitizeWindowsPath(cwd);
|
| - cwd = _enforceTrailingSlash(cwd);
|
| - _workingDirectoryUri = new Uri(scheme: 'file', path: cwd);
|
| - if (_logBuiltin) {
|
| - _print('# Working Directory: $cwd');
|
| - }
|
| -}
|
| -
|
| -
|
| +// Embedder Entrypoint:
|
| +// The embedder calls this method with a custom package root.
|
| _setPackageRoot(String packageRoot) {
|
| packageRoot = _enforceTrailingSlash(packageRoot);
|
| if (packageRoot.startsWith('file:') ||
|
| @@ -149,7 +175,7 @@
|
| packageRoot = _trimWindowsPath(packageRoot);
|
| _packageRoot = _workingDirectoryUri.resolveUri(new Uri.file(packageRoot));
|
| }
|
| - if (_logBuiltin) {
|
| + if (_logLoading) {
|
| _print('# Package root: $packageRoot -> $_packageRoot');
|
| }
|
| }
|
| @@ -167,76 +193,44 @@
|
| "'$right', not '$wrong'.";
|
| }
|
|
|
| - var packageRoot = _packageRoot == null ?
|
| - _entryPointScript.resolve('packages/') :
|
| - _packageRoot;
|
| - return packageRoot.resolve(uri.path);
|
| + if (_logLoading) {
|
| + _print('# Package root: $_packageRoot');
|
| + _print('# uri path: ${uri.path}');
|
| + }
|
| + return _packageRoot.resolve(uri.path);
|
| }
|
|
|
|
|
| -
|
| -String _resolveScriptUri(String scriptName) {
|
| +// Resolves the script uri in the current working directory iff the given uri
|
| +// did not specify a scheme (e.g. a path to a script file on the command line).
|
| +Uri _resolveScriptUri(String scriptName) {
|
| if (_workingDirectoryUri == null) {
|
| throw 'No current working directory set.';
|
| }
|
| scriptName = _sanitizeWindowsPath(scriptName);
|
|
|
| var scriptUri = Uri.parse(scriptName);
|
| - if (scriptUri.scheme != '') {
|
| - // Script has a scheme, assume that it is fully formed.
|
| - _entryPointScript = scriptUri;
|
| - } else {
|
| + if (scriptUri.scheme == '') {
|
| // Script does not have a scheme, assume that it is a path,
|
| // resolve it against the working directory.
|
| - _entryPointScript = _workingDirectoryUri.resolve(scriptName);
|
| + scriptUri = _workingDirectoryUri.resolveUri(scriptUri);
|
| }
|
| - if (_logBuiltin) {
|
| - _print('# Resolved entry point to: $_entryPointScript');
|
| - }
|
| - return _entryPointScript.toString();
|
| -}
|
|
|
| + // Remember the entry point script URI so that we can resolve packages
|
| + // based on this location.
|
| + _entryPointScript = scriptUri;
|
|
|
| -// Function called by standalone embedder to resolve uris.
|
| -String _resolveUri(String base, String userString) {
|
| - if (_logBuiltin) {
|
| - _print('# Resolving: $userString from $base');
|
| + if (_logLoading) {
|
| + _print('# Resolved entry point to: $_entryPointScript');
|
| }
|
| - var baseUri = Uri.parse(base);
|
| - if (userString.startsWith(_DART_EXT)) {
|
| - var uri = userString.substring(_DART_EXT.length);
|
| - return '$_DART_EXT${baseUri.resolve(uri)}';
|
| - } else {
|
| - return baseUri.resolve(userString).toString();
|
| - }
|
| + return scriptUri;
|
| }
|
|
|
| -Uri _createUri(String userUri) {
|
| - var uri = Uri.parse(userUri);
|
| - switch (uri.scheme) {
|
| - case '':
|
| - case 'data':
|
| - case 'file':
|
| - case 'http':
|
| - case 'https':
|
| - return uri;
|
| - case 'package':
|
| - return _resolvePackageUri(uri);
|
| - default:
|
| - // Only handling file, http[s], and package URIs
|
| - // in standalone binary.
|
| - if (_logBuiltin) {
|
| - _print('# Unknown scheme (${uri.scheme}) in $uri.');
|
| - }
|
| - throw 'Not a known scheme: $uri';
|
| - }
|
| -}
|
|
|
| -int _numOutstandingLoadRequests = 0;
|
| -void _finishedOneLoadRequest(String uri) {
|
| +void _finishLoadRequest(String uri) {
|
| assert(_numOutstandingLoadRequests > 0);
|
| _numOutstandingLoadRequests--;
|
| - if (_logBuiltin) {
|
| + if (_logLoading) {
|
| _print("Loading of $uri finished, "
|
| "${_numOutstandingLoadRequests} requests remaining");
|
| }
|
| @@ -245,38 +239,28 @@
|
| }
|
| }
|
|
|
| -void _startingOneLoadRequest(String uri) {
|
| +
|
| +void _startLoadRequest(String uri, Uri resourceUri) {
|
| assert(_numOutstandingLoadRequests >= 0);
|
| _numOutstandingLoadRequests++;
|
| - if (_logBuiltin) {
|
| - _print("Loading of $uri started, "
|
| + if (_logLoading) {
|
| + _print("Loading of $resourceUri for $uri started, "
|
| "${_numOutstandingLoadRequests} requests outstanding");
|
| }
|
| }
|
|
|
| -class LoadError extends Error {
|
| - final String message;
|
| - LoadError(this.message);
|
|
|
| - 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) {
|
| +void _loadScript(int tag, String uri, String libraryUri, Uint8List 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);
|
| - _finishedOneLoadRequest(uri);
|
| + _finishLoadRequest(uri);
|
| }
|
|
|
| +
|
| void _asyncLoadError(int tag, String uri, String libraryUri, LoadError error) {
|
| - if (_logBuiltin) {
|
| + if (_logLoading) {
|
| _print("_asyncLoadError($uri), error: $error");
|
| }
|
| if (tag == Dart_kImportTag) {
|
| @@ -285,18 +269,18 @@
|
| libraryUri = uri;
|
| }
|
| _asyncLoadErrorCallback(uri, libraryUri, error);
|
| - _finishedOneLoadRequest(uri);
|
| + _finishLoadRequest(uri);
|
| }
|
|
|
|
|
| -_loadDataAsyncLoadPort(int tag,
|
| - String uri,
|
| - String libraryUri,
|
| - Uri resourceUri) {
|
| +_loadDataFromLoadPort(int tag,
|
| + String uri,
|
| + String libraryUri,
|
| + Uri resourceUri) {
|
| var receivePort = new ReceivePort();
|
| receivePort.first.then((dataOrError) {
|
| receivePort.close();
|
| - if (dataOrError is List<int>) {
|
| + if (dataOrError is Uint8List) {
|
| _loadScript(tag, uri, libraryUri, dataOrError);
|
| } else {
|
| assert(dataOrError is String);
|
| @@ -314,9 +298,9 @@
|
| try {
|
| var msg = [receivePort.sendPort, resourceUri.toString()];
|
| _loadPort.send(msg);
|
| - _startingOneLoadRequest(uri);
|
| + _startLoadRequest(uri, resourceUri);
|
| } catch (e) {
|
| - if (_logBuiltin) {
|
| + if (_logLoading) {
|
| _print("Exception when communicating with service isolate: $e");
|
| }
|
| // Wrap inside a LoadError unless we are already propagating a previously
|
| @@ -327,21 +311,92 @@
|
| }
|
| }
|
|
|
| +
|
| +// Embedder Entrypoint:
|
| // Asynchronously loads script data through a http[s] or file uri.
|
| _loadDataAsync(int tag, String uri, String libraryUri) {
|
| + var resourceUri;
|
| if (tag == Dart_kScriptTag) {
|
| - uri = _resolveScriptUri(uri);
|
| + resourceUri = _resolveScriptUri(uri);
|
| + uri = resourceUri.toString();
|
| + } else {
|
| + resourceUri = Uri.parse(uri);
|
| }
|
|
|
| - Uri resourceUri = _createUri(uri);
|
| + // package based uris need to be resolved to the correct loadable location.
|
| + if (resourceUri.scheme == 'package') {
|
| + resourceUri = _resolvePackageUri(resourceUri);
|
| + }
|
|
|
| - _loadDataAsyncLoadPort(tag, uri, libraryUri, resourceUri);
|
| + _loadDataFromLoadPort(tag, uri, libraryUri, resourceUri);
|
| }
|
|
|
| +
|
| +// Embedder Entrypoint:
|
| +// Function called by standalone embedder to resolve uris when the VM requests
|
| +// Dart_kCanonicalizeUrl from the tag handler.
|
| +String _resolveUri(String base, String userString) {
|
| + if (_logLoading) {
|
| + _print('# Resolving: $userString from $base');
|
| + }
|
| + var baseUri = Uri.parse(base);
|
| + var result;
|
| + if (userString.startsWith(_DART_EXT)) {
|
| + var uri = userString.substring(_DART_EXT.length);
|
| + result = '$_DART_EXT${baseUri.resolve(uri)}';
|
| + } else {
|
| + result = baseUri.resolve(userString).toString();
|
| + }
|
| + if (_logLoading) {
|
| + _print('Resolved $userString in $base to $result');
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +// Embedder Entrypoint (gen_snapshot):
|
| +// Resolve relative paths relative to working directory.
|
| +String _resolveInWorkingDirectory(String fileName) {
|
| + if (_workingDirectoryUri == null) {
|
| + throw 'No current working directory set.';
|
| + }
|
| + var name = _sanitizeWindowsPath(fileName);
|
| +
|
| + var uri = Uri.parse(name);
|
| + if (uri.scheme != '') {
|
| + throw 'Schemes are not supported when resolving filenames.';
|
| + }
|
| + uri = _workingDirectoryUri.resolveUri(uri);
|
| +
|
| + if (_logLoading) {
|
| + _print('# Resolved in working directory: $fileName -> $uri');
|
| + }
|
| + return uri.toString();
|
| +}
|
| +
|
| +
|
| +// Handling of dart-ext loading.
|
| +// Dart native extension scheme.
|
| +const _DART_EXT = 'dart-ext:';
|
| +
|
| +String _nativeLibraryExtension() native "Builtin_NativeLibraryExtension";
|
| +
|
| +
|
| +String _platformExtensionFileName(String name) {
|
| + var extension = _nativeLibraryExtension();
|
| +
|
| + if (_isWindows) {
|
| + return '$name.$extension';
|
| + } else {
|
| + return 'lib$name.$extension';
|
| + }
|
| +}
|
| +
|
| +
|
| // 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) {
|
| + if (_logLoading) {
|
| _print('# Getting file path from: $uri');
|
| }
|
|
|
| @@ -349,35 +404,27 @@
|
| switch (uri.scheme) {
|
| case '':
|
| case 'file':
|
| - return uri.toFilePath();
|
| + return uri.toFilePath();
|
| case 'package':
|
| - return _filePathFromUri(_resolvePackageUri(uri).toString());
|
| + return _filePathFromUri(_resolvePackageUri(uri).toString());
|
| case 'data':
|
| case 'http':
|
| case 'https':
|
| - return uri.toString();
|
| + return uri.toString();
|
| default:
|
| - // Only handling file, http, and package URIs
|
| - // in standalone binary.
|
| - if (_logBuiltin) {
|
| - _print('# Unknown scheme (${uri.scheme}) in $uri.');
|
| - }
|
| - throw 'Not a known scheme: $uri';
|
| + // Only handling file, http, and package URIs
|
| + // in standalone binary.
|
| + if (_logLoading) {
|
| + _print('# Unknown scheme (${uri.scheme}) in $uri.');
|
| + }
|
| + throw 'Not a known scheme: $uri';
|
| }
|
| }
|
|
|
| -String _nativeLibraryExtension() native "Builtin_NativeLibraryExtension";
|
|
|
| -String _platformExtensionFileName(String name) {
|
| - var extension = _nativeLibraryExtension();
|
| -
|
| - if (_isWindows) {
|
| - return '$name.$extension';
|
| - } else {
|
| - return 'lib$name.$extension';
|
| - }
|
| -}
|
| -
|
| +// Embedder Entrypoint:
|
| +// When loading an extension the embedder calls this method to get the
|
| +// different components.
|
| // Returns the directory part, the filename part, and the name
|
| // of a native extension URL as a list [directory, filename, name].
|
| // The directory part is either a file system path or an HTTP(S) URL.
|
| @@ -393,7 +440,6 @@
|
| throw 'Unexpected internal error: Extension URI $userUri contains \\';
|
| }
|
|
|
| -
|
| String name;
|
| String path; // Will end in '/'.
|
| int index = userUri.lastIndexOf('/');
|
|
|