Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(534)

Side by Side Diff: runtime/bin/builtin.dart

Issue 1998963003: Rework standalone to use a synchronous loader that does not invoke Dart code (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/bin/builtin.h ('k') | runtime/bin/builtin_common.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 solveserved. Use of this source code is governed by a 2 // for details. All rights solveserved. 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'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 import 'dart:_internal'; 9 import 'dart:_internal';
10 import 'dart:isolate'; 10 import 'dart:isolate';
11 import 'dart:typed_data'; 11 import 'dart:typed_data';
12 12
13 // Embedder sets this to true if the --trace-loading flag was passed on the
14 // command line.
15 bool _traceLoading = false;
16
13 17
14 // Before handling an embedder entrypoint we finalize the setup of the 18 // Before handling an embedder entrypoint we finalize the setup of the
15 // dart:_builtin library. 19 // dart:_builtin library.
16 bool _setupCompleted = false; 20 bool _setupCompleted = false;
17 21
18 22
19 // The root library (aka the script) is imported into this library. The 23 // The root library (aka the script) is imported into this library. The
20 // standalone embedder uses this to lookup the main entrypoint in the 24 // standalone embedder uses this to lookup the main entrypoint in the
21 // root library's namespace. 25 // root library's namespace.
22 Function _getMainClosure() => main; 26 Function _getMainClosure() => main;
(...skipping 22 matching lines...) Expand all
45 // We are not using Dircetory.current here to limit the dependency 49 // We are not using Dircetory.current here to limit the dependency
46 // on dart:io. This code is the same as: 50 // on dart:io. This code is the same as:
47 // return new Uri.directory(Directory.current.path); 51 // return new Uri.directory(Directory.current.path);
48 var path = _getCurrentDirectoryPath(); 52 var path = _getCurrentDirectoryPath();
49 return new Uri.directory(path); 53 return new Uri.directory(path);
50 } 54 }
51 55
52 56
53 _getUriBaseClosure() => _uriBase; 57 _getUriBaseClosure() => _uriBase;
54 58
55
56 // Asynchronous loading of resources. 59 // Asynchronous loading of resources.
57 // The embedder forwards most loading requests to this library. 60 // The embedder forwards loading requests to the service isolate.
58
59 // See Dart_LibraryTag in dart_api.h
60 const _Dart_kScriptTag = null;
61 const _Dart_kImportTag = 0;
62 const _Dart_kSourceTag = 1;
63 const _Dart_kCanonicalizeUrl = 2;
64 const _Dart_kResourceLoad = 3;
65
66 // Embedder sets this to true if the --trace-loading flag was passed on the
67 // command line.
68 bool _traceLoading = false;
69
70 // This is currently a build time flag only. We measure the time from the first
71 // load request (opening the receive port) to completing the last load
72 // request (closing the receive port). Future, deferred load operations will
73 // add to this time.
74 bool _timeLoading = false;
75 Stopwatch _stopwatch;
76 61
77 // A port for communicating with the service isolate for I/O. 62 // A port for communicating with the service isolate for I/O.
78 SendPort _loadPort; 63 SendPort _loadPort;
79 // The receive port for a load request. Multiple sources can be fetched in 64
80 // a single load request. 65 // The isolateId used to communicate with the service isolate for I/O.
81 RawReceivePort _dataPort; 66 int _isolateId;
82 // A request id valid only for the current load cycle (while the number of 67
83 // outstanding load requests is greater than 0). Can be reset when loading is 68 // Requests made to the service isolate over the load port.
84 // completed. 69
85 int _reqId = 0; 70 // Extra requests. Keep these in sync between loader.dart and builtin.dart.
86 // An unordered hash map mapping from request id to a particular load request. 71 const _Dart_kInitLoader = 4; // Initialize the loader.
87 // Once there are no outstanding load requests the current load has finished. 72 const _Dart_kResourceLoad = 5; // Resource class support.
88 HashMap _reqMap = new HashMap(); 73 const _Dart_kGetPackageRootUri = 6; // Uri of the packages/ directory.
74 const _Dart_kGetPackageConfigUri = 7; // Uri of the .packages file.
75 const _Dart_kResolvePackageUri = 8; // Resolve a package: uri.
76
77 // Make a request to the loader. Future will complete with result which is
78 // either a Uri or a List<int>.
79 Future _makeLoaderRequest(int tag, String uri) {
80 assert(_isolateId != null);
81 assert(_loadPort != null);
82 Completer completer = new Completer();
83 RawReceivePort port = new RawReceivePort();
84 port.handler = (msg) {
85 // Close the port.
86 port.close();
87 completer.complete(msg);
88 };
89 _loadPort.send([_traceLoading, _isolateId, tag, port.sendPort, uri]);
90 return completer.future;
91 }
92
89 93
90 // The current working directory when the embedder was launched. 94 // The current working directory when the embedder was launched.
91 Uri _workingDirectory; 95 Uri _workingDirectory;
92 // The URI that the root script was loaded from. Remembered so that 96 // The URI that the root script was loaded from. Remembered so that
93 // package imports can be resolved relative to it. The root script is the basis 97 // package imports can be resolved relative to it. The root script is the basis
94 // for the root library in the VM. 98 // for the root library in the VM.
95 Uri _rootScript; 99 Uri _rootScript;
96 100 // The package root set on the command line.
97 // Packages are either resolved looking up in a map or resolved from within a 101 Uri _packageRoot;
98 // package root.
99 bool get _packagesReady =>
100 (_packageRoot != null) || (_packageMap != null) || (_packageError != null);
101 // Error string set if there was an error resolving package configuration.
102 // For example not finding a .packages file or packages/ directory, malformed
103 // .packages file or any other related error.
104 String _packageError = null;
105 // The directory to look in to resolve "package:" scheme URIs. By detault it is
106 // the 'packages' directory right next to the script.
107 Uri _packageRoot = null; // Used to be _rootScript.resolve('packages/');
108 // The map describing how certain package names are mapped to Uris.
109 Uri _packageConfig = null;
110 Map<String, Uri> _packageMap = null;
111
112 // A list of pending packags which have been requested while resolving the
113 // location of the package root or the contents of the package map.
114 List<_LoadRequest> _pendingPackageLoads = [];
115
116 // If we have outstanding loads or pending package loads waiting for resolution,
117 // then we do have pending loads.
118 bool _pendingLoads() => !_reqMap.isEmpty || !_pendingPackageLoads.isEmpty;
119 102
120 // Special handling for Windows paths so that they are compatible with URI 103 // Special handling for Windows paths so that they are compatible with URI
121 // handling. 104 // handling.
122 // Embedder sets this to true if we are running on Windows. 105 // Embedder sets this to true if we are running on Windows.
123 bool _isWindows = false; 106 bool _isWindows = false;
124 107
125 // Logging from builtin.dart is prefixed with a '*'. 108 // Logging from builtin.dart is prefixed with a '*'.
126 String _logId = (Isolate.current.hashCode % 0x100000).toRadixString(16); 109 String _logId = (Isolate.current.hashCode % 0x100000).toRadixString(16);
127 _log(msg) { 110 _log(msg) {
128 _print("* $_logId $msg"); 111 _print("* $_logId $msg");
129 } 112 }
130 113
131 // A class wrapping the load error message in an Error object.
132 class _LoadError extends Error {
133 final _LoadRequest request;
134 final String message;
135 _LoadError(this.request, this.message);
136
137 String toString() {
138 var context = request._context;
139 if (context == null || context is! String) {
140 return 'Could not load "${request._uri}": $message';
141 } else {
142 return 'Could not import "${request._uri}" from "$context": $message';
143 }
144 }
145 }
146
147 // Class collecting all of the information about a particular load request.
148 class _LoadRequest {
149 final int _id = _reqId++;
150 final int _tag;
151 final String _uri;
152 final Uri _resourceUri;
153 final _context;
154
155 _LoadRequest(this._tag, this._uri, this._resourceUri, this._context) {
156 assert(_reqMap[_id] == null);
157 _reqMap[_id] = this;
158 }
159
160 toString() => "LoadRequest($_id, $_tag, $_uri, $_resourceUri, $_context)";
161 }
162
163
164 // Native calls provided by the embedder.
165 void _signalDoneLoading() native "Builtin_DoneLoading";
166 void _loadScriptCallback(int tag, String uri, String libraryUri, Uint8List data)
167 native "Builtin_LoadSource";
168 void _asyncLoadErrorCallback(uri, libraryUri, error)
169 native "Builtin_AsyncLoadError";
170
171
172 _sanitizeWindowsPath(path) { 114 _sanitizeWindowsPath(path) {
173 // For Windows we need to massage the paths a bit according to 115 // For Windows we need to massage the paths a bit according to
174 // http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx 116 // http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx
175 // 117 //
176 // Convert 118 // Convert
177 // C:\one\two\three 119 // C:\one\two\three
178 // to 120 // to
179 // /C:/one/two/three 121 // /C:/one/two/three
180 122
181 if (_isWindows == false) { 123 if (_isWindows == false) {
182 // Do nothing when not running Windows. 124 // Do nothing when not running Windows.
183 return path; 125 return path;
184 } 126 }
185 127
186 var fixedPath = "${path.replaceAll('\\', '/')}"; 128 var fixedPath = "${path.replaceAll('\\', '/')}";
187 129
188 if ((path.length > 2) && (path[1] == ':')) { 130 if ((path.length > 2) && (path[1] == ':')) {
189 // Path begins with a drive letter. 131 // Path begins with a drive letter.
190 return '/$fixedPath'; 132 return '/$fixedPath';
191 } 133 }
192 134
193 return fixedPath; 135 return fixedPath;
194 } 136 }
195 137
196
197 _trimWindowsPath(path) { 138 _trimWindowsPath(path) {
198 // Convert /X:/ to X:/. 139 // Convert /X:/ to X:/.
199 if (_isWindows == false) { 140 if (_isWindows == false) {
200 // Do nothing when not running Windows. 141 // Do nothing when not running Windows.
201 return path; 142 return path;
202 } 143 }
203 if (!path.startsWith('/') || (path.length < 3)) { 144 if (!path.startsWith('/') || (path.length < 3)) {
204 return path; 145 return path;
205 } 146 }
206 // Match '/?:'. 147 // Match '/?:'.
207 if ((path[0] == '/') && (path[2] == ':')) { 148 if ((path[0] == '/') && (path[2] == ':')) {
208 // Remove leading '/'. 149 // Remove leading '/'.
209 return path.substring(1); 150 return path.substring(1);
210 } 151 }
211 return path; 152 return path;
212 } 153 }
213 154
214
215 // Ensure we have a trailing slash character. 155 // Ensure we have a trailing slash character.
216 _enforceTrailingSlash(uri) { 156 _enforceTrailingSlash(uri) {
217 if (!uri.endsWith('/')) { 157 if (!uri.endsWith('/')) {
218 return '$uri/'; 158 return '$uri/';
219 } 159 }
220 return uri; 160 return uri;
221 } 161 }
222 162
223
224 // Embedder Entrypoint: 163 // Embedder Entrypoint:
225 // The embedder calls this method with the current working directory. 164 // The embedder calls this method with the current working directory.
226 void _setWorkingDirectory(cwd) { 165 void _setWorkingDirectory(cwd) {
227 if (!_setupCompleted) { 166 if (!_setupCompleted) {
228 _setupHooks(); 167 _setupHooks();
229 } 168 }
230 if (_traceLoading) { 169 if (_traceLoading) {
231 _log('Setting working directory: $cwd'); 170 _log('Setting working directory: $cwd');
232 } 171 }
233 _workingDirectory = new Uri.directory(cwd); 172 _workingDirectory = new Uri.directory(cwd);
234 if (_traceLoading) { 173 if (_traceLoading) {
235 _log('Working directory URI: $_workingDirectory'); 174 _log('Working directory URI: $_workingDirectory');
236 } 175 }
237 } 176 }
238 177
239
240 // Embedder Entrypoint: 178 // Embedder Entrypoint:
241 // The embedder calls this method with a custom package root. 179 // The embedder calls this method with a custom package root.
242 _setPackageRoot(String packageRoot) { 180 _setPackageRoot(String packageRoot) {
243 if (!_setupCompleted) { 181 if (!_setupCompleted) {
244 _setupHooks(); 182 _setupHooks();
245 } 183 }
246 if (_traceLoading) { 184 if (_traceLoading) {
247 _log('Setting package root: $packageRoot'); 185 _log('Setting package root: $packageRoot');
248 } 186 }
249 if (packageRoot.startsWith('file:') || 187 if (packageRoot.startsWith('file:') ||
250 packageRoot.startsWith('http:') || 188 packageRoot.startsWith('http:') ||
251 packageRoot.startsWith('https:')) { 189 packageRoot.startsWith('https:')) {
252 packageRoot = _enforceTrailingSlash(packageRoot); 190 packageRoot = _enforceTrailingSlash(packageRoot);
253 _packageRoot = _workingDirectory.resolve(packageRoot); 191 _packageRoot = _workingDirectory.resolve(packageRoot);
254 } else { 192 } else {
255 packageRoot = _sanitizeWindowsPath(packageRoot); 193 packageRoot = _sanitizeWindowsPath(packageRoot);
256 packageRoot = _trimWindowsPath(packageRoot); 194 packageRoot = _trimWindowsPath(packageRoot);
257 _packageRoot = _workingDirectory.resolveUri(new Uri.directory(packageRoot)); 195 _packageRoot = _workingDirectory.resolveUri(new Uri.directory(packageRoot));
258 } 196 }
259 // Now that we have determined the packageRoot value being used, set it 197 // Now that we have determined the packageRoot value being used, set it
260 // up for use in Platform.packageRoot. This is only set when the embedder 198 // up for use in Platform.packageRoot. This is only set when the embedder
261 // sets up the package root. Automatically discovered package root will 199 // sets up the package root. Automatically discovered package root will
262 // not update the VMLibraryHooks value. 200 // not update the VMLibraryHooks value.
263 VMLibraryHooks.packageRootString = _packageRoot.toString(); 201 VMLibraryHooks.packageRootString = _packageRoot.toString();
264 if (_traceLoading) { 202 if (_traceLoading) {
265 _log('Package root URI: $_packageRoot'); 203 _log('Package root URI: $_packageRoot');
266 } 204 }
267 } 205 }
268 206
269
270 // Given a uri with a 'package' scheme, return a Uri that is prefixed with
271 // the package root.
272 Uri _resolvePackageUri(Uri uri) {
273 assert(uri.scheme == "package");
274 assert(_packagesReady);
275
276 if (!uri.host.isEmpty) {
277 var path = '${uri.host}${uri.path}';
278 var right = 'package:$path';
279 var wrong = 'package://$path';
280
281 throw "URIs using the 'package:' scheme should look like "
282 "'$right', not '$wrong'.";
283 }
284
285 if (_traceLoading) {
286 _log('Resolving package with uri path: ${uri.path}');
287 }
288 var resolvedUri;
289 if (_packageError != null) {
290 if (_traceLoading) {
291 _log("Resolving package with pending resolution error: $_packageError");
292 }
293 throw _packageError;
294 } else if (_packageRoot != null) {
295 resolvedUri = _packageRoot.resolve(uri.path);
296 } else {
297 var packageName = uri.pathSegments[0];
298 var mapping = _packageMap[packageName];
299 if (_traceLoading) {
300 _log("Mapped '$packageName' package to '$mapping'");
301 }
302 if (mapping == null) {
303 throw "No mapping for '$packageName' package when resolving '$uri'.";
304 }
305 var path;
306 if (uri.path.length > packageName.length) {
307 path = uri.path.substring(packageName.length + 1);
308 } else {
309 // Handle naked package resolution to the default package name:
310 // package:foo is equivalent to package:foo/foo.dart
311 assert(uri.path.length == packageName.length);
312 path = "$packageName.dart";
313 }
314 if (_traceLoading) {
315 _log("Path to be resolved in package: $path");
316 }
317 resolvedUri = mapping.resolve(path);
318 }
319 if (_traceLoading) {
320 _log("Resolved '$uri' to '$resolvedUri'.");
321 }
322 return resolvedUri;
323 }
324
325
326 // Resolves the script uri in the current working directory iff the given uri
327 // did not specify a scheme (e.g. a path to a script file on the command line).
328 Uri _resolveScriptUri(String scriptName) {
329 if (_traceLoading) {
330 _log("Resolving script: $scriptName");
331 }
332 if (_workingDirectory == null) {
333 throw 'No current working directory set.';
334 }
335 scriptName = _sanitizeWindowsPath(scriptName);
336
337 var scriptUri = Uri.parse(scriptName);
338 if (scriptUri.scheme == '') {
339 // Script does not have a scheme, assume that it is a path,
340 // resolve it against the working directory.
341 scriptUri = _workingDirectory.resolveUri(scriptUri);
342 }
343
344 // Remember the root script URI so that we can resolve packages based on
345 // this location.
346 _rootScript = scriptUri;
347
348 if (_traceLoading) {
349 _log('Resolved entry point to: $_rootScript');
350 }
351 return scriptUri;
352 }
353
354
355 void _finishLoadRequest(_LoadRequest req) {
356 if (req != null) {
357 // Now that we are done with loading remove the request from the map.
358 var tmp = _reqMap.remove(req._id);
359 assert(tmp == req);
360 if (_traceLoading) {
361 _log("Loading of ${req._uri} finished: "
362 "${_reqMap.length} requests remaining, "
363 "${_pendingPackageLoads.length} packages pending.");
364 }
365 }
366
367 if (!_pendingLoads() && (_dataPort != null)) {
368 _stopwatch.stop();
369 // Close the _dataPort now that there are no more requests outstanding.
370 if (_traceLoading || _timeLoading) {
371 _log("Closing loading port: ${_stopwatch.elapsedMilliseconds} ms");
372 }
373 _dataPort.close();
374 _dataPort = null;
375 _reqId = 0;
376 _signalDoneLoading();
377 }
378 }
379
380
381 void _handleLoaderReply(msg) {
382 int id = msg[0];
383 var dataOrError = msg[1];
384 assert((id >= 0) && (id < _reqId));
385 var req = _reqMap[id];
386 try {
387 if (dataOrError is Uint8List) {
388 // Successfully loaded the data.
389 if (req._tag == _Dart_kResourceLoad) {
390 Completer c = req._context;
391 c.complete(dataOrError);
392 } else {
393 // TODO: Currently a compilation error while loading the script is
394 // fatal for the isolate. _loadScriptCallback() does not return and
395 // the number of requests remains out of sync.
396 _loadScriptCallback(req._tag, req._uri, req._context, dataOrError);
397 }
398 _finishLoadRequest(req);
399 } else {
400 assert(dataOrError is String);
401 var error = new _LoadError(req, dataOrError.toString());
402 _asyncLoadError(req, error, null);
403 }
404 } catch(e, s) {
405 // Wrap inside a _LoadError unless we are already propagating a
406 // previous _LoadError.
407 var error = (e is _LoadError) ? e : new _LoadError(req, e.toString());
408 assert(req != null);
409 _asyncLoadError(req, error, s);
410 }
411 }
412
413
414 void _startLoadRequest(int tag, String uri, Uri resourceUri, context) {
415 if (_dataPort == null) {
416 if (_traceLoading) {
417 _log("Initializing load port.");
418 }
419 // Allocate the Stopwatch if necessary.
420 if (_stopwatch == null) {
421 _stopwatch = new Stopwatch();
422 }
423 assert(_dataPort == null);
424 _dataPort = new RawReceivePort(_handleLoaderReply);
425 _stopwatch.start();
426 }
427 // Register the load request and send it to the VM service isolate.
428 var req = new _LoadRequest(tag, uri, resourceUri, context);
429
430 assert(_dataPort != null);
431 var msg = new List(4);
432 msg[0] = _dataPort.sendPort;
433 msg[1] = _traceLoading;
434 msg[2] = req._id;
435 msg[3] = resourceUri.toString();
436 _loadPort.send(msg);
437
438 if (_traceLoading) {
439 _log("Loading of $resourceUri for $uri started with id: ${req._id}. "
440 "${_reqMap.length} requests remaining, "
441 "${_pendingPackageLoads.length} packages pending.");
442 }
443 }
444
445
446 RawReceivePort _packagesPort;
447
448 void _handlePackagesReply(msg) {
449 // Make sure to close the _packagePort before any other action.
450 _packagesPort.close();
451 _packagesPort = null;
452
453 if (_traceLoading) {
454 _log("Got packages reply: $msg");
455 }
456 if (msg is String) {
457 if (_traceLoading) {
458 _log("Got failure response on package port: '$msg'");
459 }
460 // Remember the error message.
461 _packageError = msg;
462 } else if (msg is List) {
463 if (msg.length == 1) {
464 if (_traceLoading) {
465 _log("Received package root: '${msg[0]}'");
466 }
467 _packageRoot = Uri.parse(msg[0]);
468 } else {
469 // First entry contains the location of the loaded .packages file.
470 assert((msg.length % 2) == 0);
471 assert(msg.length >= 2);
472 assert(msg[1] == null);
473 _packageConfig = Uri.parse(msg[0]);
474 _packageMap = new Map<String, Uri>();
475 for (var i = 2; i < msg.length; i+=2) {
476 // TODO(iposva): Complain about duplicate entries.
477 _packageMap[msg[i]] = Uri.parse(msg[i+1]);
478 }
479 if (_traceLoading) {
480 _log("Setup package map: $_packageMap");
481 }
482 }
483 } else {
484 _packageError = "Bad type of packages reply: ${msg.runtimeType}";
485 if (_traceLoading) {
486 _log(_packageError);
487 }
488 }
489
490 // Resolve all pending package loads now that we know how to resolve them.
491 while (_pendingPackageLoads.length > 0) {
492 // Order does not matter as we queue all of the requests up right now.
493 var req = _pendingPackageLoads.removeLast();
494 // Call the registered closure, to handle the delayed action.
495 req();
496 }
497 // Reset the pending package loads to empty. So that we eventually can
498 // finish loading.
499 _pendingPackageLoads = [];
500 // Make sure that the receive port is closed if no other loads are pending.
501 _finishLoadRequest(null);
502 }
503
504
505 void _requestPackagesMap() {
506 assert(_packagesPort == null);
507 assert(_rootScript != null);
508 // Create a port to receive the packages map on.
509 _packagesPort = new RawReceivePort(_handlePackagesReply);
510 var sp = _packagesPort.sendPort;
511
512 var msg = new List(4);
513 msg[0] = sp;
514 msg[1] = _traceLoading;
515 msg[2] = -1;
516 msg[3] = _rootScript.toString();
517 _loadPort.send(msg);
518
519 if (_traceLoading) {
520 _log("Requested packages map for '$_rootScript'.");
521 }
522 }
523
524
525 // Embedder Entrypoint: 207 // Embedder Entrypoint:
526 // Request the load of a particular packages map. 208 void _setPackagesMap(String packagesParam) {
527 void _loadPackagesMap(String packagesParam) {
528 if (!_setupCompleted) { 209 if (!_setupCompleted) {
529 _setupHooks(); 210 _setupHooks();
530 } 211 }
531 // First convert the packages parameter from the command line to a URI which 212 // First convert the packages parameter from the command line to a URI which
532 // can be handled by the loader code. 213 // can be handled by the loader code.
533 // TODO(iposva): Consider refactoring the common code below which is almost 214 // TODO(iposva): Consider refactoring the common code below which is almost
534 // shared with resolution of the root script. 215 // shared with resolution of the root script.
535 if (_traceLoading) { 216 if (_traceLoading) {
536 _log("Resolving packages map: $packagesParam"); 217 _log("Resolving packages map: $packagesParam");
537 } 218 }
538 if (_workingDirectory == null) { 219 if (_workingDirectory == null) {
539 throw 'No current working directory set.'; 220 throw 'No current working directory set.';
540 } 221 }
541 var packagesName = _sanitizeWindowsPath(packagesParam); 222 var packagesName = _sanitizeWindowsPath(packagesParam);
542 var packagesUri = Uri.parse(packagesName); 223 var packagesUri = Uri.parse(packagesName);
543 if (packagesUri.scheme == '') { 224 if (packagesUri.scheme == '') {
544 // Script does not have a scheme, assume that it is a path, 225 // Script does not have a scheme, assume that it is a path,
545 // resolve it against the working directory. 226 // resolve it against the working directory.
546 packagesUri = _workingDirectory.resolveUri(packagesUri); 227 packagesUri = _workingDirectory.resolveUri(packagesUri);
547 } 228 }
548 var packagesUriStr = packagesUri.toString(); 229 var packagesUriStr = packagesUri.toString();
549 VMLibraryHooks.packageConfigString = packagesUriStr; 230 VMLibraryHooks.packageConfigString = packagesUriStr;
550 if (_traceLoading) { 231 if (_traceLoading) {
551 _log('Resolved packages map to: $packagesUri'); 232 _log('Resolved packages map to: $packagesUri');
552 } 233 }
234 }
553 235
554 // Request the loading and parsing of the packages map at the specified URI. 236 // Resolves the script uri in the current working directory iff the given uri
555 // Create a port to receive the packages map on. 237 // did not specify a scheme (e.g. a path to a script file on the command line).
556 assert(_packagesPort == null); 238 String _resolveScriptUri(String scriptName) {
557 _packagesPort = new RawReceivePort(_handlePackagesReply); 239 if (_traceLoading) {
558 var sp = _packagesPort.sendPort; 240 _log("Resolving script: $scriptName");
241 }
242 if (_workingDirectory == null) {
243 throw 'No current working directory set.';
244 }
245 scriptName = _sanitizeWindowsPath(scriptName);
559 246
560 var msg = new List(4); 247 var scriptUri = Uri.parse(scriptName);
561 msg[0] = sp; 248 if (scriptUri.scheme == '') {
562 msg[1] = _traceLoading; 249 // Script does not have a scheme, assume that it is a path,
563 msg[2] = -2; 250 // resolve it against the working directory.
564 msg[3] = packagesUriStr; 251 scriptUri = _workingDirectory.resolveUri(scriptUri);
565 _loadPort.send(msg); 252 }
566 253
567 // Signal that the resolution of the packages map has started. But in this 254 // Remember the root script URI so that we can resolve packages based on
568 // case it is not tied to a particular request. 255 // this location.
569 _pendingPackageLoads.add(() { 256 _rootScript = scriptUri;
570 // Nothing to be done beyond registering that there is pending package
571 // resolution requested by having an empty entry.
572 if (_traceLoading) {
573 _log("Skipping dummy deferred request.");
574 }
575 });
576 257
577 if (_traceLoading) { 258 if (_traceLoading) {
578 _log("Requested packages map at '$packagesUri'."); 259 _log('Resolved entry point to: $_rootScript');
579 } 260 }
261 return scriptUri.toString();
580 } 262 }
581 263
582
583 void _asyncLoadError(_LoadRequest req, _LoadError error, StackTrace stack) {
584 if (_traceLoading) {
585 _log("_asyncLoadError(${req._uri}), error: $error\nstack: $stack");
586 }
587 if (req._tag == _Dart_kResourceLoad) {
588 Completer c = req._context;
589 c.completeError(error, stack);
590 } else {
591 String libraryUri = req._context;
592 if (req._tag == _Dart_kImportTag) {
593 // When importing a library, the libraryUri is the imported
594 // uri.
595 libraryUri = req._uri;
596 }
597 _asyncLoadErrorCallback(req._uri, libraryUri, error);
598 }
599 _finishLoadRequest(req);
600 }
601
602
603 _loadDataFromLoadPort(int tag, String uri, Uri resourceUri, context) {
604 try {
605 _startLoadRequest(tag, uri, resourceUri, context);
606 } catch (e, s) {
607 if (_traceLoading) {
608 _log("Exception when communicating with service isolate: $e");
609 }
610 // Register a dummy load request so we can fail to load it.
611 var req = new _LoadRequest(tag, uri, resourceUri, context);
612
613 // Wrap inside a _LoadError unless we are already propagating a previously
614 // seen _LoadError.
615 var error = (e is _LoadError) ? e : new _LoadError(req, e.toString());
616 _asyncLoadError(req, error, s);
617 }
618 }
619
620
621 // Loading a package URI needs to first map the package name to a loadable
622 // URI.
623 _loadPackage(int tag, String uri, Uri resourceUri, context) {
624 if (_packagesReady) {
625 var resolvedUri;
626 try {
627 resolvedUri = _resolvePackageUri(resourceUri);
628 } catch (e, s) {
629 if (_traceLoading) {
630 _log("Exception ($e) when resolving package URI: $resourceUri");
631 }
632 // Register a dummy load request so we can fail to load it.
633 var req = new _LoadRequest(tag, uri, resourceUri, context);
634
635 // Wrap inside a _LoadError unless we are already propagating a previously
636 // seen _LoadError.
637 var error = (e is _LoadError) ? e : new _LoadError(req, e.toString());
638 _asyncLoadError(req, error, s);
639 }
640 _loadData(tag, uri, resolvedUri, context);
641 } else {
642 if (_pendingPackageLoads.isEmpty) {
643 // Package resolution has not been setup yet, and this is the first
644 // request for package resolution & loading.
645 _requestPackagesMap();
646 }
647 // Register the action of loading this package once the package resolution
648 // is ready.
649 _pendingPackageLoads.add(() {
650 if (_traceLoading) {
651 _log("Handling deferred package request: "
652 "$tag, $uri, $resourceUri, $context");
653 }
654 _loadPackage(tag, uri, resourceUri, context);
655 });
656 if (_traceLoading) {
657 _log("Pending package load of '$uri': "
658 "${_pendingPackageLoads.length} pending");
659 }
660 }
661 }
662
663
664 // Load the data associated with the resourceUri.
665 _loadData(int tag, String uri, Uri resourceUri, context) {
666 if (resourceUri.scheme == 'package') {
667 // package based uris need to be resolved to the correct loadable location.
668 // The logic of which is handled seperately, and then _loadData is called
669 // recursively.
670 _loadPackage(tag, uri, resourceUri, context);
671 } else {
672 _loadDataFromLoadPort(tag, uri, resourceUri, context);
673 }
674 }
675
676
677 // Embedder Entrypoint:
678 // Asynchronously loads script data through a http[s] or file uri.
679 _loadDataAsync(int tag, String uri, String libraryUri) {
680 if (!_setupCompleted) {
681 _setupHooks();
682 }
683 var resourceUri;
684 if (tag == _Dart_kScriptTag) {
685 resourceUri = _resolveScriptUri(uri);
686 uri = resourceUri.toString();
687 } else {
688 resourceUri = Uri.parse(uri);
689 }
690 _loadData(tag, uri, resourceUri, libraryUri);
691 }
692
693
694 // Embedder Entrypoint: 264 // Embedder Entrypoint:
695 // Function called by standalone embedder to resolve uris when the VM requests 265 // Function called by standalone embedder to resolve uris when the VM requests
696 // Dart_kCanonicalizeUrl from the tag handler. 266 // Dart_kCanonicalizeUrl from the tag handler.
697 String _resolveUri(String base, String userString) { 267 String _resolveUri(String base, String userString) {
698 if (!_setupCompleted) { 268 if (!_setupCompleted) {
699 _setupHooks(); 269 _setupHooks();
700 } 270 }
701 271
702 if (_traceLoading) { 272 if (_traceLoading) {
703 _log('Resolving: $userString from $base'); 273 _log('Resolving: $userString from $base');
704 } 274 }
705 275
706 var baseUri = Uri.parse(base); 276 var baseUri = Uri.parse(base);
707 var result = baseUri.resolve(userString).toString(); 277 var result = baseUri.resolve(userString).toString();
708 if (_traceLoading) { 278 if (_traceLoading) {
709 _log('Resolved $userString in $base to $result'); 279 _log('Resolved $userString in $base to $result');
710 } 280 }
711 281
712 return result; 282 return result;
713 } 283 }
714 284
715
716
717 // Handling of access to the package root or package map from user code.
718 _triggerPackageResolution(action) {
719 if (_packagesReady) {
720 // Packages are ready. Execute the action now.
721 action();
722 } else {
723 if (_pendingPackageLoads.isEmpty) {
724 // Package resolution has not been setup yet, and this is the first
725 // request for package resolution & loading.
726 _requestPackagesMap();
727 }
728 // Register the action for when the package resolution is ready.
729 _pendingPackageLoads.add(action);
730 }
731 }
732
733
734 Future<Uri> _getPackageRootFuture() {
735 if (_traceLoading) {
736 _log("Request for package root from user code.");
737 }
738 var completer = new Completer<Uri>();
739 _triggerPackageResolution(() {
740 completer.complete(_packageRoot);
741 });
742 return completer.future;
743 }
744
745
746 Future<Uri> _getPackageConfigFuture() {
747 if (_traceLoading) {
748 _log("Request for package config from user code.");
749 }
750 var completer = new Completer<Uri>();
751 _triggerPackageResolution(() {
752 completer.complete(_packageConfig);
753 });
754 return completer.future;
755 }
756
757
758 Future<Uri> _resolvePackageUriFuture(Uri packageUri) async {
759 if (_traceLoading) {
760 _log("Request for package Uri resolution from user code: $packageUri");
761 }
762 if (packageUri.scheme != "package") {
763 if (_traceLoading) {
764 _log("Non-package Uri, returning unmodified: $packageUri");
765 }
766 // Return the incoming parameter if not passed a package: URI.
767 return packageUri;
768 }
769
770 if (!_packagesReady) {
771 if (_traceLoading) {
772 _log("Trigger loading by requesting the package config.");
773 }
774 // Make sure to trigger package resolution.
775 var dummy = await _getPackageConfigFuture();
776 }
777 assert(_packagesReady);
778
779 var result;
780 try {
781 result = _resolvePackageUri(packageUri);
782 } catch (e, s) {
783 // Any error during resolution will resolve this package as not mapped,
784 // which is indicated by a null return.
785 if (_traceLoading) {
786 _log("Exception ($e) when resolving package URI: $packageUri");
787 }
788 result = null;
789 }
790 if (_traceLoading) {
791 _log("Resolved '$packageUri' to '$result'");
792 }
793 return result;
794 }
795
796
797 // Handling of Resource class by dispatching to the load port.
798 Future<List<int>> _resourceReadAsBytes(Uri uri) {
799 var completer = new Completer<List<int>>();
800 // Request the load of the resource associating the completer as the context
801 // for the load.
802 _loadData(_Dart_kResourceLoad, uri.toString(), uri, completer);
803 // Return the future that will be triggered once the resource has been loaded.
804 return completer.future;
805 }
806
807
808 // Embedder Entrypoint (gen_snapshot): 285 // Embedder Entrypoint (gen_snapshot):
809 // Resolve relative paths relative to working directory. 286 // Resolve relative paths relative to working directory.
810 String _resolveInWorkingDirectory(String fileName) { 287 String _resolveInWorkingDirectory(String fileName) {
811 if (!_setupCompleted) { 288 if (!_setupCompleted) {
812 _setupHooks(); 289 _setupHooks();
813 } 290 }
814 if (_workingDirectory == null) { 291 if (_workingDirectory == null) {
815 throw 'No current working directory set.'; 292 throw 'No current working directory set.';
816 } 293 }
817 var name = _sanitizeWindowsPath(fileName); 294 var name = _sanitizeWindowsPath(fileName);
818 295
819 var uri = Uri.parse(name); 296 var uri = Uri.parse(name);
820 if (uri.scheme != '') { 297 if (uri.scheme != '') {
821 throw 'Schemes are not supported when resolving filenames.'; 298 throw 'Schemes are not supported when resolving filenames.';
822 } 299 }
823 uri = _workingDirectory.resolveUri(uri); 300 uri = _workingDirectory.resolveUri(uri);
824 301
825 if (_traceLoading) { 302 if (_traceLoading) {
826 _log('Resolved in working directory: $fileName -> $uri'); 303 _log('Resolved in working directory: $fileName -> $uri');
827 } 304 }
828 return uri.toString(); 305 return uri.toString();
829 } 306 }
830 307
308 // Only used by vm/cc unit tests.
309 Uri _resolvePackageUri(Uri uri) {
310 assert(_packageRoot != null);
311 return _packageRoot.resolve(uri.path);
312 }
831 313
832 // Returns either a file path or a URI starting with http[s]:, as a String. 314 // Returns either a file path or a URI starting with http[s]:, as a String.
833 String _filePathFromUri(String userUri) { 315 String _filePathFromUri(String userUri) {
834 var uri = Uri.parse(userUri); 316 var uri = Uri.parse(userUri);
835 if (_traceLoading) { 317 if (_traceLoading) {
836 _log('Getting file path from: $uri'); 318 _log('Getting file path from: $uri');
837 } 319 }
838 320
839 var path; 321 var path;
840 switch (uri.scheme) { 322 switch (uri.scheme) {
841 case '': 323 case '':
842 case 'file': 324 case 'file':
843 return uri.toFilePath(); 325 return uri.toFilePath();
844 case 'package': 326 case 'package':
845 return _filePathFromUri(_resolvePackageUri(uri).toString()); 327 return _filePathFromUri(_resolvePackageUri(uri).toString());
846 case 'data': 328 case 'data':
847 case 'http': 329 case 'http':
848 case 'https': 330 case 'https':
849 return uri.toString(); 331 return uri.toString();
850 default: 332 default:
851 // Only handling file, http, and package URIs 333 // Only handling file, http, and package URIs
852 // in standalone binary. 334 // in standalone binary.
853 if (_traceLoading) { 335 if (_traceLoading) {
854 _log('Unknown scheme (${uri.scheme}) in $uri.'); 336 _log('Unknown scheme (${uri.scheme}) in $uri.');
855 } 337 }
856 throw 'Not a known scheme: $uri'; 338 throw 'Not a known scheme: $uri';
857 } 339 }
858 } 340 }
859 341
860
861 // Embedder Entrypoint. 342 // Embedder Entrypoint.
862 _libraryFilePath(String libraryUri) { 343 _libraryFilePath(String libraryUri) {
863 if (!_setupCompleted) { 344 if (!_setupCompleted) {
864 _setupHooks(); 345 _setupHooks();
865 } 346 }
866 int index = libraryUri.lastIndexOf('/'); 347 int index = libraryUri.lastIndexOf('/');
867 var path; 348 var path;
868 if (index == -1) { 349 if (index == -1) {
869 path = './'; 350 path = './';
870 } else { 351 } else {
871 path = libraryUri.substring(0, index + 1); 352 path = libraryUri.substring(0, index + 1);
872 } 353 }
873 return _filePathFromUri(path); 354 return _filePathFromUri(path);
874 } 355 }
875 356
876
877 // Register callbacks and hooks with the rest of the core libraries. 357 // Register callbacks and hooks with the rest of the core libraries.
878 _setupHooks() { 358 _setupHooks() {
879 _setupCompleted = true; 359 _setupCompleted = true;
880 VMLibraryHooks.resourceReadAsBytes = _resourceReadAsBytes; 360 VMLibraryHooks.resourceReadAsBytes = _resourceReadAsBytes;
881 361
882 VMLibraryHooks.packageRootUriFuture = _getPackageRootFuture; 362 VMLibraryHooks.packageRootUriFuture = _getPackageRootFuture;
883 VMLibraryHooks.packageConfigUriFuture = _getPackageConfigFuture; 363 VMLibraryHooks.packageConfigUriFuture = _getPackageConfigFuture;
884 VMLibraryHooks.resolvePackageUriFuture = _resolvePackageUriFuture; 364 VMLibraryHooks.resolvePackageUriFuture = _resolvePackageUriFuture;
885 } 365 }
366
367 // Handling of Resource class by dispatching to the load port.
368 Future<List<int>> _resourceReadAsBytes(Uri uri) async {
369 List response = await _makeLoaderRequest(_Dart_kResourceLoad, uri.toString());
370 if (response[3] is String) {
371 // Throw the error.
372 throw response[3];
373 } else {
374 return response[3];
375 }
376 }
377
378 Future<Uri> _getPackageRootFuture() {
379 if (_traceLoading) {
380 _log("Request for package root from user code.");
381 }
382 return _makeLoaderRequest(_Dart_kGetPackageRootUri, null);
383 }
384
385 Future<Uri> _getPackageConfigFuture() {
386 if (_traceLoading) {
387 _log("Request for package config from user code.");
388 }
389 assert(_loadPort != null);
390 return _makeLoaderRequest(_Dart_kGetPackageConfigUri, null);
391 }
392
393 Future<Uri> _resolvePackageUriFuture(Uri packageUri) async {
394 if (_traceLoading) {
395 _log("Request for package Uri resolution from user code: $packageUri");
396 }
397 if (packageUri.scheme != "package") {
398 if (_traceLoading) {
399 _log("Non-package Uri, returning unmodified: $packageUri");
400 }
401 // Return the incoming parameter if not passed a package: URI.
402 return packageUri;
403 }
404 var result = await _makeLoaderRequest(_Dart_kResolvePackageUri,
405 packageUri.toString());
406 if (result is! Uri) {
407 if (_traceLoading) {
408 _log("Exception when resolving package URI: $packageUri");
409 }
410 result = null;
411 }
412 if (_traceLoading) {
413 _log("Resolved '$packageUri' to '$result'");
414 }
415 return result;
416 }
OLDNEW
« no previous file with comments | « runtime/bin/builtin.h ('k') | runtime/bin/builtin_common.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698