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('/'); |