Version 0.8.2.3

svn merge -c 28641 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 28650 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 28657 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@28709 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 0cc4351..41a06e6 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -660,13 +660,13 @@
 
 Dart_Handle DartUtils::PrepareForScriptLoading(const char* package_root,
                                                Dart_Handle builtin_lib) {
-  Dart_Handle corelib = Dart_LookupLibrary(NewString("dart:core"));
-  DART_CHECK_VALID(corelib);
-
-  // Setup the corelib 'print' function.
+  // Setup the internal library's 'internalPrint' function.
+  Dart_Handle internal_lib =
+      Dart_LookupLibrary(NewString("dart:_collection-dev"));
+  DART_CHECK_VALID(internal_lib);
   Dart_Handle print = Dart_Invoke(
       builtin_lib, NewString("_getPrintClosure"), 0, NULL);
-  Dart_Handle result = Dart_SetField(corelib,
+  Dart_Handle result = Dart_SetField(internal_lib,
                                      NewString("_printClosure"),
                                      print);
   DART_CHECK_VALID(result);
@@ -685,6 +685,8 @@
       async_lib, NewString("_setTimerFactoryClosure"), 1, args));
 
   // Setup the corelib 'Uri.base' getter.
+  Dart_Handle corelib = Dart_LookupLibrary(NewString("dart:core"));
+  DART_CHECK_VALID(corelib);
   Dart_Handle uri_base = Dart_Invoke(
       builtin_lib, NewString("_getUriBaseClosure"), 0, NULL);
   DART_CHECK_VALID(uri_base);
diff --git a/runtime/lib/collection_dev_sources.gypi b/runtime/lib/collection_dev_sources.gypi
index 76121f5..63c909f 100644
--- a/runtime/lib/collection_dev_sources.gypi
+++ b/runtime/lib/collection_dev_sources.gypi
@@ -8,6 +8,7 @@
   'sources': [
     'collection_dev_patch.dart',
     # The above file needs to be first as it imports required libraries.
+    'print_patch.dart',
     'symbol_patch.dart',
   ],
 }
diff --git a/runtime/lib/corelib_sources.gypi b/runtime/lib/corelib_sources.gypi
index 3d50b40..95a846d 100644
--- a/runtime/lib/corelib_sources.gypi
+++ b/runtime/lib/corelib_sources.gypi
@@ -38,7 +38,6 @@
     'null_patch.dart',
     'object.cc',
     'object_patch.dart',
-    'print_patch.dart',
     'regexp.cc',
     'regexp_jsc.cc',
     'regexp_jsc.h',
diff --git a/runtime/lib/print_patch.dart b/runtime/lib/print_patch.dart
index 53d034c..186b4fb 100644
--- a/runtime/lib/print_patch.dart
+++ b/runtime/lib/print_patch.dart
@@ -4,8 +4,8 @@
 
 typedef void _PrintClosure(Object obj);
 
