Chromium Code Reviews| Index: runtime/bin/builtin.dart |
| =================================================================== |
| --- runtime/bin/builtin.dart (revision 45623) |
| +++ 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 |
|
siva
2015/05/08 23:57:07
This comment seems out dated now.
|
| -/* 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,19 @@ |
| } |
| -_extractDriveLetterPrefix(cwd) { |
| - if (!_isWindows) { |
| - return null; |
| - } |
| - if (cwd.length > 1 && cwd[1] == ':') { |
| - return '/${cwd[0]}:'; |
| - } |
| - return null; |
| -} |
| - |
| - |
| +// Embedder Entrypoint: |
| +// The embedder calls this method with the current working directory. |
| 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'); |
| + _workingDirectoryUri = new Uri.directory(cwd); |
| + if (_logLoading) { |
| + _print('# Working Directory: $cwd -> $_workingDirectoryUri'); |
| } |
| } |
| +// Embedder Entrypoint: |
| +// The embedder calls this method with a custom package root. |
| _setPackageRoot(String packageRoot) { |
| packageRoot = _enforceTrailingSlash(packageRoot); |
| if (packageRoot.startsWith('file:') || |
| @@ -149,7 +173,7 @@ |
| packageRoot = _trimWindowsPath(packageRoot); |
| _packageRoot = _workingDirectoryUri.resolveUri(new Uri.file(packageRoot)); |
| } |
| - if (_logBuiltin) { |
| + if (_logLoading) { |
| _print('# Package root: $packageRoot -> $_packageRoot'); |
| } |
| } |
| @@ -167,76 +191,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 +237,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 +267,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 +296,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 +309,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 +402,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 +438,6 @@ |
| throw 'Unexpected internal error: Extension URI $userUri contains \\'; |
| } |
| - |
| String name; |
| String path; // Will end in '/'. |
| int index = userUri.lastIndexOf('/'); |