Index: tool/input_sdk/lib/async/schedule_microtask.dart |
diff --git a/tool/input_sdk/lib/async/schedule_microtask.dart b/tool/input_sdk/lib/async/schedule_microtask.dart |
index cc0931d40cc5e9ee02f5b9a93dc641bd851b9c1e..70fbeba924d664bd0934e6d0defbc2227bc5869c 100644 |
--- a/tool/input_sdk/lib/async/schedule_microtask.dart |
+++ b/tool/input_sdk/lib/async/schedule_microtask.dart |
@@ -32,24 +32,28 @@ _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; |
- entry.callback(); |
+ (entry.callback)(); |
} |
} |
-void _asyncRunCallback() { |
+void _startMicrotaskLoop() { |
_isInCallbackLoop = true; |
try { |
- _asyncRunCallbackLoop(); |
+ // Moved to separate function because try-finally prevents |
+ // good optimization. |
+ _microtaskLoop(); |
} finally { |
_lastPriorityCallback = null; |
_isInCallbackLoop = false; |
- if (_nextCallback != null) _AsyncRun._scheduleImmediate(_asyncRunCallback); |
+ if (_nextCallback != null) { |
+ _AsyncRun._scheduleImmediate(_startMicrotaskLoop); |
+ } |
} |
} |
@@ -59,16 +63,14 @@ 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(_AsyncCallback callback) { |
+ _AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback); |
if (_nextCallback == null) { |
- _nextCallback = _lastCallback = new _AsyncCallbackEntry(callback); |
+ _nextCallback = _lastCallback = newEntry; |
if (!_isInCallbackLoop) { |
- _AsyncRun._scheduleImmediate(_asyncRunCallback); |
+ _AsyncRun._scheduleImmediate(_startMicrotaskLoop); |
} |
} else { |
- _AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback); |
_lastCallback.next = newEntry; |
_lastCallback = newEntry; |
} |
@@ -79,13 +81,17 @@ 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); |
+void _schedulePriorityAsyncCallback(_AsyncCallback callback) { |
if (_nextCallback == null) { |
_scheduleAsyncCallback(callback); |
_lastPriorityCallback = _lastCallback; |
- } else if (_lastPriorityCallback == null) { |
+ return; |
+ } |
+ _AsyncCallbackEntry entry = new _AsyncCallbackEntry(callback); |
+ if (_lastPriorityCallback == null) { |
entry.next = _nextCallback; |
_nextCallback = _lastPriorityCallback = entry; |
} else { |
@@ -124,12 +130,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)); |
} |