| Index: dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart | 
| diff --git a/dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart | 
| index cc6d052cce473a4d293d4ddbcea5d028b473526d..60853523726971f18b71eeba915b000c5a3c581b 100644 | 
| --- a/dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart | 
| +++ b/dart/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart | 
| @@ -951,30 +951,81 @@ class MathNatives { | 
| } | 
|  | 
| /** | 
| - * Throws the given Dart object as an exception by wrapping it in a | 
| - * proper JavaScript error object and then throwing that. That gives | 
| - * us a reasonable stack trace on most JavaScript implementations. The | 
| - * code in [unwrapException] deals with getting the original Dart | 
| + * Wrap the given Dart object and record a stack trace. | 
| + * | 
| + * The code in [unwrapException] deals with getting the original Dart | 
| * object out of the wrapper again. | 
| */ | 
| $throw(ex) { | 
| if (ex == null) ex = const NullThrownError(); | 
| -  var jsError = JS('var', r'new Error()'); | 
| -  JS('void', r'#.name = #', jsError, ex); | 
| -  JS('void', r'#.description = #', jsError, ex); | 
| -  JS('void', r'#.dartException = #', jsError, ex); | 
| -  JS('void', r'#.toString = #', jsError, | 
| -     DART_CLOSURE_TO_JS(toStringWrapper)); | 
| -  JS('void', r'throw #', jsError); | 
| +  var wrapper = new DartError(ex); | 
| + | 
| +  if (JS('bool', 'Error.captureStackTrace')) { | 
| +    // Use V8 API for recording a "fast" stack trace (this installs a | 
| +    // "stack" property getter on [wrapper]). | 
| +    JS('void', r'Error.captureStackTrace(#, #)', | 
| +       wrapper, RAW_DART_FUNCTION_REF($throw)); | 
| +  } else { | 
| +    // Otherwise, produce a stack trace and record it in the wrapper. | 
| +    // This is a slower way to create a stack trace which works on | 
| +    // some browsers, but may simply evaluate to null. | 
| +    String stackTrace = JS('', 'new Error().stack'); | 
| +    JS('void', '#.stack = #', wrapper, stackTrace); | 
| +  } | 
| +  return wrapper; | 
| } | 
|  | 
| /** | 
| - * This method is installed as JavaScript toString method on exception | 
| - * objects in [$throw]. So JavaScript 'this' binds to an instance of | 
| - * JavaScript Error to which we have added a property 'dartException' | 
| - * which holds a Dart object. | 
| + * Wrapper class for throwing exceptions. | 
| */ | 
| -toStringWrapper() => JS('', r'this.dartException').toString(); | 
| +class DartError { | 
| +  /// The Dart object (or primitive JavaScript value) which was thrown. | 
| +  final dartException; | 
| + | 
| +  DartError(this.dartException) { | 
| +    // Install a toString method that the JavaScript system will call | 
| +    // to format uncaught exceptions. | 
| +    JS('void', '#.toString = #', this, DART_CLOSURE_TO_JS(toStringWrapper)); | 
| +  } | 
| + | 
| +  /** | 
| +   * V8/Chrome installs a property getter, "stack", when calling | 
| +   * Error.captureStackTrace (see [$throw]). In [$throw], we make sure | 
| +   * that this property is always set. | 
| +   */ | 
| +  String get stack => JS('', '#.stack', this); | 
| + | 
| +  /** | 
| +   * This method can be invoked by calling toString from | 
| +   * JavaScript. See the constructor of this class. | 
| +   * | 
| +   * We only expect this method to be called (indirectly) by the | 
| +   * browser when an uncaught exception occurs. Instance of this class | 
| +   * should never escape into Dart code (except for [$throw] above). | 
| +   */ | 
| +  String toString() { | 
| +    // If Error.captureStackTrace is available, accessing stack from | 
| +    // this method would cause recursion because the stack property | 
| +    // (on this object) is actually a getter which calls toString on | 
| +    // this object (via the wrapper installed in this class' | 
| +    // constructor). Fortunately, both Chrome and d8 prints the stack | 
| +    // trace and Chrome even applies source maps to the stack | 
| +    // trace. Remeber, this method is only ever invoked by the browser | 
| +    // when an uncaught exception occurs. | 
| +    if (JS('bool', 'Error.captureStackTrace') || (stack == null)) { | 
| +      return dartException.toString(); | 
| +    } else { | 
| +      return '$dartException\n$stack'; | 
| +    } | 
| +  } | 
| + | 
| +  /** | 
| +   * This method is installed as JavaScript toString method on | 
| +   * [DartError].  So JavaScript 'this' binds to an instance of | 
| +   * DartError. | 
| +   */ | 
| +  static toStringWrapper() => JS('', r'this').toString(); | 
| +} | 
|  | 
| makeLiteralListConst(list) { | 
| JS('bool', r'#.immutable$list = #', list, true); | 
|  |