Index: sdk/lib/_internal/lib/isolate_helper.dart |
diff --git a/sdk/lib/_internal/lib/isolate_helper.dart b/sdk/lib/_internal/lib/isolate_helper.dart |
index 85d9f2bd0442e559dfcd67a695fed23a543e3243..0a6bcb7799490c662b794787f17bb8d86587f804 100644 |
--- a/sdk/lib/_internal/lib/isolate_helper.dart |
+++ b/sdk/lib/_internal/lib/isolate_helper.dart |
@@ -89,7 +89,6 @@ void startRootIsolate(entry, args) { |
// isolate automatically we try to give them a reasonable context to live in |
// by having a "default" isolate (the first one created). |
_globalState.currentContext = rootContext; |
- |
if (entry is _MainFunctionArgs) { |
rootContext.eval(() { entry(args); }); |
} else if (entry is _MainFunctionArgsMessage) { |
@@ -271,6 +270,13 @@ class _IsolateContext implements IsolateContext { |
final Capability pauseCapability = new Capability(); |
final Capability terminateCapability = new Capability(); // License to kill. |
+ /// Boolean flag set when the initial method of the isolate has been executed. |
+ /// |
+ /// Used to avoid considering the isolate dead when it has no open |
+ /// receive ports and no scheduled timers, because it hasn't had time to |
+ /// create them yet. |
+ bool initialized = false; |
+ |
// TODO(lrn): Store these in single "PauseState" object, so they don't take |
// up as much room when not pausing. |
bool isPaused = false; |
@@ -290,11 +296,11 @@ class _IsolateContext implements IsolateContext { |
var _scheduledControlEvents; |
bool _isExecutingEvent = false; |
- /** Whether errors are considered fatal. */ |
- // This doesn't do anything yet. We need to be able to catch uncaught errors |
- // (oxymoronically) in order to take lethal action. This is waiting for the |
- // same change as the uncaught error listeners. |
- bool errorsAreFatal = false; |
+ /** Whether uncaught errors are considered fatal. */ |
+ bool errorsAreFatal = true; |
+ |
+ // Set of ports that listen to uncaught errors. |
+ Set<SendPort> errorPorts = new Set(); |
_IsolateContext() { |
this.registerWeak(controlPort._id, controlPort); |
@@ -379,6 +385,40 @@ class _IsolateContext implements IsolateContext { |
_scheduledControlEvents.addLast(kill); |
} |
+ void addErrorListener(SendPort port) { |
+ errorPorts.add(port); |
+ } |
+ |
+ void removeErrorListener(SendPort port) { |
+ errorPorts.remove(port); |
+ } |
+ |
+ /** Function called with an uncaught error. */ |
+ void handleUncaughtError(error, StackTrace stackTrace) { |
+ // Just print the error if there is no error listener registered. |
+ if (errorPorts.isEmpty) { |
+ // An uncaught error in the root isolate will terminate the program? |
+ if (errorsAreFatal && identical(this, _globalState.rootContext)) { |
+ // The error will be rethrown to reach the global scope, so |
+ // don't print it. |
+ return; |
+ } |
+ if (JS('bool', '#.console != null && ' |
+ 'typeof #.console.error == "function"', |
+ globalThis, globalThis)) { |
+ JS('void', '#.console.error(#, #)', globalThis, error, stackTrace); |
+ } else { |
+ print(error); |
+ if (stackTrace != null) print(stackTrace); |
+ } |
+ return; |
+ } |
+ List message = new List(2) |
+ ..[0] = error.toString() |
+ ..[1] = (stackTrace == null) ? null : stackTrace.toString(); |
+ for (SendPort port in errorPorts) port.send(message); |
+ } |
+ |
/** |
* Run [code] in the context of the isolate represented by [this]. |
*/ |
@@ -390,6 +430,15 @@ class _IsolateContext implements IsolateContext { |
_isExecutingEvent = true; |
try { |
result = code(); |
+ } catch (e, s) { |
+ handleUncaughtError(e, s); |
+ if (errorsAreFatal) { |
+ kill(); |
+ // An uncaught error in the root context terminates all isolates. |
+ if (identical(this, _globalState.rootContext)) { |
+ rethrow; |
+ } |
+ } |
} finally { |
_isExecutingEvent = false; |
_globalState.currentContext = old; |
@@ -437,6 +486,12 @@ class _IsolateContext implements IsolateContext { |
case "kill": |
handleKill(message[1], message[2]); |
break; |
+ case "getErrors": |
+ addErrorListener(message[1]); |
+ break; |
+ case "stopErrors": |
+ removeErrorListener(message[1]); |
+ break; |
default: |
} |
} |
@@ -468,7 +523,7 @@ class _IsolateContext implements IsolateContext { |
} |
void _updateGlobalState() { |
- if (ports.length - weakPorts.length > 0 || isPaused) { |
+ if (ports.length - weakPorts.length > 0 || isPaused || !initialized) { |
_globalState.isolates[id] = this; // indicate this isolate is active |
} else { |
kill(); |
@@ -490,6 +545,7 @@ class _IsolateContext implements IsolateContext { |
ports.clear(); |
weakPorts.clear(); |
_globalState.isolates.remove(id); // indicate this isolate is not active |
+ errorPorts.clear(); |
if (doneHandlers != null) { |
for (SendPort port in doneHandlers) { |
port.send(null); |
@@ -920,6 +976,7 @@ class IsolateNatives { |
context.terminateCapability]); |
void runStartFunction() { |
+ context.initialized = true; |
if (!isSpawnUri) { |
topLevel(message); |
} else if (topLevel is _MainFunctionArgsMessage) { |