-patch void print(Object obj) {
-  _printClosure(obj.toString());
+patch void printToConsole(String line) {
+  _printClosure(line);
 }
 
 void _unsupportedPrint(Object obj) {
diff --git a/sdk/lib/_collection_dev/collection_dev.dart b/sdk/lib/_collection_dev/collection_dev.dart
index 30a7c5c..d82d903 100644
--- a/sdk/lib/_collection_dev/collection_dev.dart
+++ b/sdk/lib/_collection_dev/collection_dev.dart
@@ -14,6 +14,6 @@
 part 'arrays.dart';
 part 'iterable.dart';
 part 'list.dart';
+part 'print.dart';
 part 'sort.dart';
 part 'symbol.dart';
-
diff --git a/sdk/lib/_collection_dev/collection_dev_sources.gypi b/sdk/lib/_collection_dev/collection_dev_sources.gypi
index 9cf5415..c85469d 100644
--- a/sdk/lib/_collection_dev/collection_dev_sources.gypi
+++ b/sdk/lib/_collection_dev/collection_dev_sources.gypi
@@ -10,6 +10,7 @@
     'arrays.dart',
     'iterable.dart',
     'list.dart',
+    'print.dart',
     'sort.dart',
     'symbol.dart',
   ],
diff --git a/sdk/lib/_collection_dev/print.dart b/sdk/lib/_collection_dev/print.dart
new file mode 100644
index 0000000..0c7182e
--- /dev/null
+++ b/sdk/lib/_collection_dev/print.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._collection.dev;
+
+/**
+ * This function is set by the first allocation of a Zone.
+ *
+ * Once the function is set the core `print` function calls this closure instead
+ * of [printToConsole].
+ *
+ * This decouples the core library from the async library.
+ */
+Function printToZone = null;
+
+external void printToConsole(String line);
diff --git a/sdk/lib/_internal/lib/collection_dev_patch.dart b/sdk/lib/_internal/lib/collection_dev_patch.dart
index f224f24..f7467fd 100644
--- a/sdk/lib/_internal/lib/collection_dev_patch.dart
+++ b/sdk/lib/_internal/lib/collection_dev_patch.dart
@@ -2,7 +2,45 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:_foreign_helper' show JS;
+
 patch class Symbol implements core.Symbol {
   patch const Symbol(String name)
       : this._name = name;
 }
+
+/**
+  * This is the low-level method that is used to implement
+  * [print]. It is possible to override this function from JavaScript
+  * by defining a function in JavaScript called "dartPrint".
+  */
+patch void printToConsole(String line) {
+  if (JS('bool', r'typeof dartPrint == "function"')) {
+    // Support overriding print from JavaScript.
+    JS('void', r'dartPrint(#)', line);
+    return;
+  }
+
+  // Inside browser or nodejs.
+  if (JS('bool', r'typeof console == "object"') &&
+      JS('bool', r'typeof console.log == "function"')) {
+    JS('void', r'console.log(#)', line);
+    return;
+  }
+
+  // Don't throw inside IE, the console is only defined if dev tools is open.
+  if (JS('bool', r'typeof window == "object"')) {
+    return;
+  }
+
+  // Running in d8, the V8 developer shell, or in Firefox' js-shell.
+  if (JS('bool', r'typeof print == "function"')) {
+    JS('void', r'print(#)', line);
+    return;
+  }
+
+  // This is somewhat nasty, but we don't want to drag in a bunch of
+  // dependencies to handle a situation that cannot happen. So we
+  // avoid using Dart [:throw:] and Dart [toString].
+  JS('void', 'throw "Unable to print message: " + String(#)', line);
+}
diff --git a/sdk/lib/_internal/lib/core_patch.dart b/sdk/lib/_internal/lib/core_patch.dart
index e14786a..cb844e0 100644
--- a/sdk/lib/_internal/lib/core_patch.dart
+++ b/sdk/lib/_internal/lib/core_patch.dart
@@ -24,10 +24,6 @@
   return result;
 }
 
-patch void print(Object object) {
-  Primitives.printString(object.toString());
-}
-
 patch int identityHashCode(Object object) => objectHashCode(object);
 
 // Patch for Object implementation.
diff --git a/sdk/lib/_internal/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart
index 0219440..8e9c4a3 100644
--- a/sdk/lib/_internal/lib/js_helper.dart
+++ b/sdk/lib/_internal/lib/js_helper.dart
@@ -281,42 +281,6 @@
 
   static computeGlobalThis() => JS('', 'function() { return this; }()');
 
