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

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

Issue 584023004: Service isolate rework (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 11 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 | Annotate | Revision Log
« no previous file with comments | « runtime/bin/builtin.cc ('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 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 import 'dart:io';
7 import 'dart:async'; 6 import 'dart:async';
8 import 'dart:convert'; 7 import 'dart:convert';
8 import 'dart:isolate';
9
10
11 /* See Dart_LibraryTag in dart_api.h */
12 const Dart_kScriptTag = null;
13 const Dart_kImportTag = 0;
14 const Dart_kSourceTag = 1;
15 const Dart_kCanonicalizeUrl = 2;
16
17 // Dart native extension scheme.
18 const _DART_EXT = 'dart-ext:';
19
9 // import 'root_library'; happens here from C Code 20 // import 'root_library'; happens here from C Code
10 21
11 // The root library (aka the script) is imported into this library. The 22 // The root library (aka the script) is imported into this library. The
12 // standalone embedder uses this to lookup the main entrypoint in the 23 // standalone embedder uses this to lookup the main entrypoint in the
13 // root library's namespace. 24 // root library's namespace.
14 Function _getMainClosure() => main; 25 Function _getMainClosure() => main;
15 26
27 // A port for communicating with the service isolate for I/O.
28 SendPort _loadPort;
29
30 const _logBuiltin = false;
16 31
17 // Corelib 'print' implementation. 32 // Corelib 'print' implementation.
18 void _print(arg) { 33 void _print(arg) {
19 _Logger._printString(arg.toString()); 34 _Logger._printString(arg.toString());
20 } 35 }
21 36
22
23 class _Logger { 37 class _Logger {
24 static void _printString(String s) native "Logger_PrintString"; 38 static void _printString(String s) native "Logger_PrintString";
25 } 39 }
26 40
27
28 _getPrintClosure() => _print; 41 _getPrintClosure() => _print;
29 42
30 const _logBuiltin = false; 43 _getCurrentDirectoryPath() native "Directory_Current";
31 44
32 // Corelib 'Uri.base' implementation. 45 // Corelib 'Uri.base' implementation.
33 Uri _uriBase() { 46 Uri _uriBase() {
34 return new Uri.file(Directory.current.path + "/"); 47 return new Uri.file(_getCurrentDirectoryPath() + "/");
35 } 48 }
36 49
37
38 _getUriBaseClosure() => _uriBase; 50 _getUriBaseClosure() => _uriBase;
39 51
40 52
41 // Are we running on Windows? 53 // Are we running on Windows?
42 var _isWindows = false; 54 var _isWindows = false;
43 var _workingWindowsDrivePrefix; 55 var _workingWindowsDrivePrefix;
44 // The current working directory 56 // The current working directory
45 var _workingDirectoryUri; 57 var _workingDirectoryUri;
46 // The URI that the entry point script was loaded from. Remembered so that 58 // The URI that the entry point script was loaded from. Remembered so that
47 // package imports can be resolved relative to it. 59 // package imports can be resolved relative to it.
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 _packageRoot = _workingDirectoryUri.resolve(packageRoot); 131 _packageRoot = _workingDirectoryUri.resolve(packageRoot);
120 } else { 132 } else {
121 _packageRoot = _workingDirectoryUri.resolveUri(new Uri.file(packageRoot)); 133 _packageRoot = _workingDirectoryUri.resolveUri(new Uri.file(packageRoot));
122 } 134 }
123 if (_logBuiltin) { 135 if (_logBuiltin) {
124 _print('# Package root: $packageRoot -> $_packageRoot'); 136 _print('# Package root: $packageRoot -> $_packageRoot');
125 } 137 }
126 } 138 }
127 139
128 140
141 // Given a uri with a 'package' scheme, return a Uri that is prefixed with
142 // the package root.
143 Uri _resolvePackageUri(Uri uri) {
144 if (!uri.host.isEmpty) {
145 var path = '${uri.host}${uri.path}';
146 var right = 'package:$path';
147 var wrong = 'package://$path';
148
149 throw "URIs using the 'package:' scheme should look like "
150 "'$right', not '$wrong'.";
151 }
152
153 var packageRoot = _packageRoot == null ?
154 _entryPointScript.resolve('packages/') :
155 _packageRoot;
156 return packageRoot.resolve(uri.path);
157 }
158
159
160
129 String _resolveScriptUri(String scriptName) { 161 String _resolveScriptUri(String scriptName) {
130 if (_workingDirectoryUri == null) { 162 if (_workingDirectoryUri == null) {
131 throw 'No current working directory set.'; 163 throw 'No current working directory set.';
132 } 164 }
133 scriptName = _sanitizeWindowsPath(scriptName); 165 scriptName = _sanitizeWindowsPath(scriptName);
134 166
135 var scriptUri = Uri.parse(scriptName); 167 var scriptUri = Uri.parse(scriptName);
136 if (scriptUri.scheme != '') { 168 if (scriptUri.scheme != '') {
137 // Script has a scheme, assume that it is fully formed. 169 // Script has a scheme, assume that it is fully formed.
138 _entryPointScript = scriptUri; 170 _entryPointScript = scriptUri;
139 } else { 171 } else {
140 // Script does not have a scheme, assume that it is a path, 172 // Script does not have a scheme, assume that it is a path,
141 // resolve it against the working directory. 173 // resolve it against the working directory.
142 _entryPointScript = _workingDirectoryUri.resolve(scriptName); 174 _entryPointScript = _workingDirectoryUri.resolve(scriptName);
143 } 175 }
144 if (_logBuiltin) { 176 if (_logBuiltin) {
145 _print('# Resolved entry point to: $_entryPointScript'); 177 _print('# Resolved entry point to: $_entryPointScript');
146 } 178 }
147 return _entryPointScript.toString(); 179 return _entryPointScript.toString();
148 } 180 }
149 181
150 const _DART_EXT = 'dart-ext:';
151 182
183 // Function called by standalone embedder to resolve uris.
152 String _resolveUri(String base, String userString) { 184 String _resolveUri(String base, String userString) {
153 if (_logBuiltin) { 185 if (_logBuiltin) {
154 _print('# Resolving: $userString from $base'); 186 _print('# Resolving: $userString from $base');
155 } 187 }
156 var baseUri = Uri.parse(base); 188 var baseUri = Uri.parse(base);
157 if (userString.startsWith(_DART_EXT)) { 189 if (userString.startsWith(_DART_EXT)) {
158 var uri = userString.substring(_DART_EXT.length); 190 var uri = userString.substring(_DART_EXT.length);
159 return '$_DART_EXT${baseUri.resolve(uri)}'; 191 return '$_DART_EXT${baseUri.resolve(uri)}';
160 } else { 192 } else {
161 return baseUri.resolve(userString).toString(); 193 return baseUri.resolve(userString).toString();
162 } 194 }
163 } 195 }
164 196
165 197 Uri _createUri(String userUri) {
166 // Returns either a file path or a URI starting with http[s]:, as a String.
167 String _filePathFromUri(String userUri) {
168 var uri = Uri.parse(userUri); 198 var uri = Uri.parse(userUri);
169 if (_logBuiltin) {
170 _print('# Getting file path from: $uri');
171 }
172
173 var path;
174 switch (uri.scheme) { 199 switch (uri.scheme) {
175 case '': 200 case '':
176 case 'file': 201 case 'file':
177 return uri.toFilePath();
178 case 'package':
179 return _filePathFromUri(_resolvePackageUri(uri).toString());
180 case 'http': 202 case 'http':
181 case 'https': 203 case 'https':
182 return uri.toString(); 204 return uri;
205 case 'package':
206 return _resolvePackageUri(uri);
183 default: 207 default:
184 // Only handling file, http, and package URIs 208 // Only handling file, http[s], and package URIs
185 // in standalone binary. 209 // in standalone binary.
186 if (_logBuiltin) { 210 if (_logBuiltin) {
187 _print('# Unknown scheme (${uri.scheme}) in $uri.'); 211 _print('# Unknown scheme (${uri.scheme}) in $uri.');
188 } 212 }
189 throw 'Not a known scheme: $uri'; 213 throw 'Not a known scheme: $uri';
190 } 214 }
191 } 215 }
192 216
193 217 int _numOutstandingLoadRequests = 0;
194 Uri _resolvePackageUri(Uri uri) { 218 void _finishedOneLoadRequest(String uri) {
195 if (!uri.host.isEmpty) { 219 assert(_numOutstandingLoadRequests > 0);
196 var path = '${uri.host}${uri.path}'; 220 _numOutstandingLoadRequests--;
197 var right = 'package:$path'; 221 if (_logBuiltin) {
198 var wrong = 'package://$path'; 222 _print("Loading of $uri finished, "
199 223 "${_numOutstandingLoadRequests} requests remaining");
200 throw "URIs using the 'package:' scheme should look like "
201 "'$right', not '$wrong'.";
202 } 224 }
203 225 if (_numOutstandingLoadRequests == 0) {
204 var packageRoot = _packageRoot == null ? 226 _signalDoneLoading();
205 _entryPointScript.resolve('packages/') :
206 _packageRoot;
207 return packageRoot.resolve(uri.path);
208 }
209
210
211 int _numOutstandingLoadRequests = 0;
212 var _httpClient;
213
214 void _httpGet(Uri uri, String libraryUri, loadCallback(List<int> data)) {
215 if (_httpClient == null) {
216 _httpClient = new HttpClient()..maxConnectionsPerHost = 6;
217 }
218 _httpClient.getUrl(uri)
219 .then((HttpClientRequest request) => request.close())
220 .then((HttpClientResponse response) {
221 var builder = new BytesBuilder(copy: false);
222 response.listen(
223 builder.add,
224 onDone: () {
225 if (response.statusCode != 200) {
226 var msg = 'Failure getting $uri: '
227 '${response.statusCode} ${response.reasonPhrase}';
228 _asyncLoadError(uri.toString(), libraryUri, msg);
229 }
230 loadCallback(builder.takeBytes());
231 },
232 onError: (error) {
233 _asyncLoadError(uri.toString(), libraryUri, error);
234 });
235 })
236 .catchError((error) {
237 _asyncLoadError(uri.toString(), libraryUri, error);
238 });
239 // TODO(floitsch): remove this line. It's just here to push an event on the
240 // event loop so that we invoke the scheduled microtasks. Also remove the
241 // import of dart:async when this line is not needed anymore.
242 Timer.run(() {});
243 }
244
245
246 void _signalDoneLoading() native "Builtin_DoneLoading";
247
248 void _cleanup() {
249 if (_httpClient != null) {
250 _httpClient.close();
251 _httpClient = null;
252 } 227 }
253 } 228 }
254 229
230 void _startingOneLoadRequest(String uri) {
231 assert(_numOutstandingLoadRequests >= 0);
232 _numOutstandingLoadRequests++;
233 if (_logBuiltin) {
234 _print("Loading of $uri started, "
235 "${_numOutstandingLoadRequests} requests outstanding");
236 }
237 }
238
239 class LoadError extends Error {
240 final String message;
241 LoadError(this.message);
242
243 String toString() => 'Load Error: $message';
244 }
245
246 void _signalDoneLoading() native "Builtin_DoneLoading";
255 void _loadScriptCallback(int tag, String uri, String libraryUri, List<int> data) 247 void _loadScriptCallback(int tag, String uri, String libraryUri, List<int> data)
256 native "Builtin_LoadScript"; 248 native "Builtin_LoadScript";
249 void _asyncLoadErrorCallback(uri, libraryUri, error)
250 native "Builtin_AsyncLoadError";
257 251
258 void _loadScript(int tag, String uri, String libraryUri, List<int> data) { 252 void _loadScript(int tag, String uri, String libraryUri, List<int> data) {
259 // TODO: Currently a compilation error while loading the script is 253 // TODO: Currently a compilation error while loading the script is
260 // fatal for the isolate. _loadScriptCallback() does not return and 254 // fatal for the isolate. _loadScriptCallback() does not return and
261 // the _numOutstandingLoadRequests counter remains out of sync. 255 // the _numOutstandingLoadRequests counter remains out of sync.
262 _loadScriptCallback(tag, uri, libraryUri, data); 256 _loadScriptCallback(tag, uri, libraryUri, data);
263 assert(_numOutstandingLoadRequests > 0); 257 _finishedOneLoadRequest(uri);
264 _numOutstandingLoadRequests--; 258 }
259
260 void _asyncLoadError(tag, uri, libraryUri, error) {
265 if (_logBuiltin) { 261 if (_logBuiltin) {
266 _print("native Builtin_LoadScript($uri) completed, " 262 _print("_asyncLoadError($uri), error: $error");
267 "${_numOutstandingLoadRequests} requests remaining");
268 } 263 }
269 if (_numOutstandingLoadRequests == 0) { 264 if (tag == Dart_kImportTag) {
270 _signalDoneLoading(); 265 // When importing a library, the libraryUri is the imported
271 _cleanup(); 266 // uri.
267 libraryUri = uri;
268 }
269 _asyncLoadErrorCallback(uri, libraryUri, new LoadError(error));
270 _finishedOneLoadRequest(uri);
271 }
272
273
274 // Asynchronously loads script data through a http[s] or file uri.
275 _loadDataAsync(int tag, String uri, String libraryUri) {
276 if (tag == Dart_kScriptTag) {
277 uri = _resolveScriptUri(uri);
278 }
279
280 Uri resourceUri = _createUri(uri);
281
282 var receivePort = new ReceivePort();
283 receivePort.first.then((dataOrError) {
284 if (dataOrError is List<int>) {
285 _loadScript(tag, uri, libraryUri, dataOrError);
286 } else {
287 _asyncLoadError(tag, uri, libraryUri, dataOrError);
288 }
289 }).catchError((e) {
290 _asyncLoadError(tag, uri, libraryUri, e.toString());
291 });
292
293 try {
294 var msg = [receivePort.sendPort, resourceUri.toString()];
295 _loadPort.send(msg);
296 _startingOneLoadRequest(uri);
297 } catch (e) {
298 if (_logBuiltin) {
299 _print("Exception when communicating with service isolate: $e");
300 }
301 _asyncLoadError(tag, uri, libraryUri, e.toString());
302 receivePort.close();
272 } 303 }
273 } 304 }
274 305
275 306 // Returns either a file path or a URI starting with http[s]:, as a String.
276 void _asyncLoadErrorCallback(uri, libraryUri, error) 307 String _filePathFromUri(String userUri) {
277 native "Builtin_AsyncLoadError";
278
279 void _asyncLoadError(uri, libraryUri, error) {
280 assert(_numOutstandingLoadRequests > 0);
281 if (_logBuiltin) {
282 _print("_asyncLoadError($uri), error: $error");
283 }
284 _numOutstandingLoadRequests--;
285 _asyncLoadErrorCallback(uri, libraryUri, error);
286 if (_numOutstandingLoadRequests == 0) {
287 _signalDoneLoading();
288 _cleanup();
289 }
290 }
291
292
293 // Create a Uri of 'userUri'. If the input uri is a package uri, then the
294 // package uri is resolved.
295 Uri _createUri(String userUri) {
296 var uri = Uri.parse(userUri); 308 var uri = Uri.parse(userUri);
297 if (_logBuiltin) { 309 if (_logBuiltin) {
298 _print('# Creating uri for: $uri'); 310 _print('# Getting file path from: $uri');
299 } 311 }
300 312
313 var path;
301 switch (uri.scheme) { 314 switch (uri.scheme) {
302 case '': 315 case '':
303 case 'file': 316 case 'file':
317 return uri.toFilePath();
318 case 'package':
319 return _filePathFromUri(_resolvePackageUri(uri).toString());
304 case 'http': 320 case 'http':
305 case 'https': 321 case 'https':
306 return uri; 322 return uri.toString();
307 case 'package':
308 return _resolvePackageUri(uri);
309 default: 323 default:
310 // Only handling file, http[s], and package URIs 324 // Only handling file, http, and package URIs
311 // in standalone binary. 325 // in standalone binary.
312 if (_logBuiltin) { 326 if (_logBuiltin) {
313 _print('# Unknown scheme (${uri.scheme}) in $uri.'); 327 _print('# Unknown scheme (${uri.scheme}) in $uri.');
314 } 328 }
315 throw 'Not a known scheme: $uri'; 329 throw 'Not a known scheme: $uri';
316 } 330 }
317 } 331 }
318 332
333 String _nativeLibraryExtension() native "Builtin_NativeLibraryExtension";
319 334
320 // Asynchronously loads script data through a http[s] or file uri. 335 String _platformExtensionFileName(String name) {
321 _loadDataAsync(int tag, String uri, String libraryUri) { 336 var extension = _nativeLibraryExtension();
322 if (tag == null) { 337
323 uri = _resolveScriptUri(uri); 338 if (_isWindows) {
324 } 339 return '$name.$extension';
325 Uri resourceUri = _createUri(uri);
326 _numOutstandingLoadRequests++;
327 if (_logBuiltin) {
328 _print("_loadDataAsync($uri), "
329 "${_numOutstandingLoadRequests} requests outstanding");
330 }
331 if ((resourceUri.scheme == 'http') || (resourceUri.scheme == 'https')) {
332 _httpGet(resourceUri, libraryUri, (data) {
333 _loadScript(tag, uri, libraryUri, data);
334 });
335 } else { 340 } else {
336 var sourceFile = new File(resourceUri.toFilePath()); 341 return 'lib$name.$extension';
337 sourceFile.readAsBytes().then((data) {
338 _loadScript(tag, uri, libraryUri, data);
339 },
340 onError: (e) {
341 _asyncLoadError(uri, libraryUri, e);
342 });
343 } 342 }
344 } 343 }
345 344
346 // Returns the directory part, the filename part, and the name 345 // Returns the directory part, the filename part, and the name
347 // of a native extension URL as a list [directory, filename, name]. 346 // of a native extension URL as a list [directory, filename, name].
348 // The directory part is either a file system path or an HTTP(S) URL. 347 // The directory part is either a file system path or an HTTP(S) URL.
349 // The filename part is the extension name, with the platform-dependent 348 // The filename part is the extension name, with the platform-dependent
350 // prefixes and extensions added. 349 // prefixes and extensions added.
351 _extensionPathFromUri(String userUri) { 350 _extensionPathFromUri(String userUri) {
352 if (!userUri.startsWith(_DART_EXT)) { 351 if (!userUri.startsWith(_DART_EXT)) {
353 throw 'Unexpected internal error: Extension URI $userUri missing dart-ext:'; 352 throw 'Unexpected internal error: Extension URI $userUri missing dart-ext:';
354 } 353 }
355 userUri = userUri.substring(_DART_EXT.length); 354 userUri = userUri.substring(_DART_EXT.length);
356 355
357 if (userUri.contains('\\')) { 356 if (userUri.contains('\\')) {
358 throw 'Unexpected internal error: Extension URI $userUri contains \\'; 357 throw 'Unexpected internal error: Extension URI $userUri contains \\';
359 } 358 }
360 359
361 String filename; 360
362 String name; 361 String name;
363 String path; // Will end in '/'. 362 String path; // Will end in '/'.
364 int index = userUri.lastIndexOf('/'); 363 int index = userUri.lastIndexOf('/');
365 if (index == -1) { 364 if (index == -1) {
366 name = userUri; 365 name = userUri;
367 path = './'; 366 path = './';
368 } else if (index == userUri.length - 1) { 367 } else if (index == userUri.length - 1) {
369 throw 'Extension name missing in $extensionUri'; 368 throw 'Extension name missing in $extensionUri';
370 } else { 369 } else {
371 name = userUri.substring(index + 1); 370 name = userUri.substring(index + 1);
372 path = userUri.substring(0, index + 1); 371 path = userUri.substring(0, index + 1);
373 } 372 }
374 373
375 path = _filePathFromUri(path); 374 path = _filePathFromUri(path);
376 375 var filename = _platformExtensionFileName(name);
377 if (Platform.isLinux || Platform.isAndroid) {
378 filename = 'lib$name.so';
379 } else if (Platform.isMacOS) {
380 filename = 'lib$name.dylib';
381 } else if (Platform.isWindows) {
382 filename = '$name.dll';
383 } else {
384 if (_logBuiltin) {
385 _print('Native extensions not supported on ${Platform.operatingSystem}');
386 }
387 throw 'Native extensions not supported on ${Platform.operatingSystem}';
388 }
389 376
390 return [path, filename, name]; 377 return [path, filename, name];
391 } 378 }
OLDNEW
« no previous file with comments | « runtime/bin/builtin.cc ('k') | runtime/bin/builtin_common.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698