| 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) {
|
|
|