Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library builtin; | 5 library builtin; |
| 6 // NOTE: Do not import 'dart:io' in builtin. | 6 // NOTE: Do not import 'dart:io' in builtin. |
| 7 import 'dart:async'; | |
| 8 import 'dart:convert'; | |
| 9 import 'dart:isolate'; | 7 import 'dart:isolate'; |
| 10 | 8 import 'dart:typed_data'; |
| 11 | |
| 12 /* See Dart_LibraryTag in dart_api.h */ | |
| 13 const Dart_kScriptTag = null; | |
| 14 const Dart_kImportTag = 0; | |
| 15 const Dart_kSourceTag = 1; | |
| 16 const Dart_kCanonicalizeUrl = 2; | |
| 17 | |
| 18 // Dart native extension scheme. | |
| 19 const _DART_EXT = 'dart-ext:'; | |
| 20 | 9 |
| 21 // import 'root_library'; happens here from C Code | 10 // import 'root_library'; happens here from C Code |
|
siva
2015/05/08 23:57:07
This comment seems out dated now.
| |
| 22 | 11 |
| 12 // Build time flag to enable debug logging of loading code. | |
| 13 const _logLoading = false; | |
| 14 | |
| 15 | |
| 23 // The root library (aka the script) is imported into this library. The | 16 // The root library (aka the script) is imported into this library. The |
| 24 // standalone embedder uses this to lookup the main entrypoint in the | 17 // standalone embedder uses this to lookup the main entrypoint in the |
| 25 // root library's namespace. | 18 // root library's namespace. |
| 26 Function _getMainClosure() => main; | 19 Function _getMainClosure() => main; |
| 27 | 20 |
| 28 // A port for communicating with the service isolate for I/O. | |
| 29 SendPort _loadPort; | |
| 30 | 21 |
| 31 const _logBuiltin = false; | 22 // 'print' implementation. |
| 23 // The standalone embedder registers the closurized _print function with the | |
| 24 // dart:core library. | |
| 25 void _printString(String s) native "Builtin_PrintString"; | |
| 32 | 26 |
| 33 // Corelib 'print' implementation. | 27 |
| 34 void _print(arg) { | 28 void _print(arg) { |
| 35 _Logger._printString(arg.toString()); | 29 _printString(arg.toString()); |
| 36 } | 30 } |
| 37 | 31 |
| 38 class _Logger { | |
| 39 static void _printString(String s) native "Logger_PrintString"; | |
| 40 } | |
| 41 | 32 |
| 42 _getPrintClosure() => _print; | 33 _getPrintClosure() => _print; |
| 43 | 34 |
| 35 | |
| 36 // Corelib 'Uri.base' implementation. | |
| 37 // Uri.base is susceptible to changes in the current working directory. | |
| 44 _getCurrentDirectoryPath() native "Builtin_GetCurrentDirectory"; | 38 _getCurrentDirectoryPath() native "Builtin_GetCurrentDirectory"; |
| 45 | 39 |
| 46 // Corelib 'Uri.base' implementation. | 40 |
| 47 Uri _uriBase() { | 41 Uri _uriBase() { |
| 48 // We are not using Dircetory.current here to limit the dependency | 42 // We are not using Dircetory.current here to limit the dependency |
| 49 // on dart:io. This code is the same as: | 43 // on dart:io. This code is the same as: |
| 50 // return new Uri.file(Directory.current.path + "/"); | 44 // return new Uri.file(Directory.current.path + "/"); |
| 51 var result = _getCurrentDirectoryPath(); | 45 var result = _getCurrentDirectoryPath(); |
| 52 return new Uri.file(result + "/"); | 46 return new Uri.file("$result/"); |
| 53 } | 47 } |
| 54 | 48 |
| 49 | |
| 55 _getUriBaseClosure() => _uriBase; | 50 _getUriBaseClosure() => _uriBase; |
| 56 | 51 |
| 57 | 52 |
| 58 // Are we running on Windows? | 53 // Asynchronous loading of resources. |
| 59 var _isWindows; | 54 // The embedder forwards most loading requests to this library. |
| 60 var _workingWindowsDrivePrefix; | 55 |
| 61 // The current working directory | 56 // See Dart_LibraryTag in dart_api.h |
| 57 const Dart_kScriptTag = null; | |
| 58 const Dart_kImportTag = 0; | |
| 59 const Dart_kSourceTag = 1; | |
| 60 const Dart_kCanonicalizeUrl = 2; | |
| 61 | |
| 62 // A port for communicating with the service isolate for I/O. | |
| 63 SendPort _loadPort; | |
| 64 // Maintain a number of outstanding load requests. Current loading request is | |
| 65 // finished once there are no outstanding requests. | |
| 66 int _numOutstandingLoadRequests = 0; | |
| 67 | |
| 68 // The current working directory when the embedder was launched. | |
| 62 var _workingDirectoryUri; | 69 var _workingDirectoryUri; |
| 63 // The URI that the entry point script was loaded from. Remembered so that | 70 // The URI that the entry point script was loaded from. Remembered so that |
| 64 // package imports can be resolved relative to it. | 71 // package imports can be resolved relative to it. |
| 65 var _entryPointScript; | 72 var _entryPointScript; |
| 66 // The directory to look in to resolve "package:" scheme URIs. | 73 // The directory to look in to resolve "package:" scheme URIs. By detault it is |
| 67 var _packageRoot; | 74 // the 'packages' directory right next to the script. |
| 75 var _packageRoot = _entryPointScript.resolve('packages/'); | |
| 76 | |
| 77 // Special handling for Windows paths so that they are compatible with URI | |
| 78 // handling. | |
| 79 // Embedder sets whether we are running on Windows. | |
| 80 var _isWindows; | |
| 81 | |
| 82 | |
| 83 // A class wrapping the load error message in an Error object. | |
| 84 class LoadError extends Error { | |
| 85 final String message; | |
| 86 LoadError(this.message); | |
| 87 | |
| 88 String toString() => 'Load Error: $message'; | |
| 89 } | |
| 90 | |
| 91 | |
| 92 // Native calls provided by the embedder. | |
| 93 void _signalDoneLoading() native "Builtin_DoneLoading"; | |
| 94 void _loadScriptCallback(int tag, String uri, String libraryUri, Uint8List data) | |
| 95 native "Builtin_LoadSource"; | |
| 96 void _asyncLoadErrorCallback(uri, libraryUri, error) | |
| 97 native "Builtin_AsyncLoadError"; | |
| 98 | |
| 68 | 99 |
| 69 _sanitizeWindowsPath(path) { | 100 _sanitizeWindowsPath(path) { |
| 70 // For Windows we need to massage the paths a bit according to | 101 // For Windows we need to massage the paths a bit according to |
| 71 // http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx | 102 // http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx |
| 72 // | 103 // |
| 73 // Convert | 104 // Convert |
| 74 // C:\one\two\three | 105 // C:\one\two\three |
| 75 // to | 106 // to |
| 76 // /C:/one/two/three | 107 // /C:/one/two/three |
| 77 | 108 |
| 78 if (_isWindows == false) { | 109 if (_isWindows == false) { |
| 79 // Do nothing when not running Windows. | 110 // Do nothing when not running Windows. |
| 80 return path; | 111 return path; |
| 81 } | 112 } |
| 82 | 113 |
| 83 var fixedPath = "${path.replaceAll('\\', '/')}"; | 114 var fixedPath = "${path.replaceAll('\\', '/')}"; |
| 84 | 115 |
| 85 if ((path.length > 2) && (path[1] == ':')) { | 116 if ((path.length > 2) && (path[1] == ':')) { |
| 86 // Path begins with a drive letter. | 117 // Path begins with a drive letter. |
| 87 return '/$fixedPath'; | 118 return '/$fixedPath'; |
| 88 } | 119 } |
| 89 | 120 |
| 90 return fixedPath; | 121 return fixedPath; |
| 91 } | 122 } |
| 92 | 123 |
| 124 | |
| 93 _trimWindowsPath(path) { | 125 _trimWindowsPath(path) { |
| 94 // Convert /X:/ to X:/. | 126 // Convert /X:/ to X:/. |
| 95 if (_isWindows == false) { | 127 if (_isWindows == false) { |
| 96 // Do nothing when not running Windows. | 128 // Do nothing when not running Windows. |
| 97 return path; | 129 return path; |
| 98 } | 130 } |
| 99 if (!path.startsWith('/') || (path.length < 3)) { | 131 if (!path.startsWith('/') || (path.length < 3)) { |
| 100 return path; | 132 return path; |
| 101 } | 133 } |
| 102 // Match '/?:'. | 134 // Match '/?:'. |
| 103 if ((path[0] == '/') && (path[2] == ':')) { | 135 if ((path[0] == '/') && (path[2] == ':')) { |
| 104 // Remove leading '/'. | 136 // Remove leading '/'. |
| 105 return path.substring(1); | 137 return path.substring(1); |
| 106 } | 138 } |
| 107 return path; | 139 return path; |
| 108 } | 140 } |
| 109 | 141 |
| 142 | |
| 143 // Ensure we have a trailing slash character. | |
| 110 _enforceTrailingSlash(uri) { | 144 _enforceTrailingSlash(uri) { |
| 111 // Ensure we have a trailing slash character. | |
| 112 if (!uri.endsWith('/')) { | 145 if (!uri.endsWith('/')) { |
| 113 return '$uri/'; | 146 return '$uri/'; |
| 114 } | 147 } |
| 115 return uri; | 148 return uri; |
| 116 } | 149 } |
| 117 | 150 |
| 118 | 151 |
| 119 _extractDriveLetterPrefix(cwd) { | 152 // Embedder Entrypoint: |
| 120 if (!_isWindows) { | 153 // The embedder calls this method with the current working directory. |
| 121 return null; | |
| 122 } | |
| 123 if (cwd.length > 1 && cwd[1] == ':') { | |
| 124 return '/${cwd[0]}:'; | |
| 125 } | |
| 126 return null; | |
| 127 } | |
| 128 | |
| 129 | |
| 130 void _setWorkingDirectory(cwd) { | 154 void _setWorkingDirectory(cwd) { |
| 131 _workingWindowsDrivePrefix = _extractDriveLetterPrefix(cwd); | |
| 132 cwd = _sanitizeWindowsPath(cwd); | 155 cwd = _sanitizeWindowsPath(cwd); |
| 133 cwd = _enforceTrailingSlash(cwd); | 156 _workingDirectoryUri = new Uri.directory(cwd); |
| 134 _workingDirectoryUri = new Uri(scheme: 'file', path: cwd); | 157 if (_logLoading) { |
| 135 if (_logBuiltin) { | 158 _print('# Working Directory: $cwd -> $_workingDirectoryUri'); |
| 136 _print('# Working Directory: $cwd'); | |
| 137 } | 159 } |
| 138 } | 160 } |
| 139 | 161 |
| 140 | 162 |
| 163 // Embedder Entrypoint: | |
| 164 // The embedder calls this method with a custom package root. | |
| 141 _setPackageRoot(String packageRoot) { | 165 _setPackageRoot(String packageRoot) { |
| 142 packageRoot = _enforceTrailingSlash(packageRoot); | 166 packageRoot = _enforceTrailingSlash(packageRoot); |
| 143 if (packageRoot.startsWith('file:') || | 167 if (packageRoot.startsWith('file:') || |
| 144 packageRoot.startsWith('http:') || | 168 packageRoot.startsWith('http:') || |
| 145 packageRoot.startsWith('https:')) { | 169 packageRoot.startsWith('https:')) { |
| 146 _packageRoot = _workingDirectoryUri.resolve(packageRoot); | 170 _packageRoot = _workingDirectoryUri.resolve(packageRoot); |
| 147 } else { | 171 } else { |
| 148 packageRoot = _sanitizeWindowsPath(packageRoot); | 172 packageRoot = _sanitizeWindowsPath(packageRoot); |
| 149 packageRoot = _trimWindowsPath(packageRoot); | 173 packageRoot = _trimWindowsPath(packageRoot); |
| 150 _packageRoot = _workingDirectoryUri.resolveUri(new Uri.file(packageRoot)); | 174 _packageRoot = _workingDirectoryUri.resolveUri(new Uri.file(packageRoot)); |
| 151 } | 175 } |
| 152 if (_logBuiltin) { | 176 if (_logLoading) { |
| 153 _print('# Package root: $packageRoot -> $_packageRoot'); | 177 _print('# Package root: $packageRoot -> $_packageRoot'); |
| 154 } | 178 } |
| 155 } | 179 } |
| 156 | 180 |
| 157 | 181 |
| 158 // Given a uri with a 'package' scheme, return a Uri that is prefixed with | 182 // Given a uri with a 'package' scheme, return a Uri that is prefixed with |
| 159 // the package root. | 183 // the package root. |
| 160 Uri _resolvePackageUri(Uri uri) { | 184 Uri _resolvePackageUri(Uri uri) { |
| 161 if (!uri.host.isEmpty) { | 185 if (!uri.host.isEmpty) { |
| 162 var path = '${uri.host}${uri.path}'; | 186 var path = '${uri.host}${uri.path}'; |
| 163 var right = 'package:$path'; | 187 var right = 'package:$path'; |
| 164 var wrong = 'package://$path'; | 188 var wrong = 'package://$path'; |
| 165 | 189 |
| 166 throw "URIs using the 'package:' scheme should look like " | 190 throw "URIs using the 'package:' scheme should look like " |
| 167 "'$right', not '$wrong'."; | 191 "'$right', not '$wrong'."; |
| 168 } | 192 } |
| 169 | 193 |
| 170 var packageRoot = _packageRoot == null ? | 194 if (_logLoading) { |
| 171 _entryPointScript.resolve('packages/') : | 195 _print('# Package root: $_packageRoot'); |
| 172 _packageRoot; | 196 _print('# uri path: ${uri.path}'); |
| 173 return packageRoot.resolve(uri.path); | 197 } |
| 198 return _packageRoot.resolve(uri.path); | |
| 174 } | 199 } |
| 175 | 200 |
| 176 | 201 |
| 177 | 202 // Resolves the script uri in the current working directory iff the given uri |
| 178 String _resolveScriptUri(String scriptName) { | 203 // did not specify a scheme (e.g. a path to a script file on the command line). |
| 204 Uri _resolveScriptUri(String scriptName) { | |
| 179 if (_workingDirectoryUri == null) { | 205 if (_workingDirectoryUri == null) { |
| 180 throw 'No current working directory set.'; | 206 throw 'No current working directory set.'; |
| 181 } | 207 } |
| 182 scriptName = _sanitizeWindowsPath(scriptName); | 208 scriptName = _sanitizeWindowsPath(scriptName); |
| 183 | 209 |
| 184 var scriptUri = Uri.parse(scriptName); | 210 var scriptUri = Uri.parse(scriptName); |
| 185 if (scriptUri.scheme != '') { | 211 if (scriptUri.scheme == '') { |
| 186 // Script has a scheme, assume that it is fully formed. | |
| 187 _entryPointScript = scriptUri; | |
| 188 } else { | |
| 189 // Script does not have a scheme, assume that it is a path, | 212 // Script does not have a scheme, assume that it is a path, |
| 190 // resolve it against the working directory. | 213 // resolve it against the working directory. |
| 191 _entryPointScript = _workingDirectoryUri.resolve(scriptName); | 214 scriptUri = _workingDirectoryUri.resolveUri(scriptUri); |
| 192 } | 215 } |
| 193 if (_logBuiltin) { | 216 |
| 217 // Remember the entry point script URI so that we can resolve packages | |
| 218 // based on this location. | |
| 219 _entryPointScript = scriptUri; | |
| 220 | |
| 221 if (_logLoading) { | |
| 194 _print('# Resolved entry point to: $_entryPointScript'); | 222 _print('# Resolved entry point to: $_entryPointScript'); |
| 195 } | 223 } |
| 196 return _entryPointScript.toString(); | 224 return scriptUri; |
| 197 } | 225 } |
| 198 | 226 |
| 199 | 227 |
| 200 // Function called by standalone embedder to resolve uris. | 228 void _finishLoadRequest(String uri) { |
| 201 String _resolveUri(String base, String userString) { | |
| 202 if (_logBuiltin) { | |
| 203 _print('# Resolving: $userString from $base'); | |
| 204 } | |
| 205 var baseUri = Uri.parse(base); | |
| 206 if (userString.startsWith(_DART_EXT)) { | |
| 207 var uri = userString.substring(_DART_EXT.length); | |
| 208 return '$_DART_EXT${baseUri.resolve(uri)}'; | |
| 209 } else { | |
| 210 return baseUri.resolve(userString).toString(); | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 Uri _createUri(String userUri) { | |
| 215 var uri = Uri.parse(userUri); | |
| 216 switch (uri.scheme) { | |
| 217 case '': | |
| 218 case 'data': | |
| 219 case 'file': | |
| 220 case 'http': | |
| 221 case 'https': | |
| 222 return uri; | |
| 223 case 'package': | |
| 224 return _resolvePackageUri(uri); | |
| 225 default: | |
| 226 // Only handling file, http[s], and package URIs | |
| 227 // in standalone binary. | |
| 228 if (_logBuiltin) { | |
| 229 _print('# Unknown scheme (${uri.scheme}) in $uri.'); | |
| 230 } | |
| 231 throw 'Not a known scheme: $uri'; | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 int _numOutstandingLoadRequests = 0; | |
| 236 void _finishedOneLoadRequest(String uri) { | |
| 237 assert(_numOutstandingLoadRequests > 0); | 229 assert(_numOutstandingLoadRequests > 0); |
| 238 _numOutstandingLoadRequests--; | 230 _numOutstandingLoadRequests--; |
| 239 if (_logBuiltin) { | 231 if (_logLoading) { |
| 240 _print("Loading of $uri finished, " | 232 _print("Loading of $uri finished, " |
| 241 "${_numOutstandingLoadRequests} requests remaining"); | 233 "${_numOutstandingLoadRequests} requests remaining"); |
| 242 } | 234 } |
| 243 if (_numOutstandingLoadRequests == 0) { | 235 if (_numOutstandingLoadRequests == 0) { |
| 244 _signalDoneLoading(); | 236 _signalDoneLoading(); |
| 245 } | 237 } |
| 246 } | 238 } |
| 247 | 239 |
| 248 void _startingOneLoadRequest(String uri) { | 240 |
| 241 void _startLoadRequest(String uri, Uri resourceUri) { | |
| 249 assert(_numOutstandingLoadRequests >= 0); | 242 assert(_numOutstandingLoadRequests >= 0); |
| 250 _numOutstandingLoadRequests++; | 243 _numOutstandingLoadRequests++; |
| 251 if (_logBuiltin) { | 244 if (_logLoading) { |
| 252 _print("Loading of $uri started, " | 245 _print("Loading of $resourceUri for $uri started, " |
| 253 "${_numOutstandingLoadRequests} requests outstanding"); | 246 "${_numOutstandingLoadRequests} requests outstanding"); |
| 254 } | 247 } |
| 255 } | 248 } |
| 256 | 249 |
| 257 class LoadError extends Error { | |
| 258 final String message; | |
| 259 LoadError(this.message); | |
| 260 | 250 |
| 261 String toString() => 'Load Error: $message'; | 251 void _loadScript(int tag, String uri, String libraryUri, Uint8List data) { |
| 262 } | |
| 263 | |
| 264 void _signalDoneLoading() native "Builtin_DoneLoading"; | |
| 265 void _loadScriptCallback(int tag, String uri, String libraryUri, List<int> data) | |
| 266 native "Builtin_LoadScript"; | |
| 267 void _asyncLoadErrorCallback(uri, libraryUri, error) | |
| 268 native "Builtin_AsyncLoadError"; | |
| 269 | |
| 270 void _loadScript(int tag, String uri, String libraryUri, List<int> data) { | |
| 271 // TODO: Currently a compilation error while loading the script is | 252 // TODO: Currently a compilation error while loading the script is |
| 272 // fatal for the isolate. _loadScriptCallback() does not return and | 253 // fatal for the isolate. _loadScriptCallback() does not return and |
| 273 // the _numOutstandingLoadRequests counter remains out of sync. | 254 // the _numOutstandingLoadRequests counter remains out of sync. |
| 274 _loadScriptCallback(tag, uri, libraryUri, data); | 255 _loadScriptCallback(tag, uri, libraryUri, data); |
| 275 _finishedOneLoadRequest(uri); | 256 _finishLoadRequest(uri); |
| 276 } | 257 } |
| 277 | 258 |
| 259 | |
| 278 void _asyncLoadError(int tag, String uri, String libraryUri, LoadError error) { | 260 void _asyncLoadError(int tag, String uri, String libraryUri, LoadError error) { |
| 279 if (_logBuiltin) { | 261 if (_logLoading) { |
| 280 _print("_asyncLoadError($uri), error: $error"); | 262 _print("_asyncLoadError($uri), error: $error"); |
| 281 } | 263 } |
| 282 if (tag == Dart_kImportTag) { | 264 if (tag == Dart_kImportTag) { |
| 283 // When importing a library, the libraryUri is the imported | 265 // When importing a library, the libraryUri is the imported |
| 284 // uri. | 266 // uri. |
| 285 libraryUri = uri; | 267 libraryUri = uri; |
| 286 } | 268 } |
| 287 _asyncLoadErrorCallback(uri, libraryUri, error); | 269 _asyncLoadErrorCallback(uri, libraryUri, error); |
| 288 _finishedOneLoadRequest(uri); | 270 _finishLoadRequest(uri); |
| 289 } | 271 } |
| 290 | 272 |
| 291 | 273 |
| 292 _loadDataAsyncLoadPort(int tag, | 274 _loadDataFromLoadPort(int tag, |
| 293 String uri, | 275 String uri, |
| 294 String libraryUri, | 276 String libraryUri, |
| 295 Uri resourceUri) { | 277 Uri resourceUri) { |
| 296 var receivePort = new ReceivePort(); | 278 var receivePort = new ReceivePort(); |
| 297 receivePort.first.then((dataOrError) { | 279 receivePort.first.then((dataOrError) { |
| 298 receivePort.close(); | 280 receivePort.close(); |
| 299 if (dataOrError is List<int>) { | 281 if (dataOrError is Uint8List) { |
| 300 _loadScript(tag, uri, libraryUri, dataOrError); | 282 _loadScript(tag, uri, libraryUri, dataOrError); |
| 301 } else { | 283 } else { |
| 302 assert(dataOrError is String); | 284 assert(dataOrError is String); |
| 303 var error = new LoadError(dataOrError.toString()); | 285 var error = new LoadError(dataOrError.toString()); |
| 304 _asyncLoadError(tag, uri, libraryUri, error); | 286 _asyncLoadError(tag, uri, libraryUri, error); |
| 305 } | 287 } |
| 306 }).catchError((e) { | 288 }).catchError((e) { |
| 307 receivePort.close(); | 289 receivePort.close(); |
| 308 // Wrap inside a LoadError unless we are already propagating a previously | 290 // Wrap inside a LoadError unless we are already propagating a previously |
| 309 // seen LoadError. | 291 // seen LoadError. |
| 310 var error = (e is LoadError) ? e : new LoadError(e.toString); | 292 var error = (e is LoadError) ? e : new LoadError(e.toString); |
| 311 _asyncLoadError(tag, uri, libraryUri, error); | 293 _asyncLoadError(tag, uri, libraryUri, error); |
| 312 }); | 294 }); |
| 313 | 295 |
| 314 try { | 296 try { |
| 315 var msg = [receivePort.sendPort, resourceUri.toString()]; | 297 var msg = [receivePort.sendPort, resourceUri.toString()]; |
| 316 _loadPort.send(msg); | 298 _loadPort.send(msg); |
| 317 _startingOneLoadRequest(uri); | 299 _startLoadRequest(uri, resourceUri); |
| 318 } catch (e) { | 300 } catch (e) { |
| 319 if (_logBuiltin) { | 301 if (_logLoading) { |
| 320 _print("Exception when communicating with service isolate: $e"); | 302 _print("Exception when communicating with service isolate: $e"); |
| 321 } | 303 } |
| 322 // Wrap inside a LoadError unless we are already propagating a previously | 304 // Wrap inside a LoadError unless we are already propagating a previously |
| 323 // seen LoadError. | 305 // seen LoadError. |
| 324 var error = (e is LoadError) ? e : new LoadError(e.toString); | 306 var error = (e is LoadError) ? e : new LoadError(e.toString); |
| 325 _asyncLoadError(tag, uri, libraryUri, error); | 307 _asyncLoadError(tag, uri, libraryUri, error); |
| 326 receivePort.close(); | 308 receivePort.close(); |
| 327 } | 309 } |
| 328 } | 310 } |
| 329 | 311 |
| 312 | |
| 313 // Embedder Entrypoint: | |
| 330 // Asynchronously loads script data through a http[s] or file uri. | 314 // Asynchronously loads script data through a http[s] or file uri. |
| 331 _loadDataAsync(int tag, String uri, String libraryUri) { | 315 _loadDataAsync(int tag, String uri, String libraryUri) { |
| 316 var resourceUri; | |
| 332 if (tag == Dart_kScriptTag) { | 317 if (tag == Dart_kScriptTag) { |
| 333 uri = _resolveScriptUri(uri); | 318 resourceUri = _resolveScriptUri(uri); |
| 319 uri = resourceUri.toString(); | |
| 320 } else { | |
| 321 resourceUri = Uri.parse(uri); | |
| 334 } | 322 } |
| 335 | 323 |
| 336 Uri resourceUri = _createUri(uri); | 324 // package based uris need to be resolved to the correct loadable location. |
| 325 if (resourceUri.scheme == 'package') { | |
| 326 resourceUri = _resolvePackageUri(resourceUri); | |
| 327 } | |
| 337 | 328 |
| 338 _loadDataAsyncLoadPort(tag, uri, libraryUri, resourceUri); | 329 _loadDataFromLoadPort(tag, uri, libraryUri, resourceUri); |
| 339 } | 330 } |
| 340 | 331 |
| 332 | |
| 333 // Embedder Entrypoint: | |
| 334 // Function called by standalone embedder to resolve uris when the VM requests | |
| 335 // Dart_kCanonicalizeUrl from the tag handler. | |
| 336 String _resolveUri(String base, String userString) { | |
| 337 if (_logLoading) { | |
| 338 _print('# Resolving: $userString from $base'); | |
| 339 } | |
| 340 var baseUri = Uri.parse(base); | |
| 341 var result; | |
| 342 if (userString.startsWith(_DART_EXT)) { | |
| 343 var uri = userString.substring(_DART_EXT.length); | |
| 344 result = '$_DART_EXT${baseUri.resolve(uri)}'; | |
| 345 } else { | |
| 346 result = baseUri.resolve(userString).toString(); | |
| 347 } | |
| 348 if (_logLoading) { | |
| 349 _print('Resolved $userString in $base to $result'); | |
| 350 } | |
| 351 return result; | |
| 352 } | |
| 353 | |
| 354 | |
| 355 // Embedder Entrypoint (gen_snapshot): | |
| 356 // Resolve relative paths relative to working directory. | |
| 357 String _resolveInWorkingDirectory(String fileName) { | |
| 358 if (_workingDirectoryUri == null) { | |
| 359 throw 'No current working directory set.'; | |
| 360 } | |
| 361 var name = _sanitizeWindowsPath(fileName); | |
| 362 | |
| 363 var uri = Uri.parse(name); | |
| 364 if (uri.scheme != '') { | |
| 365 throw 'Schemes are not supported when resolving filenames.'; | |
| 366 } | |
| 367 uri = _workingDirectoryUri.resolveUri(uri); | |
| 368 | |
| 369 if (_logLoading) { | |
| 370 _print('# Resolved in working directory: $fileName -> $uri'); | |
| 371 } | |
| 372 return uri.toString(); | |
| 373 } | |
| 374 | |
| 375 | |
| 376 // Handling of dart-ext loading. | |
| 377 // Dart native extension scheme. | |
| 378 const _DART_EXT = 'dart-ext:'; | |
| 379 | |
| 380 String _nativeLibraryExtension() native "Builtin_NativeLibraryExtension"; | |
| 381 | |
| 382 | |
| 383 String _platformExtensionFileName(String name) { | |
| 384 var extension = _nativeLibraryExtension(); | |
| 385 | |
| 386 if (_isWindows) { | |
| 387 return '$name.$extension'; | |
| 388 } else { | |
| 389 return 'lib$name.$extension'; | |
| 390 } | |
| 391 } | |
| 392 | |
| 393 | |
| 341 // Returns either a file path or a URI starting with http[s]:, as a String. | 394 // Returns either a file path or a URI starting with http[s]:, as a String. |
| 342 String _filePathFromUri(String userUri) { | 395 String _filePathFromUri(String userUri) { |
| 343 var uri = Uri.parse(userUri); | 396 var uri = Uri.parse(userUri); |
| 344 if (_logBuiltin) { | 397 if (_logLoading) { |
| 345 _print('# Getting file path from: $uri'); | 398 _print('# Getting file path from: $uri'); |
| 346 } | 399 } |
| 347 | 400 |
| 348 var path; | 401 var path; |
| 349 switch (uri.scheme) { | 402 switch (uri.scheme) { |
| 350 case '': | 403 case '': |
| 351 case 'file': | 404 case 'file': |
| 352 return uri.toFilePath(); | 405 return uri.toFilePath(); |
| 353 case 'package': | 406 case 'package': |
| 354 return _filePathFromUri(_resolvePackageUri(uri).toString()); | 407 return _filePathFromUri(_resolvePackageUri(uri).toString()); |
| 355 case 'data': | 408 case 'data': |
| 356 case 'http': | 409 case 'http': |
| 357 case 'https': | 410 case 'https': |
| 358 return uri.toString(); | 411 return uri.toString(); |
| 359 default: | 412 default: |
| 360 // Only handling file, http, and package URIs | 413 // Only handling file, http, and package URIs |
| 361 // in standalone binary. | 414 // in standalone binary. |
| 362 if (_logBuiltin) { | 415 if (_logLoading) { |
| 363 _print('# Unknown scheme (${uri.scheme}) in $uri.'); | 416 _print('# Unknown scheme (${uri.scheme}) in $uri.'); |
| 364 } | 417 } |
| 365 throw 'Not a known scheme: $uri'; | 418 throw 'Not a known scheme: $uri'; |
| 366 } | 419 } |
| 367 } | 420 } |
| 368 | 421 |
| 369 String _nativeLibraryExtension() native "Builtin_NativeLibraryExtension"; | |
| 370 | 422 |
| 371 String _platformExtensionFileName(String name) { | 423 // Embedder Entrypoint: |
| 372 var extension = _nativeLibraryExtension(); | 424 // When loading an extension the embedder calls this method to get the |
| 373 | 425 // different components. |
| 374 if (_isWindows) { | |
| 375 return '$name.$extension'; | |
| 376 } else { | |
| 377 return 'lib$name.$extension'; | |
| 378 } | |
| 379 } | |
| 380 | |
| 381 // Returns the directory part, the filename part, and the name | 426 // Returns the directory part, the filename part, and the name |
| 382 // of a native extension URL as a list [directory, filename, name]. | 427 // of a native extension URL as a list [directory, filename, name]. |
| 383 // The directory part is either a file system path or an HTTP(S) URL. | 428 // The directory part is either a file system path or an HTTP(S) URL. |
| 384 // The filename part is the extension name, with the platform-dependent | 429 // The filename part is the extension name, with the platform-dependent |
| 385 // prefixes and extensions added. | 430 // prefixes and extensions added. |
| 386 _extensionPathFromUri(String userUri) { | 431 _extensionPathFromUri(String userUri) { |
| 387 if (!userUri.startsWith(_DART_EXT)) { | 432 if (!userUri.startsWith(_DART_EXT)) { |
| 388 throw 'Unexpected internal error: Extension URI $userUri missing dart-ext:'; | 433 throw 'Unexpected internal error: Extension URI $userUri missing dart-ext:'; |
| 389 } | 434 } |
| 390 userUri = userUri.substring(_DART_EXT.length); | 435 userUri = userUri.substring(_DART_EXT.length); |
| 391 | 436 |
| 392 if (userUri.contains('\\')) { | 437 if (userUri.contains('\\')) { |
| 393 throw 'Unexpected internal error: Extension URI $userUri contains \\'; | 438 throw 'Unexpected internal error: Extension URI $userUri contains \\'; |
| 394 } | 439 } |
| 395 | 440 |
| 396 | |
| 397 String name; | 441 String name; |
| 398 String path; // Will end in '/'. | 442 String path; // Will end in '/'. |
| 399 int index = userUri.lastIndexOf('/'); | 443 int index = userUri.lastIndexOf('/'); |
| 400 if (index == -1) { | 444 if (index == -1) { |
| 401 name = userUri; | 445 name = userUri; |
| 402 path = './'; | 446 path = './'; |
| 403 } else if (index == userUri.length - 1) { | 447 } else if (index == userUri.length - 1) { |
| 404 throw 'Extension name missing in $extensionUri'; | 448 throw 'Extension name missing in $extensionUri'; |
| 405 } else { | 449 } else { |
| 406 name = userUri.substring(index + 1); | 450 name = userUri.substring(index + 1); |
| 407 path = userUri.substring(0, index + 1); | 451 path = userUri.substring(0, index + 1); |
| 408 } | 452 } |
| 409 | 453 |
| 410 path = _filePathFromUri(path); | 454 path = _filePathFromUri(path); |
| 411 var filename = _platformExtensionFileName(name); | 455 var filename = _platformExtensionFileName(name); |
| 412 | 456 |
| 413 return [path, filename, name]; | 457 return [path, filename, name]; |
| 414 } | 458 } |
| OLD | NEW |