Index: sdk/lib/async/schedule_microtask.dart |
diff --git a/sdk/lib/async/schedule_microtask.dart b/sdk/lib/async/schedule_microtask.dart |
index cc0931d40cc5e9ee02f5b9a93dc641bd851b9c1e..acc4036ee7fa2e60646f64ebdbfba7aa639f4ddc 100644 |
--- a/sdk/lib/async/schedule_microtask.dart |
+++ b/sdk/lib/async/schedule_microtask.dart |
@@ -8,8 +8,9 @@ typedef void _AsyncCallback(); |
class _AsyncCallbackEntry { |
final _AsyncCallback callback; |
+ final Zone zone; |
_AsyncCallbackEntry next; |
- _AsyncCallbackEntry(this.callback); |
+ _AsyncCallbackEntry(this.callback, this.zone); |
} |
/** Head of single linked list of pending callbacks. */ |
@@ -32,24 +33,30 @@ _AsyncCallbackEntry _lastPriorityCallback; |
*/ |
bool _isInCallbackLoop = false; |
-void _asyncRunCallbackLoop() { |
+void _microtaskLoop() { |
while (_nextCallback != null) { |
_lastPriorityCallback = null; |
_AsyncCallbackEntry entry = _nextCallback; |
_nextCallback = entry.next; |
if (_nextCallback == null) _lastCallback = null; |
+ Zone._current = entry.zone; |
entry.callback(); |
} |
} |
-void _asyncRunCallback() { |
+void _microtaskLoopEntry() { |
_isInCallbackLoop = true; |
try { |
- _asyncRunCallbackLoop(); |
+ // Moved to separate function because try-finally prevents |
+ // good optimization. |
+ _microtaskLoop(); |
} finally { |
+ Zone._current = _ROOT_ZONE; |
_lastPriorityCallback = null; |
_isInCallbackLoop = false; |
- if (_nextCallback != null) _AsyncRun._scheduleImmediate(_asyncRunCallback); |
+ if (_nextCallback != null) { |
+ _AsyncRun._scheduleImmediate(_microtaskLoopEntry); |
+ } |
} |
} |
@@ -59,16 +66,13 @@ void _asyncRunCallback() { |
* The microtask is called after all other currently scheduled |
* microtasks, but as part of the current system event. |
*/ |
-void _scheduleAsyncCallback(callback) { |
- // Optimizing a group of Timer.run callbacks to be executed in the |
- // same Timer callback. |
+void _scheduleAsyncCallback(_AsyncCallbackEntry newEntry) { |
if (_nextCallback == null) { |
- _nextCallback = _lastCallback = new _AsyncCallbackEntry(callback); |
+ _nextCallback = _lastCallback = newEntry; |
if (!_isInCallbackLoop) { |
- _AsyncRun._scheduleImmediate(_asyncRunCallback); |
+ _AsyncRun._scheduleImmediate(_microtaskLoopEntry); |
} |
} else { |
- _AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback); |
_lastCallback.next = newEntry; |
_lastCallback = newEntry; |
} |
@@ -79,11 +83,14 @@ void _scheduleAsyncCallback(callback) { |
* |
* This callback takes priority over existing scheduled callbacks. |
* It is only used internally to give higher priority to error reporting. |
+ * |
+ * Is always run in the root zone. |
*/ |
void _schedulePriorityAsyncCallback(callback) { |
- _AsyncCallbackEntry entry = new _AsyncCallbackEntry(callback); |
+ _AsyncCallbackEntry entry = |
+ new _AsyncCallbackEntry(callback, _ROOT_ZONE); |
if (_nextCallback == null) { |
- _scheduleAsyncCallback(callback); |
+ _scheduleAsyncCallback(entry); |
_lastPriorityCallback = _lastCallback; |
} else if (_lastPriorityCallback == null) { |
entry.next = _nextCallback; |
@@ -124,12 +131,20 @@ void _schedulePriorityAsyncCallback(callback) { |
* better asynchronous code with fewer surprises. |
*/ |
void scheduleMicrotask(void callback()) { |
- if (identical(_ROOT_ZONE, Zone.current)) { |
+ _Zone currentZone = Zone.current; |
+ if (identical(_ROOT_ZONE, currentZone)) { |
// No need to bind the callback. We know that the root's scheduleMicrotask |
// will be invoked in the root zone. |
_rootScheduleMicrotask(null, null, _ROOT_ZONE, callback); |
return; |
} |
+ _ZoneFunction implementation = currentZone._scheduleMicrotask; |
+ if (identical(_ROOT_ZONE, implementation.zone) && |
+ _ROOT_ZONE.inSameErrorZone(currentZone)) { |
+ _rootScheduleMicrotask(null, null, currentZone, |
+ currentZone.registerCallback(callback)); |
+ return; |
+ } |
Zone.current.scheduleMicrotask( |
Zone.current.bindCallback(callback, runGuarded: true)); |
} |