Index: sdk/lib/async/zone.dart |
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart |
index 4f067dd7fdecd75efac0bf4730f03499ab2ed8f1..39ce0c550018b07905e58fdbd43bb278d5c999fc 100644 |
--- a/sdk/lib/async/zone.dart |
+++ b/sdk/lib/async/zone.dart |
@@ -6,16 +6,21 @@ part of dart.async; |
typedef dynamic ZoneCallback(); |
typedef dynamic ZoneUnaryCallback(arg); |
+typedef dynamic ZoneBinaryCallback(arg1, arg2); |
typedef dynamic HandleUncaughtErrorHandler( |
- Zone self, ZoneDelegate parent, Zone zone, e); |
+ Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace); |
typedef dynamic RunHandler(Zone self, ZoneDelegate parent, Zone zone, f()); |
typedef dynamic RunUnaryHandler( |
Zone self, ZoneDelegate parent, Zone zone, f(arg), arg); |
+typedef dynamic RunBinaryHandler( |
+ Zone self, ZoneDelegate parent, Zone zone, f(arg1, arg2), arg1, arg2); |
typedef ZoneCallback RegisterCallbackHandler( |
Zone self, ZoneDelegate parent, Zone zone, f()); |
typedef ZoneUnaryCallback RegisterUnaryCallbackHandler( |
Zone self, ZoneDelegate parent, Zone zone, f(arg)); |
+typedef ZoneBinaryCallback RegisterBinaryCallbackHandler( |
+ Zone self, ZoneDelegate parent, Zone zone, f(arg1, arg2)); |
typedef void ScheduleMicrotaskHandler( |
Zone self, ZoneDelegate parent, Zone zone, f()); |
typedef Timer CreateTimerHandler( |
@@ -51,15 +56,19 @@ abstract class ZoneSpecification { |
* Creates a specification with the provided handlers. |
*/ |
const factory ZoneSpecification({ |
- void handleUncaughtError( |
- Zone self, ZoneDelegate parent, Zone zone, e): null, |
+ dynamic handleUncaughtError(Zone self, ZoneDelegate parent, Zone zone, |
+ error, StackTrace stackTrace): null, |
dynamic run(Zone self, ZoneDelegate parent, Zone zone, f()): null, |
dynamic runUnary( |
Zone self, ZoneDelegate parent, Zone zone, f(arg), arg): null, |
+ dynamic runBinary(Zone self, ZoneDelegate parent, Zone zone, |
+ f(arg1, arg2), arg1, arg2): null, |
ZoneCallback registerCallback( |
Zone self, ZoneDelegate parent, Zone zone, f()): null, |
ZoneUnaryCallback registerUnaryCallback( |
Zone self, ZoneDelegate parent, Zone zone, f(arg)): null, |
+ ZoneBinaryCallback registerBinaryCallback( |
+ Zone self, ZoneDelegate parent, Zone zone, f(arg1, arg2)): null, |
void scheduleMicrotask( |
Zone self, ZoneDelegate parent, Zone zone, f()): null, |
Timer createTimer(Zone self, ZoneDelegate parent, Zone zone, |
@@ -75,15 +84,19 @@ abstract class ZoneSpecification { |
* the ones in [other]. |
*/ |
factory ZoneSpecification.from(ZoneSpecification other, { |
- void handleUncaughtError( |
- Zone self, ZoneDelegate parent, Zone zone, e): null, |
+ dynamic handleUncaughtError(Zone self, ZoneDelegate parent, Zone zone, |
+ error, StackTrace stackTrace): null, |
dynamic run(Zone self, ZoneDelegate parent, Zone zone, f()): null, |
dynamic runUnary( |
Zone self, ZoneDelegate parent, Zone zone, f(arg), arg): null, |
+ dynamic runBinary(Zone self, ZoneDelegate parent, Zone zone, |
+ f(arg1, arg2), arg1, arg2): null, |
ZoneCallback registerCallback( |
Zone self, ZoneDelegate parent, Zone zone, f()): null, |
ZoneUnaryCallback registerUnaryCallback( |
Zone self, ZoneDelegate parent, Zone zone, f(arg)): null, |
+ ZoneBinaryCallback registerBinaryCallback( |
+ Zone self, ZoneDelegate parent, Zone zone, f(arg1, arg2)): null, |
void scheduleMicrotask( |
Zone self, ZoneDelegate parent, Zone zone, f()): null, |
Timer createTimer(Zone self, ZoneDelegate parent, Zone zone, |
@@ -100,12 +113,16 @@ abstract class ZoneSpecification { |
: other.handleUncaughtError, |
run: run != null ? run : other.run, |
runUnary: runUnary != null ? runUnary : other.runUnary, |
+ runBinary: runBinary != null ? runBinary : other.runBinary, |
registerCallback: registerCallback != null |
? registerCallback |
: other.registerCallback, |
registerUnaryCallback: registerUnaryCallback != null |
? registerUnaryCallback |
: other.registerUnaryCallback, |
+ registerBinaryCallback: registerBinaryCallback != null |
+ ? registerBinaryCallback |
+ : other.registerBinaryCallback, |
scheduleMicrotask: scheduleMicrotask != null |
? scheduleMicrotask |
: other.scheduleMicrotask, |
@@ -119,8 +136,10 @@ abstract class ZoneSpecification { |
HandleUncaughtErrorHandler get handleUncaughtError; |
RunHandler get run; |
RunUnaryHandler get runUnary; |
+ RunBinaryHandler get runBinary; |
RegisterCallbackHandler get registerCallback; |
RegisterUnaryCallbackHandler get registerUnaryCallback; |
+ RegisterBinaryCallbackHandler get registerBinaryCallback; |
ScheduleMicrotaskHandler get scheduleMicrotask; |
CreateTimerHandler get createTimer; |
CreatePeriodicTimerHandler get createPeriodicTimer; |
@@ -139,8 +158,10 @@ class _ZoneSpecification implements ZoneSpecification { |
this.handleUncaughtError: null, |
this.run: null, |
this.runUnary: null, |
+ this.runBinary: null, |
this.registerCallback: null, |
this.registerUnaryCallback: null, |
+ this.registerBinaryCallback: null, |
this.scheduleMicrotask: null, |
this.createTimer: null, |
this.createPeriodicTimer: null, |
@@ -151,8 +172,10 @@ class _ZoneSpecification implements ZoneSpecification { |
final /*HandleUncaughtErrorHandler*/ handleUncaughtError; |
final /*RunHandler*/ run; |
final /*RunUnaryHandler*/ runUnary; |
+ final /*RunBinaryHandler*/ runBinary; |
final /*RegisterCallbackHandler*/ registerCallback; |
final /*RegisterUnaryCallbackHandler*/ registerUnaryCallback; |
+ final /*RegisterBinaryCallbackHandler*/ registerBinaryCallback; |
final /*ScheduleMicrotaskHandler*/ scheduleMicrotask; |
final /*CreateTimerHandler*/ createTimer; |
final /*CreatePeriodicTimerHandler*/ createPeriodicTimer; |
@@ -173,11 +196,13 @@ abstract class ZoneDelegate { |
/// The [Zone] this class wraps. |
Zone get _zone; |
- dynamic handleUncaughtError(Zone zone, e); |
+ dynamic handleUncaughtError(Zone zone, error, StackTrace stackTrace); |
dynamic run(Zone zone, f()); |
dynamic runUnary(Zone zone, f(arg), arg); |
+ dynamic runBinary(Zone zone, f(arg1, arg2), arg1, arg2); |
ZoneCallback registerCallback(Zone zone, f()); |
ZoneUnaryCallback registerUnaryCallback(Zone zone, f(arg)); |
+ ZoneBinaryCallback registerBinaryCallback(Zone zone, f(arg1, arg2)); |
void scheduleMicrotask(Zone zone, f()); |
Timer createTimer(Zone zone, Duration duration, void f()); |
Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer)); |
@@ -202,7 +227,7 @@ abstract class Zone { |
static Zone get current => _current; |
- dynamic handleUncaughtError(error); |
+ dynamic handleUncaughtError(error, StackTrace stackTrace); |
/** |
* Returns the parent zone. |
@@ -236,6 +261,12 @@ abstract class Zone { |
dynamic runUnary(f(arg), var arg); |
/** |
+ * Executes the given callback [f] with argument [arg1] and [arg2] in this |
+ * zone. |
+ */ |
+ dynamic runBinary(f(arg1, arg2), var arg1, var arg2); |
+ |
+ /** |
* Executes the given function [f] in this zone. |
* |
* Same as [run] but catches uncaught errors and gives them to |
@@ -252,6 +283,14 @@ abstract class Zone { |
dynamic runUnaryGuarded(f(arg), var arg); |
/** |
+ * Executes the given callback [f] in this zone. |
+ * |
+ * Same as [runBinary] but catches uncaught errors and gives them to |
+ * [handleUncaughtError]. |
+ */ |
+ dynamic runBinaryGuarded(f(arg1, arg2), var arg1, var arg2); |
+ |
+ /** |
* Registers the given callback in this zone. |
* |
* It is good practice to register asynchronous or delayed callbacks before |
@@ -273,6 +312,13 @@ abstract class Zone { |
ZoneUnaryCallback registerUnaryCallback(callback(arg)); |
/** |
+ * Registers the given callback in this zone. |
+ * |
+ * Similar to [registerCallback] but with a unary callback. |
+ */ |
+ ZoneBinaryCallback registerBinaryCallback(callback(arg1, arg2)); |
+ |
+ /** |
* Equivalent to: |
* |
* ZoneCallback registered = registerCallback(f); |
@@ -281,16 +327,29 @@ abstract class Zone { |
* |
*/ |
ZoneCallback bindCallback(f(), { bool runGuarded: true }); |
+ |
/** |
* Equivalent to: |
* |
- * ZoneCallback registered = registerCallback1(f); |
+ * ZoneCallback registered = registerUnaryCallback(f); |
* if (runGuarded) return (arg) => this.runUnaryGuarded(registered, arg); |
* return (arg) => thin.runUnary(registered, arg); |
*/ |
ZoneUnaryCallback bindUnaryCallback(f(arg), { bool runGuarded: true }); |
/** |
+ * Equivalent to: |
+ * |
+ * ZoneCallback registered = registerBinaryCallback(f); |
+ * if (runGuarded) { |
+ * return (arg1, arg2) => this.runBinaryGuarded(registered, arg); |
+ * } |
+ * return (arg1, arg2) => thin.runBinary(registered, arg1, arg2); |
+ */ |
+ ZoneBinaryCallback bindBinaryCallback( |
+ f(arg1, arg2), { bool runGuarded: true }); |
+ |
+ /** |
* Runs [f] asynchronously. |
*/ |
void scheduleMicrotask(void f()); |
@@ -327,13 +386,13 @@ class _ZoneDelegate implements ZoneDelegate { |
const _ZoneDelegate(this._degelationTarget); |
- dynamic handleUncaughtError(Zone zone, e) { |
+ dynamic handleUncaughtError(Zone zone, error, StackTrace stackTrace) { |
_CustomizedZone parent = _degelationTarget; |
while (parent._specification.handleUncaughtError == null) { |
parent = parent.parent; |
} |
return (parent._specification.handleUncaughtError)( |
- parent, new _ZoneDelegate(parent.parent), zone, e); |
+ parent, new _ZoneDelegate(parent.parent), zone, error, stackTrace); |
} |
dynamic run(Zone zone, f()) { |
@@ -354,6 +413,15 @@ class _ZoneDelegate implements ZoneDelegate { |
parent, new _ZoneDelegate(parent.parent), zone, f, arg); |
} |
+ dynamic runBinary(Zone zone, f(arg1, arg2), arg1, arg2) { |
+ _CustomizedZone parent = _degelationTarget; |
+ while (parent._specification.runBinary == null) { |
+ parent = parent.parent; |
+ } |
+ return (parent._specification.runBinary)( |
+ parent, new _ZoneDelegate(parent.parent), zone, f, arg1, arg2); |
+ } |
+ |
ZoneCallback registerCallback(Zone zone, f()) { |
_CustomizedZone parent = _degelationTarget; |
while (parent._specification.registerCallback == null) { |
@@ -372,6 +440,15 @@ class _ZoneDelegate implements ZoneDelegate { |
parent, new _ZoneDelegate(parent.parent), zone, f); |
} |
+ ZoneBinaryCallback registerBinaryCallback(Zone zone, f(arg1, arg2)) { |
+ _CustomizedZone parent = _degelationTarget; |
+ while (parent._specification.registerBinaryCallback == null) { |
+ parent = parent.parent; |
+ } |
+ return (parent._specification.registerBinaryCallback)( |
+ parent, new _ZoneDelegate(parent.parent), zone, f); |
+ } |
+ |
void scheduleMicrotask(Zone zone, f()) { |
_CustomizedZone parent = _degelationTarget; |
while (parent._specification.scheduleMicrotask == null) { |
@@ -436,7 +513,7 @@ class _CustomizedZone implements Zone { |
try { |
return run(f); |
} catch (e, s) { |
- return handleUncaughtError(_asyncError(e, s)); |
+ return handleUncaughtError(e, s); |
} |
} |
@@ -444,7 +521,15 @@ class _CustomizedZone implements Zone { |
try { |
return runUnary(f, arg); |
} catch (e, s) { |
- return handleUncaughtError(_asyncError(e, s)); |
+ return handleUncaughtError(e, s); |
+ } |
+ } |
+ |
+ dynamic runBinaryGuarded(f(arg1, arg2), arg1, arg2) { |
+ try { |
+ return runBinary(f, arg1, arg2); |
+ } catch (e, s) { |
+ return handleUncaughtError(e, s); |
} |
} |
@@ -466,6 +551,16 @@ class _CustomizedZone implements Zone { |
} |
} |
+ ZoneBinaryCallback bindBinaryCallback( |
+ f(arg1, arg2), { bool runGuarded: true }) { |
+ ZoneBinaryCallback registered = registerBinaryCallback(f); |
+ if (runGuarded) { |
+ return (arg1, arg2) => this.runBinaryGuarded(registered, arg1, arg2); |
+ } else { |
+ return (arg1, arg2) => this.runBinary(registered, arg1, arg2); |
+ } |
+ } |
+ |
operator [](Symbol key) { |
var result = _map[key]; |
if (result != null || _map.containsKey(key)) return result; |
@@ -477,8 +572,8 @@ class _CustomizedZone implements Zone { |
// Methods that can be customized by the zone specification. |
- dynamic handleUncaughtError(error) { |
- return new _ZoneDelegate(this).handleUncaughtError(this, error); |
+ dynamic handleUncaughtError(error, StackTrace stackTrace) { |
+ return new _ZoneDelegate(this).handleUncaughtError(this, error, stackTrace); |
} |
Zone fork({ZoneSpecification specification, Map zoneValues}) { |
@@ -493,6 +588,10 @@ class _CustomizedZone implements Zone { |
return new _ZoneDelegate(this).runUnary(this, f, arg); |
} |
+ dynamic runBinary(f(arg1, arg2), arg1, arg2) { |
+ return new _ZoneDelegate(this).runBinary(this, f, arg1, arg2); |
+ } |
+ |
ZoneCallback registerCallback(f()) { |
return new _ZoneDelegate(this).registerCallback(this, f); |
} |
@@ -501,6 +600,10 @@ class _CustomizedZone implements Zone { |
return new _ZoneDelegate(this).registerUnaryCallback(this, f); |
} |
+ ZoneBinaryCallback registerBinaryCallback(f(arg1, arg2)) { |
+ return new _ZoneDelegate(this).registerBinaryCallback(this, f); |
+ } |
+ |
void scheduleMicrotask(void f()) { |
new _ZoneDelegate(this).scheduleMicrotask(this, f); |
} |
@@ -515,13 +618,15 @@ class _CustomizedZone implements Zone { |
} |
void _rootHandleUncaughtError( |
- Zone self, ZoneDelegate parent, Zone zone, error) { |
+ Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace) { |
_scheduleAsyncCallback(() { |
print("Uncaught Error: ${error}"); |
- var trace = getAttachedStackTrace(error); |
+ var trace = stackTrace; |
+ if (trace == null) trace = getAttachedStackTrace(error); |
+ // Clear the attached stack trace (if any). |
_attachStackTrace(error, null); |
if (trace != null) { |
- print("Stack Trace:\n$trace\n"); |
+ print("Stack Trace: \n$trace\n"); |
} |
throw error; |
}); |
@@ -551,6 +656,19 @@ dynamic _rootRunUnary(Zone self, ZoneDelegate parent, Zone zone, f(arg), arg) { |
} |
} |
+dynamic _rootRunBinary(Zone self, ZoneDelegate parent, Zone zone, |
+ f(arg1, arg2), arg1, arg2) { |
+ if (Zone._current == zone) return f(arg1, arg2); |
+ |
+ Zone old = Zone._current; |
+ try { |
+ Zone._current = zone; |
+ return f(arg1, arg2); |
+ } finally { |
+ Zone._current = old; |
+ } |
+} |
+ |
ZoneCallback _rootRegisterCallback( |
Zone self, ZoneDelegate parent, Zone zone, f()) { |
return f; |
@@ -561,6 +679,11 @@ ZoneUnaryCallback _rootRegisterUnaryCallback( |
return f; |
} |
+ZoneBinaryCallback _rootRegisterBinaryCallback( |
+ Zone self, ZoneDelegate parent, Zone zone, f(arg1, arg2)) { |
+ return f; |
+} |
+ |
void _rootScheduleMicrotask(Zone self, ZoneDelegate parent, Zone zone, f()) { |
_scheduleAsyncCallback(f); |
} |
@@ -601,8 +724,10 @@ const _ROOT_SPECIFICATION = const ZoneSpecification( |
handleUncaughtError: _rootHandleUncaughtError, |
run: _rootRun, |
runUnary: _rootRunUnary, |
+ runBinary: _rootRunBinary, |
registerCallback: _rootRegisterCallback, |
registerUnaryCallback: _rootRegisterUnaryCallback, |
+ registerBinaryCallback: _rootRegisterBinaryCallback, |
scheduleMicrotask: _rootScheduleMicrotask, |
createTimer: _rootCreateTimer, |
createPeriodicTimer: _rootCreatePeriodicTimer, |
@@ -641,17 +766,21 @@ const _ROOT_ZONE = |
dynamic runZoned(body(), |
{ Map<Symbol, dynamic> zoneValues, |
ZoneSpecification zoneSpecification, |
- void onError(error) }) { |
+ Function onError }) { |
HandleUncaughtErrorHandler errorHandler; |
if (onError != null) { |
- errorHandler = (Zone self, ZoneDelegate parent, Zone zone, error) { |
+ errorHandler = (Zone self, ZoneDelegate parent, Zone zone, |
+ error, StackTrace stackTrace) { |
try { |
+ if (onError is ZoneBinaryCallback) { |
+ return self.parent.runBinary(onError, error, stackTrace); |
+ } |
return self.parent.runUnary(onError, error); |
} catch(e, s) { |
if (identical(e, error)) { |
- return parent.handleUncaughtError(zone, error); |
+ return parent.handleUncaughtError(zone, error, stackTrace); |
} else { |
- return parent.handleUncaughtError(zone, _asyncError(e, s)); |
+ return parent.handleUncaughtError(zone, e, s); |
} |
} |
}; |
@@ -704,14 +833,15 @@ runZonedExperimental(body(), |
} |
HandleUncaughtErrorHandler errorHandler; |
if (onError != null) { |
- errorHandler = (Zone self, ZoneDelegate parent, Zone zone, error) { |
+ errorHandler = (Zone self, ZoneDelegate parent, Zone zone, |
+ error, StackTrace stackTrace) { |
try { |
return self.parent.runUnary(onError, error); |
} catch(e, s) { |
if (identical(e, error)) { |
- return parent.handleUncaughtError(zone, error); |
+ return parent.handleUncaughtError(zone, error, stackTrace); |
} else { |
- return parent.handleUncaughtError(zone, _asyncError(e, s)); |
+ return parent.handleUncaughtError(zone, _asyncError(e, s), s); |
} |
} |
}; |