-  /**
-   * This is the low-level method that is used to implement
-   * [print]. It is possible to override this function from JavaScript
-   * by defining a function in JavaScript called "dartPrint".
-   */
-  static void printString(String string) {
-    if (JS('bool', r'typeof dartPrint == "function"')) {
-      // Support overriding print from JavaScript.
-      JS('void', r'dartPrint(#)', string);
-      return;
-    }
-
-    // Inside browser or nodejs.
-    if (JS('bool', r'typeof console == "object"') &&
-        JS('bool', r'typeof console.log == "function"')) {
-      JS('void', r'console.log(#)', string);
-      return;
-    }
-
-    // Don't throw inside IE, the console is only defined if dev tools is open.
-    if (JS('bool', r'typeof window == "object"')) {
-      return;
-    }
-
-    // Running in d8, the V8 developer shell, or in Firefox' js-shell.
-    if (JS('bool', r'typeof print == "function"')) {
-      JS('void', r'print(#)', string);
-      return;
-    }
-
-    // This is somewhat nasty, but we don't want to drag in a bunch of
-    // dependencies to handle a situation that cannot happen. So we
-    // avoid using Dart [:throw:] and Dart [toString].
-    JS('void', 'throw "Unable to print message: " + String(#)', string);
-  }
-
   static _throwFormatException(String string) {
     throw new FormatException(string);
   }
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index 4d03ccd..f336c60 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.dart
@@ -18,7 +18,7 @@
 library dart.async;
 
 import "dart:collection";
-import "dart:_collection-dev" show deprecated;
+import "dart:_collection-dev" show deprecated, printToZone, printToConsole;
 
 part 'async_error.dart';
 part 'broadcast_stream_controller.dart';
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 80184c2..2306a6e 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -31,6 +31,8 @@
 typedef Timer CreatePeriodicTimerHandler(
     Zone self, ZoneDelegate parent, Zone zone,
     Duration period, void f(Timer timer));
+typedef void PrintHandler(
+    Zone self, ZoneDelegate parent, Zone zone, String line);
 typedef Zone ForkHandler(Zone self, ZoneDelegate parent, Zone zone,
                          ZoneSpecification specification,
                          Map<Symbol, dynamic> zoneValues);
@@ -82,6 +84,7 @@
                       Duration duration, void f()): null,
     Timer createPeriodicTimer(Zone self, ZoneDelegate parent, Zone zone,
                               Duration period, void f(Timer timer)): null,
+    void print(Zone self, ZoneDelegate parent, Zone zone, String line): null,
     Zone fork(Zone self, ZoneDelegate parent, Zone zone,
               ZoneSpecification specification, Map zoneValues): null
   }) = _ZoneSpecification;
@@ -112,6 +115,7 @@
                       Duration duration, void f()): null,
     Timer createPeriodicTimer(Zone self, ZoneDelegate parent, Zone zone,
                               Duration period, void f(Timer timer)): null,
+    void print(Zone self, ZoneDelegate parent, Zone zone, String line): null,
     Zone fork(Zone self, ZoneDelegate parent, Zone zone,
               ZoneSpecification specification,
               Map<Symbol, dynamic> zoneValues): null
@@ -141,6 +145,7 @@
       createPeriodicTimer: createPeriodicTimer != null
                            ? createPeriodicTimer
                            : other.createPeriodicTimer,
+      print : print != null ? print : other.print,
       fork: fork != null ? fork : other.fork);
   }
 
@@ -156,6 +161,7 @@
   RunAsyncHandler get runAsync;
   CreateTimerHandler get createTimer;
   CreatePeriodicTimerHandler get createPeriodicTimer;
+  PrintHandler get print;
   ForkHandler get fork;
 }
 
@@ -179,6 +185,7 @@
     this.runAsync: null,
     this.createTimer: null,
     this.createPeriodicTimer: null,
+    this.print: null,
     this.fork: null
   });
 
@@ -195,6 +202,7 @@
   final /*RunAsyncHandler*/ runAsync;
   final /*CreateTimerHandler*/ createTimer;
   final /*CreatePeriodicTimerHandler*/ createPeriodicTimer;
+  final /*PrintHandler*/ print;
   final /*ForkHandler*/ fork;
 }
 
@@ -224,6 +232,7 @@
   void scheduleMicrotask(Zone zone, f());
   Timer createTimer(Zone zone, Duration duration, void f());
   Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer));
+  void print(Zone zone, String line);
   Zone fork(Zone zone, ZoneSpecification specification, Map zoneValues);
 }
 
@@ -386,6 +395,11 @@
   Timer createPeriodicTimer(Duration period, void callback(Timer timer));
 
   /**
+   * Prints the given [line].
+   */
+  void print(String line);
+
+  /**
    * The error zone is the one that is responsible for dealing with uncaught
    * errors. Errors are not allowed to cross zones with different error-zones.
    */
