| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 /// A library for compiling Dart code and manipulating analyzer parse trees. | 5 /// A library for compiling Dart code and manipulating analyzer parse trees. |
| 6 library pub.dart; | 6 library pub.dart; |
| 7 | 7 |
| 8 import 'dart:async'; | 8 import 'dart:async'; |
| 9 import 'dart:isolate'; | 9 import 'dart:isolate'; |
| 10 | 10 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 /// [code] should be the contents of a Dart entrypoint. It may contain imports; | 85 /// [code] should be the contents of a Dart entrypoint. It may contain imports; |
| 86 /// they will be resolved in the same context as the host isolate. | 86 /// they will be resolved in the same context as the host isolate. |
| 87 /// | 87 /// |
| 88 /// Returns a Future that will resolve to a [SendPort] that will communicate to | 88 /// Returns a Future that will resolve to a [SendPort] that will communicate to |
| 89 /// the spawned isolate once it's spawned. If the isolate fails to spawn, the | 89 /// the spawned isolate once it's spawned. If the isolate fails to spawn, the |
| 90 /// Future will complete with an error. | 90 /// Future will complete with an error. |
| 91 Future<SendPort> runInIsolate(String code) { | 91 Future<SendPort> runInIsolate(String code) { |
| 92 return withTempDir((dir) { | 92 return withTempDir((dir) { |
| 93 var dartPath = path.join(dir, 'runInIsolate.dart'); | 93 var dartPath = path.join(dir, 'runInIsolate.dart'); |
| 94 writeTextFile(dartPath, code, dontLogContents: true); | 94 writeTextFile(dartPath, code, dontLogContents: true); |
| 95 var bufferPort = spawnFunction(_isolateBuffer); | 95 var port = new ReceivePort(); |
| 96 return bufferPort.call(path.toUri(dartPath).toString()).then((response) { | 96 var initialMessage = [path.toUri(dartPath).toString(), port.sendPort]; |
| 97 if (response.first == 'error') { | 97 var isolate = Isolate.spawn(_isolateBuffer, initialMessage); |
| 98 return new Future.error( | 98 return isolate.then((_) { |
| 99 new CrossIsolateException.deserialize(response.last)); | 99 return port.first.then((response) { |
| 100 } | 100 if (response.first == 'error') { |
| 101 return new Future.error( |
| 102 new CrossIsolateException.deserialize(response.last)); |
| 103 } |
| 101 | 104 |
| 102 return response.last; | 105 return response.last; |
| 106 }); |
| 103 }); | 107 }); |
| 104 }); | 108 }); |
| 105 } | 109 } |
| 106 | 110 |
| 107 // TODO(nweiz): remove this when issue 12617 is fixed. | 111 // TODO(nweiz): remove this when issue 12617 is fixed. |
| 108 /// A function used as a buffer between the host isolate and [spawnUri]. | 112 /// A function used as a buffer between the host isolate and [spawnUri]. |
| 109 /// | 113 /// |
| 110 /// [spawnUri] synchronously loads the file and its imports, which can deadlock | 114 /// [spawnUri] synchronously loads the file and its imports, which can deadlock |
| 111 /// the host isolate if there's an HTTP import pointing at a server in the host. | 115 /// the host isolate if there's an HTTP import pointing at a server in the host. |
| 112 /// Adding an additional isolate in the middle works around this. | 116 /// Adding an additional isolate in the middle works around this. |
| 113 void _isolateBuffer() { | 117 void _isolateBuffer(initialMessage) { |
| 114 port.receive((uri, replyTo) { | 118 var uri = initialMessage[0]; |
| 115 try { | 119 var replyTo = initialMessage[1]; |
| 116 replyTo.send(['success', spawnUri(uri)]); | 120 try { |
| 117 } catch (e, stack) { | 121 // TODO(floitsch): If we do it right we shouldn't need to have a try/catch |
| 122 // and a catchError. |
| 123 Isolate.spawnUri(Uri.parse(uri), [], replyTo).catchError((e, stack) { |
| 118 replyTo.send(['error', CrossIsolateException.serialize(e, stack)]); | 124 replyTo.send(['error', CrossIsolateException.serialize(e, stack)]); |
| 119 } | 125 }); |
| 120 }); | 126 } catch (e, stack) { |
| 127 replyTo.send(['error', CrossIsolateException.serialize(e, stack)]); |
| 128 } |
| 121 } | 129 } |
| 122 | 130 |
| 123 /// An exception that was originally raised in another isolate. | 131 /// An exception that was originally raised in another isolate. |
| 124 /// | 132 /// |
| 125 /// Exception objects can't cross isolate boundaries in general, so this class | 133 /// Exception objects can't cross isolate boundaries in general, so this class |
| 126 /// wraps as much information as can be consistently serialized. | 134 /// wraps as much information as can be consistently serialized. |
| 127 class CrossIsolateException implements Exception { | 135 class CrossIsolateException implements Exception { |
| 128 /// The name of the type of exception thrown. | 136 /// The name of the type of exception thrown. |
| 129 /// | 137 /// |
| 130 /// This is the return value of [error.runtimeType.toString()]. Keep in mind | 138 /// This is the return value of [error.runtimeType.toString()]. Keep in mind |
| (...skipping 29 matching lines...) Expand all Loading... |
| 160 if (stack == null) stack = getAttachedStackTrace(error); | 168 if (stack == null) stack = getAttachedStackTrace(error); |
| 161 return { | 169 return { |
| 162 'type': error.runtimeType.toString(), | 170 'type': error.runtimeType.toString(), |
| 163 'message': getErrorMessage(error), | 171 'message': getErrorMessage(error), |
| 164 'stack': stack == null ? null : stack.toString() | 172 'stack': stack == null ? null : stack.toString() |
| 165 }; | 173 }; |
| 166 } | 174 } |
| 167 | 175 |
| 168 String toString() => "$message\n$stackTrace"; | 176 String toString() => "$message\n$stackTrace"; |
| 169 } | 177 } |
| OLD | NEW |