Chromium Code Reviews| Index: sdk/lib/_internal/pub/lib/src/dart.dart |
| diff --git a/sdk/lib/_internal/pub/lib/src/dart.dart b/sdk/lib/_internal/pub/lib/src/dart.dart |
| index d1e3b03d0a1e254d0175db8f690bb2d28929dd12..c48d3f4754995ad8c3952dda57d2dfcfd91b42ec 100644 |
| --- a/sdk/lib/_internal/pub/lib/src/dart.dart |
| +++ b/sdk/lib/_internal/pub/lib/src/dart.dart |
| @@ -6,9 +6,11 @@ |
| library pub.dart; |
| import 'dart:async'; |
| +import 'dart:isolate'; |
| import 'package:analyzer_experimental/analyzer.dart'; |
| import 'package:path/path.dart' as path; |
| +import 'package:stack_trace/stack_trace.dart'; |
| import '../../../compiler/compiler.dart' as compiler; |
| import '../../../compiler/implementation/source_file_provider.dart' |
| show FormattingDiagnosticHandler, SourceFileProvider; |
| @@ -63,3 +65,84 @@ bool isEntrypoint(CompilationUnit dart) { |
| node.functionExpression.parameters.parameters.isEmpty; |
| }); |
| } |
| + |
| +/// Runs [code] in an isolate. |
| +/// |
| +/// [code] should be the contents of a Dart entrypoint. It may contain imports; |
| +/// they will be resolved in the same context as the host isolate. |
| +/// |
| +/// Returns a Future that will resolve to a send point that will communicate to |
|
Bob Nystrom
2013/08/27 22:12:30
"send point" -> "[SendPort]".
nweiz
2013/08/28 20:45:23
Done.
|
| +/// the spawned isolate once it's spawned. If the isolate fails to spawn, the |
| +/// Future will complete with an error. |
| +Future<SendPort> runInIsolate(String code) { |
| + return withTempDir((dir) { |
| + var dartPath = path.join(dir, 'runInIsolate.dart'); |
| + writeTextFile(dartPath, code, dontLogContents: true); |
| + var bufferPort = spawnFunction(_isolateBuffer); |
| + return bufferPort.call(path.toUri(dartPath).toString()).then((response) { |
| + if (response.first == 'error') { |
| + return new Future.error( |
| + new CrossIsolateException.deserialize(response.last)); |
| + } |
| + |
| + return response.last; |
| + }); |
| + }); |
| +} |
| + |
| +// TODO(nweiz): remove this when issue 12617 is fixed. |
| +/// A function used as a buffer between the host isolate and [spawnUri]. |
| +/// |
| +/// [spawnUri] synchronously loads the file and its imports, which can deadlock |
| +/// the host isolate if there's an HTTP import pointing at a server in the host. |
| +/// Adding an additional isolate in the middle works around this. |
| +void _isolateBuffer() { |
| + port.receive((uri, replyTo) { |
| + try { |
| + replyTo.send(['success', spawnUri(uri)]); |
| + } catch (e, stack) { |
| + replyTo.send(['error', CrossIsolateException.serialize(e, stack)]); |
| + } |
| + }); |
| +} |
| + |
| +/// An exception that was originally raised in another isolate. |
| +/// |
| +/// Exception objects can't cross isolate boundaries in general, so this class |
| +/// wraps as much information as can be consistently serialized. |
| +class CrossIsolateException implements Exception { |
| + /// The name of the type of exception thrown. |
| + /// |
| + /// This is the return value of [error.runtimeType.toString()]. Keep in mind |
| + /// that objects in different libraries may have the same type name. |
| + final String type; |
| + |
| + /// The exception's message, or its [toString] if it didn't expose a `message` |
| + /// property. |
| + final String message; |
| + |
| + /// The exception's stack trace, or `null` if no stack trace was available. |
| + final Trace stackTrace; |
| + |
| + /// Loads a [CrossIsolateException] from a map. |
| + /// |
| + /// [error] should be the result of [CrossIsolateException.serialize]. |
| + CrossIsolateException.deserialize(Map error) |
|
Bob Nystrom
2013/08/27 22:12:30
Instead of Map here and below, I'd just use Object
nweiz
2013/08/28 20:45:23
Done.
|
| + : type = error['type'], |
| + message = error['message'], |
| + stackTrace = error['stack'] == null ? null : |
| + new Trace.parse(error['stack']); |
| + |
| + /// Serializes [error] to a map that can safely be passed across isolate |
| + /// boundaries. |
| + static Map serialize(error, [StackTrace stack]) { |
| + if (stack == null) stack = getAttachedStackTrace(error); |
| + return { |
| + 'type': error.runtimeType.toString(), |
| + 'message': getErrorMessage(error), |
| + 'stack': stack == null ? null : stack.toString() |
| + }; |
| + } |
| + |
| + String toString() => "$message\n$stackTrace"; |
| +} |