@@ -401,14 +415,14 @@
 }
 
 class _ZoneDelegate implements ZoneDelegate {
-  final _CustomizedZone _degelationTarget;
+  final _BaseZone _degelationTarget;
 
   Zone get _zone => _degelationTarget;
 
   const _ZoneDelegate(this._degelationTarget);
 
   dynamic handleUncaughtError(Zone zone, error, StackTrace stackTrace) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.handleUncaughtError == null) {
       parent = parent.parent;
     }
@@ -417,7 +431,7 @@
   }
 
   dynamic run(Zone zone, f()) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.run == null) {
       parent = parent.parent;
     }
@@ -426,7 +440,7 @@
   }
 
   dynamic runUnary(Zone zone, f(arg), arg) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.runUnary == null) {
       parent = parent.parent;
     }
@@ -435,7 +449,7 @@
   }
 
   dynamic runBinary(Zone zone, f(arg1, arg2), arg1, arg2) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.runBinary == null) {
       parent = parent.parent;
     }
@@ -444,7 +458,7 @@
   }
 
   ZoneCallback registerCallback(Zone zone, f()) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.registerCallback == null) {
       parent = parent.parent;
     }
@@ -453,7 +467,7 @@
   }
 
   ZoneUnaryCallback registerUnaryCallback(Zone zone, f(arg)) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.registerUnaryCallback == null) {
       parent = parent.parent;
     }
@@ -462,7 +476,7 @@
   }
 
   ZoneBinaryCallback registerBinaryCallback(Zone zone, f(arg1, arg2)) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.registerBinaryCallback == null) {
       parent = parent.parent;
     }
@@ -471,7 +485,7 @@
   }
 
   void scheduleMicrotask(Zone zone, f()) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.scheduleMicrotask == null &&
            parent._specification.runAsync == null) {
       parent = parent.parent;
@@ -490,7 +504,7 @@
   }
 
   Timer createTimer(Zone zone, Duration duration, void f()) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.createTimer == null) {
       parent = parent.parent;
     }
@@ -499,7 +513,7 @@
   }
 
   Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer)) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.createPeriodicTimer == null) {
       parent = parent.parent;
     }
@@ -507,9 +521,18 @@
         parent, new _ZoneDelegate(parent.parent), zone, period, f);
   }
 
