| 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); | 
| } | 
| } | 
| }; | 
|  |