+  void print(Zone zone, String line) {
+    _BaseZone parent = _degelationTarget;
+    while (parent._specification.print == null) {
+      parent = parent.parent;
+    }
+    (parent._specification.print)(
+        parent, new _ZoneDelegate(parent.parent), zone, line);
+  }
+
   Zone fork(Zone zone, ZoneSpecification specification,
             Map<Symbol, dynamic> zoneValues) {
-    _CustomizedZone parent = _degelationTarget;
+    _BaseZone parent = _degelationTarget;
     while (parent._specification.fork == null) {
       parent = parent.parent;
     }
@@ -521,22 +544,22 @@
 
 
 /**
- * Default implementation of a [Zone].
+ * Base class for Zone implementations.
  */
-class _CustomizedZone implements Zone {
+abstract class _BaseZone implements Zone {
+  const _BaseZone();
+
   /// The parent zone.
-  final _CustomizedZone parent;
+  _BaseZone get parent;
   /// The zone's handlers.
-  final ZoneSpecification _specification;
-  /// The zone's value map.
-  final Map<Symbol, dynamic> _map;
-
-  const _CustomizedZone(this.parent, this._specification, this._map);
-
-  Zone get _errorZone {
-    if (_specification.handleUncaughtError != null) return this;
-    return parent._errorZone;
-  }
+  ZoneSpecification get _specification;
+  /**
+   * The closest error-handling zone.
+   *
+   * Returns `this` if `this` has an error-handler. Otherwise returns the
+   * parent's error-zone.
+   */
+  Zone get _errorZone;
 
   bool inSameErrorZone(Zone otherZone) => _errorZone == otherZone._errorZone;
 
@@ -591,6 +614,25 @@
       return (arg1, arg2) => this.runBinary(registered, arg1, arg2);
     }
   }
+}
+
+
+/**
+ * Default implementation of a [Zone].
+ */
+class _CustomizedZone extends _BaseZone {
+  final _BaseZone parent;
+  final ZoneSpecification _specification;
+
+  /// The zone's value map.
+  final Map<Symbol, dynamic> _map;
+
+  const _CustomizedZone(this.parent, this._specification, this._map);
+
+  Zone get _errorZone {
+    if (_specification.handleUncaughtError != null) return this;
+    return parent._errorZone;
+  }
 
   operator [](Symbol key) {
     var result = _map[key];
@@ -651,6 +693,10 @@
   Timer createPeriodicTimer(Duration duration, void f(Timer timer)) {
     return new _ZoneDelegate(this).createPeriodicTimer(this, duration, f);
   }
+
+  void print(String line) {
+    new _ZoneDelegate(this).print(this, line);
+  }
 }
 
 void _rootHandleUncaughtError(
@@ -735,9 +781,22 @@
   return _createPeriodicTimer(duration, callback);
 }
 
+void _rootPrint(Zone self, ZoneDelegate parent, Zone zone, String line) {
+  printToConsole(line);
+}
+
+void _printToZone(String line) {
+  Zone.current.print(line);
+}
+
 Zone _rootFork(Zone self, ZoneDelegate parent, Zone zone,
                ZoneSpecification specification,
                Map<Symbol, dynamic> zoneValues) {
+  // TODO(floitsch): it would be nice if we could get rid of this hack.
+  // Change the static zoneOrDirectPrint function to go through zones
+  // from now on.
+  printToZone = _printToZone;
+
   if (specification == null) {
     specification = const ZoneSpecification();
   } else if (specification is! _ZoneSpecification) {
@@ -756,22 +815,83 @@
   return new _CustomizedZone(zone, specification, copiedMap);
 }
 
-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,
-  fork: _rootFork
-);
+class _RootZoneSpecification implements ZoneSpecification {
+  const _RootZoneSpecification();
 
-const _ROOT_ZONE =
-    const _CustomizedZone(null, _ROOT_SPECIFICATION, const <Symbol, dynamic>{});
+  HandleUncaughtErrorHandler get handleUncaughtError =>
+      _rootHandleUncaughtError;
+  RunHandler get run => _rootRun;
+  RunUnaryHandler get runUnary => _rootRunUnary;
+  RunBinaryHandler get runBinary => _rootRunBinary;
+  RegisterCallbackHandler get registerCallback => _rootRegisterCallback;
+  RegisterUnaryCallbackHandler get registerUnaryCallback =>
+      _rootRegisterUnaryCallback;
+  RegisterBinaryCallbackHandler get registerBinaryCallback =>
+      _rootRegisterBinaryCallback;
+  ScheduleMicrotaskHandler get scheduleMicrotask => _rootScheduleMicrotask;
+  @deprecated
+  RunAsyncHandler get runAsync => null;
+  CreateTimerHandler get createTimer => _rootCreateTimer;
+  CreatePeriodicTimerHandler get createPeriodicTimer =>
+      _rootCreatePeriodicTimer;
+  PrintHandler get print => _rootPrint;
+  ForkHandler get fork => _rootFork;
+}
+
+class _RootZone extends _BaseZone {
+  const _RootZone();
+
+  Zone get parent => null;
+  ZoneSpecification get _specification => const _RootZoneSpecification();
+  Zone get _errorZone => this;
+
+  bool inSameErrorZone(Zone otherZone) => otherZone._errorZone == this;
+
+  operator [](Symbol key) => null;
+
+  // Methods that can be customized by the zone specification.
+
+  dynamic handleUncaughtError(error, StackTrace stackTrace) =>
+      _rootHandleUncaughtError(this, null, this, error, stackTrace);
+
+  Zone fork({ZoneSpecification specification, Map zoneValues}) =>
+      _rootFork(this, null, this, specification, zoneValues);
+
+  dynamic run(f()) => _rootRun(this, null, this, f);
+
+  dynamic runUnary(f(arg), arg) => _rootRunUnary(this, null, this, f, arg);
+
+  dynamic runBinary(f(arg1, arg2), arg1, arg2) =>
+      _rootRunBinary(this, null, this, f, arg1, arg2);
+
+  ZoneCallback registerCallback(f()) =>
+      _rootRegisterCallback(this, null, this, f);
+
+  ZoneUnaryCallback registerUnaryCallback(f(arg)) =>
+      _rootRegisterUnaryCallback(this, null, this, f);
+
+  ZoneBinaryCallback registerBinaryCallback(f(arg1, arg2)) =>
+      _rootRegisterBinaryCallback(this, null, this, f);
+
+  void scheduleMicrotask(void f()) {
+    _rootScheduleMicrotask(this, null, this, f);
+  }
+
+  @deprecated
+  void runAsync(void f()) {
+    scheduleMicrotask(f);
+  }
+
+  Timer createTimer(Duration duration, void f()) =>
+      _rootCreateTimer(this, null, this, duration, f);
+
+  Timer createPeriodicTimer(Duration duration, void f(Timer timer)) =>
+      _rootCreatePeriodicTimer(this, null, this, duration, f);
+
+  void print(String line) => _rootPrint(this, null, this, line);
+}
+
+const _ROOT_ZONE = const _RootZone();
 
 
 /**
diff --git a/sdk/lib/core/print.dart b/sdk/lib/core/print.dart
index 17ef817..4379ceb 100644
--- a/sdk/lib/core/print.dart
+++ b/sdk/lib/core/print.dart
@@ -4,4 +4,11 @@
 
 part of dart.core;
 
-external void print(Object object);
+void print(Object object) {
+  String line = object.toString();
+  if (printToZone == null) {
+    printToConsole(line);
+  } else {
+    printToZone(line);
+  }
+}
diff --git a/tests/compiler/dart2js/mirrors_used_test.dart b/tests/compiler/dart2js/mirrors_used_test.dart
index acc1356..25ac037 100644
--- a/tests/compiler/dart2js/mirrors_used_test.dart
+++ b/tests/compiler/dart2js/mirrors_used_test.dart
@@ -59,7 +59,7 @@
     // 2. Some code was refactored, and there are more methods.
     // Either situation could be problematic, but in situation 2, it is often
     // acceptable to increase [expectedMethodCount] a little.
-    int expectedMethodCount = 325;
+    int expectedMethodCount = 326;
     Expect.isTrue(
         generatedCode.length <= expectedMethodCount,
         'Too many compiled methods: '
diff --git a/tests/lib/async/intercept_print1_test.dart b/tests/lib/async/intercept_print1_test.dart
new file mode 100644
index 0000000..ad074c0
--- /dev/null
+++ b/tests/lib/async/intercept_print1_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'catch_errors.dart';
+
+var events = [];
+
+void printHandler1(Zone self, ZoneDelegate parent, Zone origin, String line) {
+  events.add("print: $line");
+}
+
+bool shouldIntercept = true;
+
+void printHandler2(Zone self, ZoneDelegate parent, Zone origin, String line) {
+  if (shouldIntercept) {
+    events.add("print **: $line");
+  } else {
+    parent.print(origin, line);
+  }
+}
+
+const TEST_SPEC1 = const ZoneSpecification(print: printHandler1);
+const TEST_SPEC2 = const ZoneSpecification(print: printHandler2);
+
+main() {
+  Zone zone1 = Zone.current.fork(specification: TEST_SPEC1);
+  Zone zone2 = zone1.fork(specification: TEST_SPEC2);
+  zone1.run(() {
+    print("1");
+    print(2);
+    print({3: [4]});
+  });
+  zone2.run(() {
+    print("5");
+    shouldIntercept = false;
+    print(6);
+  });
+  Expect.listEquals(
+      ["print: 1", "print: 2", "print: {3: [4]}", "print **: 5", "print: 6"],
+      events);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 4f047c0..b6fd3d5 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 8
 BUILD 2
-PATCH 2
+PATCH 3