Version 0.3.7.1
svn merge -r 18570:18571 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@18593 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/lib/compiler/implementation/lib/web.dart b/lib/compiler/implementation/lib/web.dart
new file mode 100644
index 0000000..a75db7b
--- /dev/null
+++ b/lib/compiler/implementation/lib/web.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2012, 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.
+
+#library("web");
+
+String htmlEscape(String text) {
+  throw "Unimplemented: web::htmlEscape(String).";
+}
diff --git a/lib/compiler/implementation/lib/web.dartp b/lib/compiler/implementation/lib/web.dartp
new file mode 100644
index 0000000..c3ba2ad
--- /dev/null
+++ b/lib/compiler/implementation/lib/web.dartp
@@ -0,0 +1,13 @@
+// Copyright (c) 2012, 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.
+
+// Patch file for dart:web
+
+/*patch*/ String htmlEscape(String text) {
+  return text.replaceAll("&", "&")
+             .replaceAll("<", "&lt;")
+             .replaceAll(">", "&gt;")
+             .replaceAll('"', "&quot;")
+             .replaceAll("'", "&apos;");  // Different from original.
+}
diff --git a/lib/dom/templates/html/dartium/factoryprovider__Elements.darttemplate b/lib/dom/templates/html/dartium/factoryprovider__Elements.darttemplate
new file mode 100644
index 0000000..8fe27e5
--- /dev/null
+++ b/lib/dom/templates/html/dartium/factoryprovider__Elements.darttemplate
@@ -0,0 +1,7 @@
+// Copyright (c) 2012, 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.
+
+class _Elements {
+
+$!FACTORY_METHODS}
diff --git a/lib/dom/templates/html/dartium/impl_EventTarget.darttemplate b/lib/dom/templates/html/dartium/impl_EventTarget.darttemplate
new file mode 100644
index 0000000..1b4a00d
--- /dev/null
+++ b/lib/dom/templates/html/dartium/impl_EventTarget.darttemplate
@@ -0,0 +1,106 @@
+// Copyright (c) 2012, 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.
+
+class _EventsImpl implements Events {
+  // TODO(podivilov): add type.
+  final _ptr;
+
+  final Map<String, EventListenerList> _listenerMap;
+
+  _EventsImpl(this._ptr) : _listenerMap = <EventListenerList>{};
+
+  EventListenerList operator [](String type) {
+    return _listenerMap.putIfAbsent(type,
+      () => new _EventListenerListImpl(_ptr, type));
+  }
+}
+
+class _EventListenerWrapper {
+  final EventListener raw;
+  final Function wrapped;
+  final bool useCapture;
+  _EventListenerWrapper(this.raw, this.wrapped, this.useCapture);
+}
+
+class _EventListenerListImpl implements EventListenerList {
+  // TODO(podivilov): add type.
+  final _ptr;
+  final String _type;
+  List<_EventListenerWrapper> _wrappers;
+
+  _EventListenerListImpl(this._ptr, this._type) :
+    // TODO(jacobr): switch to <_EventListenerWrapper>[] when the VM allow it.
+    _wrappers = new List<_EventListenerWrapper>();
+
+  EventListenerList add(EventListener listener, [bool useCapture = false]) {
+    _add(listener, useCapture);
+    return this;
+  }
+
+  EventListenerList remove(EventListener listener, [bool useCapture = false]) {
+    _remove(listener, useCapture);
+    return this;
+  }
+
+  bool dispatch(Event evt) {
+    // TODO(jacobr): what is the correct behavior here. We could alternately
+    // force the event to have the expected type.
+    assert(evt.type == _type);
+    return _ptr.$dom_dispatchEvent(evt);
+  }
+
+  void _add(EventListener listener, bool useCapture) {
+    _ptr.$dom_addEventListener(_type,
+                          _findOrAddWrapper(listener, useCapture),
+                          useCapture);
+  }
+
+  void _remove(EventListener listener, bool useCapture) {
+    Function wrapper = _removeWrapper(listener, useCapture);
+    if (wrapper !== null) {
+      _ptr.$dom_removeEventListener(_type, wrapper, useCapture);
+    }
+  }
+
+  Function _removeWrapper(EventListener listener, bool useCapture) {
+    if (_wrappers === null) {
+      return null;
+    }
+    for (int i = 0; i < _wrappers.length; i++) {
+      _EventListenerWrapper wrapper = _wrappers[i];
+      if (wrapper.raw === listener && wrapper.useCapture == useCapture) {
+        // Order doesn't matter so we swap with the last element instead of
+        // performing a more expensive remove from the middle of the list.
+        if (i + 1 != _wrappers.length) {
+          _wrappers[i] = _wrappers.removeLast();
+        } else {
+          _wrappers.removeLast();
+        }
+        return wrapper.wrapped;
+      }
+    }
+    return null;
+  }
+
+  Function _findOrAddWrapper(EventListener listener, bool useCapture) {
+    if (_wrappers === null) {
+      _wrappers = <_EventListenerWrapper>[];
+    } else {
+      for (_EventListenerWrapper wrapper in _wrappers) {
+        if (wrapper.raw === listener && wrapper.useCapture == useCapture) {
+          return wrapper.wrapped;
+        }
+      }
+    }
+    final wrapped = (e) { listener(e); };
+    _wrappers.add(new _EventListenerWrapper(listener, wrapped, useCapture));
+    return wrapped;
+  }
+}
+
+class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+/*
+$!MEMBERS
+*/
+}
diff --git a/lib/dom/templates/html/frog/factoryprovider__Elements.darttemplate b/lib/dom/templates/html/frog/factoryprovider__Elements.darttemplate
new file mode 100644
index 0000000..8fe27e5
--- /dev/null
+++ b/lib/dom/templates/html/frog/factoryprovider__Elements.darttemplate
@@ -0,0 +1,7 @@
+// Copyright (c) 2012, 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.
+
+class _Elements {
+
+$!FACTORY_METHODS}
diff --git a/lib/dom/templates/html/frog/impl_EventTarget.darttemplate b/lib/dom/templates/html/frog/impl_EventTarget.darttemplate
new file mode 100644
index 0000000..893f3d2
--- /dev/null
+++ b/lib/dom/templates/html/frog/impl_EventTarget.darttemplate
@@ -0,0 +1,61 @@
+// Copyright (c) 2012, 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.
+
+class _EventsImpl implements Events {
+  /* Raw event target. */
+  // TODO(jacobr): it would be nice if we could specify this as
+  // _EventTargetImpl or EventTarget
+  final Dynamic _ptr;
+
+  _EventsImpl(this._ptr);
+
+  _EventListenerListImpl operator [](String type) {
+    return new _EventListenerListImpl(_ptr, type);
+  }
+}
+
+class _EventListenerListImpl implements EventListenerList {
+  
+  // TODO(jacobr): make this _EventTargetImpl
+  final Dynamic _ptr;
+  final String _type;
+
+  _EventListenerListImpl(this._ptr, this._type);
+
+  // TODO(jacobr): implement equals.
+
+  _EventListenerListImpl add(EventListener listener,
+      [bool useCapture = false]) {
+    _add(listener, useCapture);
+    return this;
+  }
+
+  _EventListenerListImpl remove(EventListener listener,
+      [bool useCapture = false]) {
+    _remove(listener, useCapture);
+    return this;
+  }
+
+  bool dispatch(Event evt) {
+    // TODO(jacobr): what is the correct behavior here. We could alternately
+    // force the event to have the expected type.
+    assert(evt.type == _type);
+    return _ptr.$dom_dispatchEvent(evt);
+  }
+
+  void _add(EventListener listener, bool useCapture) {
+    _ptr.$dom_addEventListener(_type, listener, useCapture);
+  }
+
+  void _remove(EventListener listener, bool useCapture) {
+    _ptr.$dom_removeEventListener(_type, listener, useCapture);
+  }
+}
+
+
+class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+
+  Events get on() => new _EventsImpl(this);
+$!MEMBERS
+}
diff --git a/pkg/analyzer-experimental/lib/src/generated/java_core.dart b/pkg/analyzer-experimental/lib/src/generated/java_core.dart
index 7b148cb..5d49598 100644
--- a/pkg/analyzer-experimental/lib/src/generated/java_core.dart
+++ b/pkg/analyzer-experimental/lib/src/generated/java_core.dart
@@ -303,7 +303,7 @@
     return elements.removeLast();
   }
 
-  Iterable<E> get reversed => elements.reversed;
+  List<E> get reversed => elements.reversed;
 
   List<E> getRange(int start, int length) {
     return elements.getRange(start, length);
diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart
index 0f02eb4..3ce453b 100644
--- a/runtime/lib/array.dart
+++ b/runtime/lib/array.dart
@@ -164,7 +164,7 @@
     return this.length == 0;
   }
 
-  Iterable<E> get reversed => new ReversedListIterable<E>(this);
+  List<E> get reversed => new ReversedListView<E>(this, 0, null);
 
   void sort([int compare(E a, E b)]) {
     IterableMixinWorkaround.sortList(this, compare);
@@ -402,7 +402,7 @@
     return this.length == 0;
   }
 
-  Iterable<E> get reversed => new ReversedListIterable<E>(this);
+  List<E> get reversed => new ReversedListView<E>(this, 0, null);
 
   void sort([int compare(E a, E b)]) {
     throw new UnsupportedError(
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index d030e64..5bd8987 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -310,7 +310,7 @@
     this.length = 0;
   }
 
-  Iterable<T> get reversed => new ReversedListIterable<T>(this);
+  List<T> get reversed => new ReversedListView<T>(this, 0, null);
 
   void sort([int compare(T a, T b)]) {
     IterableMixinWorkaround.sortList(this, compare);
diff --git a/sdk/lib/_collection_dev/iterable.dart b/sdk/lib/_collection_dev/iterable.dart
index 5df7378..676ad73 100644
--- a/sdk/lib/_collection_dev/iterable.dart
+++ b/sdk/lib/_collection_dev/iterable.dart
@@ -4,6 +4,7 @@
 
 part of dart._collection.dev;
 
+
 /**
  * An [Iterable] for classes that have efficient [length] and [elementAt].
  *
@@ -14,7 +15,7 @@
   int get length;
   E elementAt(int i);
 
-  Iterator<E> get iterator => new ListIterator<E>(this);
+  Iterator<E> get iterator => new ListIterableIterator<E>(this);
 
   void forEach(void action(E element)) {
     int length = this.length;
@@ -92,7 +93,7 @@
 
   E lastMatching(bool test(E element), { E orElse() }) {
     int length = this.length;
-    for (int i = length - 1; i >= 0; i--) {
+    for (int i = length - 1; i >= 0; i++) {
       E element = elementAt(i);
       if (test(element)) return element;
       if (length != this.length) {
@@ -203,7 +204,7 @@
     var value = initialValue;
     int length = this.length;
     for (int i = 0; i < length; i++) {
-      value = combine(value, elementAt(i));
+      value = reduce(value, elementAt(i));
       if (length != this.length) {
         throw new ConcurrentModificationError(this);
       }
@@ -236,7 +237,7 @@
   }
 }
 
-class SubListIterable<E> extends ListIterable<E> {
+abstract class SubListIterable<E> extends ListIterable<E> {
   final Iterable<E> _iterable;
   final int _start;
   /** If null, represents the length of the iterable. */
@@ -283,27 +284,19 @@
     if (_endOrLength == null) {
       return new SubListIterable(_iterable, _start, _start + count);
     } else {
-      int newEnd = _start + count;
+      newEnd = _start + count;
       if (_endOrLength < newEnd) return this;
       return new SubListIterable(_iterable, _start, newEnd);
     }
   }
 }
 
-/**
- * An [Iterator] that iterates a list-like [Iterable].
- *
- * All iterations is done in terms of [Iterable.length] and
- * [Iterable.elementAt]. These operations are fast for list-like
- * iterables.
- */
-class ListIterator<E> implements Iterator<E> {
+class ListIterableIterator<E> implements Iterator<E> {
   final Iterable<E> _iterable;
   final int _length;
   int _index;
   E _current;
-
-  ListIterator(Iterable<E> iterable)
+  ListIterableIterator(Iterable<E> iterable)
       : _iterable = iterable, _length = iterable.length, _index = 0;
 
   E get current => _current;
@@ -337,14 +330,9 @@
   // Length related functions are independent of the mapping.
   int get length => _iterable.length;
   bool get isEmpty => _iterable.isEmpty;
-
-  // Index based lookup can be done before transforming.
-  T get first => _f(_iterable.first);
-  T get last => _f(_iterable.last);
-  T get single => _f(_iterable.single);
-  T elementAt(int index) => _f(_iterable.elementAt(index));
 }
 
+
 class MappedIterator<S, T> extends Iterator<T> {
   T _current;
   final Iterator<S> _iterator;
@@ -358,25 +346,343 @@
     if (_iterator.moveNext()) {
       _current = _f(_iterator.current);
       return true;
+    } else {
+      _current = null;
+      return false;
     }
-    _current = null;
-    return false;
   }
 
   T get current => _current;
 }
 
 /** Specialized alternative to [MappedIterable] for mapped [List]s. */
-class MappedListIterable<S, T> extends ListIterable<T> {
-  final Iterable<S> _source;
+class MappedListIterable<S, T> extends Iterable<T> {
+  final List<S> _list;
+  /**
+   * Start index of the part of the list to map.
+   *
+   * Allows mapping only a sub-list of an existing list.
+   *
+   * Used to implement lazy skip/take on a [MappedListIterable].
+   */
+  final int _start;
+
+  /**
+   * End index of the part of the list to map.
+   *
+   * If null, always use the length of the list.
+   */
+  final int _end;
+
   // TODO(ahe): Restore type when feature is implemented in dart2js
   // checked mode. http://dartbug.com/7733
   final /* _Transformation<S, T> */ _f;
 
-  MappedListIterable(this._source, T this._f(S value));
+  MappedListIterable(this._list, T this._f(S element), this._start, this._end) {
+    if (_end != null && _end < _start) {
+      throw new ArgumentError("End ($_end) before start ($_start)");
+    }
+  }
 
-  int get length => _source.length;
-  T elementAt(int index) => _f(_source.elementAt(index));
+  /** The start index, limited to the current length of the list. */
+  int get _startIndex {
+    if (_start <= _list.length) return _start;
+    return _list.length;
+  }
+
+  /** The end index, if given, limited to the current length of the list. */
+  int get _endIndex {
+    if (_end == null || _end > _list.length) return _list.length;
+    return _end;
+  }
+
+  Iterator<T> get iterator =>
+      new MappedListIterator<S, T>(_list, _f, _startIndex, _endIndex);
+
+  void forEach(void action(T element)) {
+    int length = _list.length;
+    for (int i = _startIndex, n = _endIndex; i < n; i++) {
+      action(_f(_list[i]));
+      if (_list.length != length) {
+        throw new ConcurrentModificationError(_list);
+      }
+    }
+  }
+
+  bool get isEmpty => _startIndex == _endIndex;
+
+  int get length => _endIndex - _startIndex;
+
+  T get first {
+    int start = _startIndex;
+    if (start == _endIndex) {
+      throw new StateError("No elements");
+    }
+    return _f(_list.elementAt(start));
+  }
+
+  T get last {
+    int end = _endIndex;
+    if (end == _startIndex) {
+      throw new StateError("No elements");
+    }
+    return _f(_list.elementAt(end - 1));
+  }
+
+  T get single {
+    int start = _startIndex;
+    int end = _endIndex;
+    if (start != end - 1) {
+      if (start == end) {
+        throw new StateError("No elements");
+      }
+      throw new StateError("Too many elements");
+    }
+    return _f(_list[start]);
+  }
+
+  T elementAt(int index) {
+    index += _startIndex;
+    if (index >= _endIndex) {
+      throw new StateError("No matching element");
+    }
+    return _f(_list.elementAt(index));
+  }
+
+  bool contains(T element) {
+    int length = _list.length;
+    for (int i = _startIndex, n = _endIndex; i < n; i++) {
+      if (_f(_list[i]) == element) {
+        return true;
+      }
+      if (_list.length != length) {
+        throw new ConcurrentModificationError(_list);
+      }
+    }
+    return false;
+  }
+
+  bool every(bool test(T element)) {
+    int length = _list.length;
+    for (int i = _startIndex, n = _endIndex; i < n; i++) {
+      if (!test(_f(_list[i]))) return false;
+      if (_list.length != length) {
+        throw new ConcurrentModificationError(_list);
+      }
+    }
+    return true;
+  }
+
+  bool any(bool test(T element)) {
+    int length = _list.length;
+    for (int i = _startIndex, n = _endIndex; i < n; i++) {
+      if (test(_f(_list[i]))) return true;
+      if (_list.length != length) {
+        throw new ConcurrentModificationError(_list);
+      }
+    }
+    return false;
+  }
+
+  T firstMatching(bool test(T element), { T orElse() }) {
+    int length = _list.length;
+    for (int i = _startIndex, n = _endIndex; i < n; i++) {
+      T value = _f(_list[i]);
+      if (test(value)) return value;
+      if (_list.length != length) {
+        throw new ConcurrentModificationError(_list);
+      }
+    }
+    if (orElse != null) return orElse();
+    throw new StateError("No matching element");
+  }
+
+  T lastMatching(bool test(T element), { T orElse() }) {
+    int length = _list.length;
+    for (int i = _endIndex - 1, start = _startIndex; i >= start; i++) {
+      T value = _f(_list[i]);
+      if (test(value)) return value;
+      if (_list.length != length) {
+        throw new ConcurrentModificationError(_list);
+      }
+    }
+    if (orElse != null) return orElse();
+    throw new StateError("No matching element");
+  }
+
+  T singleMatching(bool test(T element)) {
+    int length = _list.length;
+    T match;
+    bool matchFound = false;
+    for (int i = _startIndex, n = _endIndex; i < n; i++) {
+      T value = _f(_list[i]);
+      if (test(value)) {
+        if (matchFound) {
+          throw new StateError("More than one matching element");
+        }
+        matchFound = true;
+        match = value;
+      }
+      if (_list.length != length) {
+        throw new ConcurrentModificationError(_list);
+      }
+    }
+    if (matchFound) return match;
+    throw new StateError("No matching element");
+  }
+
+  T min([int compare(T a, T b)]) {
+    if (compare == null) {
+      var defaultCompare = Comparable.compare;
+      compare = defaultCompare;
+    }
+    int length = _list.length;
+    int start = _startIndex;
+    int end = _endIndex;
+    if (start == end) return null;
+    T value = _f(_list[start]);
+    if (_list.length != length) {
+      throw new ConcurrentModificationError(_list);
+    }
+    for (int i = start + 1; i < end; i++) {
+      T nextValue = _f(_list[i]);
+      if (compare(value, nextValue) > 0) {
+        value = nextValue;
+      }
+      if (_list.length != length) {
+        throw new ConcurrentModificationError(_list);
+      }
+    }
+    return value;
+  }
+
+  T max([int compare(T a, T b)]) {
+    if (compare == null) {
+      var defaultCompare = Comparable.compare;
+      compare = defaultCompare;
+    }
+    int length = _list.length;
+    int start = _startIndex;
+    int end = _endIndex;
+    if (start == end) return null;
+    T value = _f(_list[start]);
+    if (_list.length != length) {
+      throw new ConcurrentModificationError(_list);
+    }
+    for (int i = start + 1; i < end; i++) {
+      T nextValue = _f(_list[i]);
+      if (compare(value, nextValue) < 0) {
+        value = nextValue;
+      }
+      if (_list.length != length) {
+        throw new ConcurrentModificationError(_list);
+      }
+    }
+    return value;
+  }
+
+  String join([String separator]) {
+    int start = _startIndex;
+    int end = _endIndex;
+    if (start == end) return "";
+    StringBuffer buffer = new StringBuffer("${_f(_list[start])}");
+    if (_list.length != length) {
+      throw new ConcurrentModificationError(_list);
+    }
+    for (int i = start + 1; i < end; i++) {
+      if (separator != null && separator != "") {
+        buffer.add(separator);
+      }
+      buffer.add("${_f(_list[i])}");
+      if (_list.length != length) {
+        throw new ConcurrentModificationError(_list);
+      }
+    }
+    return buffer.toString();
+  }
+
+  Iterable<T> where(bool test(T element)) => super.where(test);
+
+  Iterable map(f(T element)) {
+    return new MappedListIterable(_list, (S v) => f(_f(v)), _start, _end);
+  }
+
+  Iterable mappedBy(f(T element)) => map(f);
+
+  reduce(var initialValue, combine(var previousValue, T element)) {
+    return _list.reduce(initialValue, (v, S e) => combine(v, _f(e)));
+  }
+
+  Iterable<T> skip(int count) {
+    int start = _startIndex + count;
+    if (_end != null && start >= _end) {
+      return new EmptyIterable<T>();
+    }
+    return new MappedListIterable(_list, _f, start, _end);
+  }
+
+  Iterable<T> skipWhile(bool test(T element)) => super.skipWhile(test);
+
+  Iterable<T> take(int count)  {
+    int newEnd = _start + count;
+    if (_end == null || newEnd < _end)  {
+      return new MappedListIterable(_list, _f, _start, newEnd);
+    }
+    // Equivalent to "this".
+    return new MappedListIterable(_list, _f, _start, _end);
+  }
+
+  Iterable<T> takeWhile(bool test(T element)) => super.takeWhile(test);
+
+  List<T> toList() {
+    List<T> result = new List<T>();
+    forEach(result.add);
+    return result;
+  }
+
+  Set<T> toSet() {
+    Set<T> result = new Set<T>();
+    forEach(result.add);
+    return result;
+  }
+}
+
+/**
+ * Iterator for [MappedListIterable].
+ *
+ * A list iterator that iterates over (a sublist of) a list and
+ * returns the values transformed by a function.
+ *
+ * As a list iterator, it throws if the length of the list has
+ * changed during iteration.
+ */
+class MappedListIterator<S, T> implements Iterator<T> {
+  List<S> _list;
+  // TODO(ahe): Restore type when feature is implemented in dart2js
+  // checked mode. http://dartbug.com/7733
+  final /* _Transformation<S, T> */ _f;
+  final int _endIndex;
+  final int _length;
+  int _index;
+  T _current;
+
+  MappedListIterator(List<S> list, this._f, int start, this._endIndex)
+      : _list = list, _length = list.length, _index = start;
+
+  T get current => _current;
+
+  bool moveNext() {
+    if (_list.length != _length) {
+      throw new ConcurrentModificationError(_list);
+    }
+    if (_index >= _endIndex) {
+      _current = null;
+      return false;
+    }
+    _current = _f(_list[_index]);
+    _index++;
+    return true;
+  }
 }
 
 typedef bool _ElementPredicate<E>(E element);
diff --git a/sdk/lib/_collection_dev/list.dart b/sdk/lib/_collection_dev/list.dart
index 0260290..7af0fbb 100644
--- a/sdk/lib/_collection_dev/list.dart
+++ b/sdk/lib/_collection_dev/list.dart
@@ -101,23 +101,23 @@
     return new MappedList(this, f);
   }
 
-  Iterable<E> take(int n) {
-    return new SubListIterable(this, 0, n);
+  List<E> take(int n) {
+    return new ListView(this, 0, n);
   }
 
-  Iterable<E> skip(int n) {
-    return new SubListIterable(this, n, null);
+  List<E> skip(int n) {
+    return new ListView(this, n, null);
   }
 
-  Iterable<E> get reversed => new ReversedListIterable(this);
-
   String toString() => ToString.collectionToString(this);
+
+  List<E> get reversed {
+    return new ReversedListView(this, 0, null);
+  }
 }
 
 /**
  * Abstract class implementing the non-length changing operations of [List].
- *
- * All modifications are performed using [[]=].
  */
 abstract class FixedLengthListBase<E> extends ListBase<E> {
   void operator[]=(int index, E value);
@@ -286,6 +286,35 @@
   }
 }
 
+/**
+ * Iterates over a [List] in growing index order.
+ */
+class ListIterator<E> implements Iterator<E> {
+  final List<E> _list;
+  final int _length;
+  int _position;
+  E _current;
+
+  ListIterator(List<E> list)
+      : _list = list, _position = -1, _length = list.length;
+
+  bool moveNext() {
+    if (_list.length != _length) {
+      throw new ConcurrentModificationError(_list);
+    }
+    int nextPosition = _position + 1;
+    if (nextPosition < _length) {
+      _position = nextPosition;
+      _current = _list[nextPosition];
+      return true;
+    }
+    _current = null;
+    return false;
+  }
+
+  E get current => _current;
+}
+
 class MappedList<S, T> extends UnmodifiableListBase<T> {
   final List<S> _list;
   // TODO(ahe): Restore type when feature is implemented in dart2js
@@ -303,17 +332,218 @@
   int get length => 0;
   E operator[](int index) { throw new RangeError.value(index); }
   void operator []=(int index, E value) { throw new RangeError.value(index); }
-  Iterable<E> skip(int count) => const EmptyIterable();
-  Iterable<E> take(int count) => const EmptyIterable();
-  Iterable<E> get reversed => const EmptyIterable();
+  List<E> skip(int count) => this;
+  List<E> take(int count) => this;
+  List<E> get reversed => this;
   void sort([int compare(E a, E b)]) {}
 }
 
-class ReversedListIterable<E> extends ListIterable<E> {
-  Iterable<E> _source;
-  ReversedListIterable(this._source);
+/**
+ * A fixed-length view of a sub-range of another [List].
+ *
+ * The range is described by start and end points relative
+ * to the other List's start or end.
+ *
+ * The range changes dynamically as the underlying list changes
+ * its length.
+ */
+abstract class SubListView<E> extends UnmodifiableListBase<E> {
+  final List<E> _list;
+  final int _start;
+  final int _end;
 
-  int get length => _source.length;
+  /**
+   * Create a sub-list view.
+   *
+   * Both [_start] and [_end] can be given as positions
+   * relative to the start of [_list] (a non-negative integer)
+   * or relative to the end of [_list] (a negative integer or
+   * null, with null being at the end of the list).
+   */
+  SubListView(this._list, this._start, this._end);
 
-  E elementAt(int index) => _source.elementAt(_source.length - 1 - index);
+  int _absoluteIndex(int relativeIndex) {
+    if (relativeIndex == null) return _list.length;
+    if (relativeIndex < 0) {
+      int result = _list.length + relativeIndex;
+      if (result < 0) return 0;
+      return result;
+    }
+    if (relativeIndex > _list.length) {
+      return _list.length;
+    }
+    return relativeIndex;
+  }
+
+  int get length {
+    int result = _absoluteIndex(_end) - _absoluteIndex(_start);
+    if (result >= 0) return result;
+    return 0;
+  }
+
+  _createListView(int start, int end) {
+    if (start == null) return new EmptyList<E>();
+    if (end != null) {
+      if (start < 0) {
+        if (end <= start) return new EmptyList<E>();
+      } else {
+        if (end >= 0 && end <= start) return new EmptyList<E>();
+      }
+    }
+    return new ListView(_list, start, end);
+  }
+
+  _createReversedListView(int start, int end) {
+    if (start == null) return new EmptyList<E>();
+    if (end != null) {
+      if (start < 0) {
+        if (end <= start) return new EmptyList<E>();
+      } else {
+        if (end >= 0 && end <= start) return new EmptyList<E>();
+      }
+    }
+    return new ReversedListView(_list, start, end);
+  }
+}
+
+
+/**
+ * A fixed-length view of a sub-range of a [List].
+ */
+class ListView<E> extends SubListView<E> {
+
+  ListView(List<E> list, int start, int end) : super(list, start, end);
+
+  E operator[](int index) {
+    int start = _absoluteIndex(_start);
+    int end = _absoluteIndex(_end);
+    int length = end - start;
+    if (index < 0 || index >= length) {
+      throw new RangeError.range(index, 0, length);
+    }
+    return _list[start + index];
+  }
+
+  List<E> skip(int count) {
+    if (count is! int || count < 0) {
+      throw new ArgumentError(count);
+    }
+    if (_start == null) {
+      return new EmptyList<E>();
+    }
+    int newStart = _start + count;
+    if (_start < 0 && newStart >= 0) {
+      return new EmptyList<E>();
+    }
+    return _createListView(newStart, _end);
+  }
+
+  List<E> take(int count) {
+    if (count is! int || count < 0) {
+      throw new ArgumentError(count);
+    }
+    if (_start == null) {
+      return new EmptyList<E>();
+    }
+    int newEnd = _start + count;
+    if (_start < 0 && newEnd >= 0) {
+      newEnd = null;
+    }
+    return _createListView(_start, newEnd);
+  }
+
+  List<E> get reversed => new ReversedListView(_list, _start, _end);
+}
+
+/**
+ * Reversed view of a [List], or a slice of a list.
+ *
+ * The view is fixed-length and becomes invalid if the underlying
+ * list changes its length below the slice used by this reversed list.
+ *
+ * Start index and end index can be either positive, negative or null.
+ * Positive means an index relative to the start of the list,
+ * negative means an index relative to the end of the list, and null
+ * means at the end of the list (since there is no -0 integer).
+ */
+class ReversedListView<E> extends SubListView<E> {
+
+  ReversedListView(List<E> list, int start, int end)
+      : super(list, start, end);
+
+  E operator[](int index) {
+    int start = _absoluteIndex(_start);
+    int end = _absoluteIndex(_end);
+    int length = end - start;
+    if (index < 0 || index >= length) {
+      throw new RangeError.range(index, 0, length);
+    }
+    return _list[end - index - 1];
+  }
+
+  List<E> skip(int count) {
+    if (count is! int || count < 0) {
+      throw new ArgumentError(count);
+    }
+    if (_end == null) {
+      return _createReversedListView(_start, -count);
+    }
+    int newEnd = _end - count;
+    if (_end >= 0 && newEnd < 0) {
+      return new EmptyList<E>();
+    }
+    return _createReversedListView(_start, newEnd);
+  }
+
+  List<E> take(int count) {
+    if (count is! int || count < 0) {
+      throw new ArgumentError(count);
+    }
+    int newStart;
+    if (_end == null) {
+      newStart = -count;
+    } else {
+      newStart = _end - count;
+      if (_end >= 0 && newStart < 0) {
+        return new EmptyList<E>();
+      }
+    }
+    return _createReversedListView(newStart, _end);
+  }
+
+  Iterator<E> get iterator => new ReverseListIterator<E>(
+      _list, _absoluteIndex(_start), _absoluteIndex(_end));
+
+  List<E> get reversed {
+    return new ListView(_list, _start, _end);
+  }
+}
+
+/**
+ * An [Iterator] over a slice of a list that access elements in reverse order.
+ */
+class ReverseListIterator<E> implements Iterator<E> {
+  final List<E> _list;
+  final int _start;
+  final int _originalLength;
+  int _index;
+  E _current;
+
+  ReverseListIterator(List<E> list, int start, int end)
+      : _list = list,
+        _start = start,
+        _index = end,
+        _originalLength = list.length;
+
+  bool moveNext() {
+    if (_list.length != _originalLength) {
+      throw new ConcurrentModificationError(_list);
+    }
+    if (_index <= _start) return false;
+    _index -= 1;
+    _current = _list[_index];
+    return true;
+  }
+
+  E get current => _current;
 }
diff --git a/sdk/lib/_internal/compiler/implementation/js/nodes.dart b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
index 54af9c5..da8cd44 100644
--- a/sdk/lib/_internal/compiler/implementation/js/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
@@ -151,10 +151,6 @@
   void visitChildren(NodeVisitor visitor);
 
   VariableUse asVariableUse() => null;
-
-  Statement toStatement() {
-    throw new UnsupportedError('toStatement');
-  }
 }
 
 class Program extends Node {
@@ -168,7 +164,6 @@
 }
 
 abstract class Statement extends Node {
-  Statement toStatement() => this;
 }
 
 class Block extends Statement {
@@ -437,71 +432,8 @@
 abstract class Expression extends Node {
   int get precedenceLevel;
 
+  PropertyAccess dot(String name) => new PropertyAccess.field(this, name);
   Call callWith(List<Expression> arguments) => new Call(this, arguments);
-
-  New newWith(List<Expression> arguments) => new New(this, arguments);
-
-  PropertyAccess operator [](expression) {
-    if (expression is Expression) {
-      return new PropertyAccess(this, expression);
-    } else if (expression is int) {
-      return new PropertyAccess.indexed(this, expression);
-    } else if (expression is String) {
-      return new PropertyAccess.field(this, expression);
-    } else {
-      throw new ArgumentError('Expected an int, String, or Expression');
-    }
-  }
-
-  Statement toStatement() => new ExpressionStatement(this);
-
-  Call call([expression]) {
-    List<Expression> arguments;
-    if (expression == null) {
-      arguments = <Expression>[];
-    } else if (expression is List) {
-      arguments = expression.map(js.toExpression).toList();
-    } else {
-      arguments = <Expression>[js.toExpression(expression)];
-    }
-    return callWith(arguments);
-  }
-
-  Expression equals(expression) => binary('==', expression);
-
-  Expression strictEquals(expression) => binary('===', expression);
-
-  Expression notEquals(expression) => binary('!=', expression);
-
-  Expression operator +(expression) => binary('+', expression);
-
-  Expression operator -(expression) => binary('-', expression);
-
-  Expression operator &(expression) => binary('&', expression);
-
-  Expression operator <(expression) => binary('<', expression);
-
-  Expression operator >(expression) => binary('>', expression);
-
-  Expression operator >=(expression) => binary('>=', expression);
-
-  Expression binary(String operator, expression) {
-    return new Binary(operator, this, js.toExpression(expression));
-  }
-
-  Expression assign(expression) {
-    return new Assignment(this, js.toExpression(expression));
-  }
-
-  Expression update(String operator, expression) {
-    return new Assignment.compound(this, operator, js.toExpression(expression));
-  }
-
-  Expression get plusPlus => new Postfix('++', this);
-
-  Prefix get typeof => new Prefix('typeof', this);
-
-  Prefix get not => new Prefix('!', this);
 }
 
 class LiteralExpression extends Expression {
@@ -729,8 +661,6 @@
   accept(NodeVisitor visitor) => visitor.visitVariableUse(this);
 
   VariableUse asVariableUse() => this;
-
-  VariableDeclarationList def([initializer]) => js.defineVar(name, initializer);
 }
 
 class VariableDeclaration extends VariableReference {
@@ -929,124 +859,48 @@
   int get precedenceLevel => PRIMARY;
 }
 
-class JsBuilder {
-  const JsBuilder();
+Prefix typeOf(Expression argument) => new Prefix('typeof', argument);
 
-  VariableUse operator [](String name) => new VariableUse(name);
-
-  // TODO(ahe): Remove this method.
-  Binary equals(Expression left, Expression right) {
-    return new Binary('==', left, right);
-  }
-
-  // TODO(ahe): Remove this method.
-  Binary strictEquals(Expression left, Expression right) {
-    return new Binary('===', left, right);
-  }
-
-  LiteralString string(String value) => new LiteralString('"$value"');
-
-  If if_(condition, thenPart, [elsePart]) {
-    condition = toExpression(condition);
-    return (elsePart == null)
-        ? new If.noElse(condition, toStatement(thenPart))
-        : new If(condition, toStatement(thenPart), toStatement(elsePart));
-  }
-
-  Return return_([value]) {
-    return new Return(value == null ? null : toExpression(value));
-  }
-
-  Block block(statement) {
-    if (statement is Block) {
-      return statement;
-    } else if (statement is List) {
-      return new Block(statement.map(toStatement).toList());
-    } else {
-      return new Block(<Statement>[toStatement(statement)]);
-    }
-  }
-
-  Fun fun(parameters, body) {
-    Parameter toParameter(parameter) {
-      if (parameter is String) {
-        return new Parameter(parameter);
-      } else if (parameter is Parameter) {
-        return parameter;
-      } else {
-        throw new ArgumentError('parameter should be a String or a Parameter');
-      }
-    }
-    if (parameters is! List) {
-      parameters = [parameters];
-    }
-    return new Fun(parameters.map(toParameter).toList(), block(body));
-  }
-
-  Assignment assign(Expression leftHandSide, Expression value) {
-    return new Assignment(leftHandSide, value);
-  }
-
-  Expression undefined() => new Prefix('void', new LiteralNumber('0'));
-
-  VariableDeclarationList defineVar(String name, [initializer]) {
-    if (initializer != null) {
-      initializer = toExpression(initializer);
-    }
-    var declaration = new VariableDeclaration(name);
-    var initialization = [new VariableInitialization(declaration, initializer)];
-    return new VariableDeclarationList(initialization);
-  }
-
-  Statement toStatement(statement) {
-    if (statement is List) {
-      return new Block(statement.map(toStatement).toList());
-    } else if (statement is Node) {
-      return statement.toStatement();
-    } else {
-      throw new ArgumentError('statement');
-    }
-  }
-
-  Expression toExpression(expression) {
-    if (expression is Expression) {
-      return expression;
-    } else if (expression is String) {
-      return this[expression];
-    } else if (expression is num) {
-      return new LiteralNumber('$expression');
-    } else if (expression is bool) {
-      return new LiteralBool(expression);
-    } else if (expression is Map) {
-      if (!expression.isEmpty) {
-        throw new ArgumentError('expression should be an empty Map');
-      }
-      return new ObjectInitializer([]);
-    } else {
-      throw new ArgumentError('expression should be an Expression, '
-                              'a String, a num, a bool, or a Map');
-    }
-  }
-
-  ForIn forIn(String name, object, statement) {
-    return new ForIn(defineVar(name),
-                     toExpression(object),
-                     toStatement(statement));
-  }
-
-  For for_(init, condition, update, statement) {
-    return new For(
-        toExpression(init), toExpression(condition), toExpression(update),
-        toStatement(statement));
-  }
-
-  Try try_(body, {catchPart, finallyPart}) {
-    if (catchPart != null) catchPart = toStatement(catchPart);
-    if (finallyPart != null) finallyPart = toStatement(finallyPart);
-    return new Try(toStatement(body), catchPart, finallyPart);
-  }
+Binary equals(Expression left, Expression right) {
+  return new Binary('==', left, right);
 }
 
-const JsBuilder js = const JsBuilder();
+Binary strictEquals(Expression left, Expression right) {
+  return new Binary('===', left, right);
+}
 
-LiteralString string(String value) => js.string(value);
+LiteralString string(String value) => new LiteralString('"$value"');
+
+If if_(Expression condition, Node then, [Node otherwise]) {
+  return (otherwise == null)
+      ? new If.noElse(condition, then)
+      : new If(condition, then, otherwise);
+}
+
+Return return_([Expression value]) => new Return(value);
+
+VariableUse use(String name) => new VariableUse(name);
+
+PropertyAccess fieldAccess(Expression receiver, String fieldName) {
+  return new PropertyAccess.field(receiver, fieldName);
+}
+
+Block emptyBlock() => new Block.empty();
+
+Block block1(Statement statement) => new Block(<Statement>[statement]);
+
+Block block2(Statement s1, Statement s2) => new Block(<Statement>[s1, s2]);
+
+Call call(Expression target, List<Expression> arguments) {
+  return new Call(target, arguments);
+}
+
+Fun fun(List<String> parameterNames, Block body) {
+  return new Fun(parameterNames.map((n) => new Parameter(n)).toList(), body);
+}
+
+Assignment assign(Expression leftHandSide, Expression value) {
+  return new Assignment(leftHandSide, value);
+}
+
+Expression undefined() => new Prefix('void', new LiteralNumber('0'));
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 4c51bc2..e0ba156 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -624,15 +624,15 @@
   /**
    * The generated code as a js AST for compiled methods. 
    */
-  Map<Element, jsAst.Expression> get generatedCode {
+  Map<Element, js.Expression> get generatedCode {
     return compiler.enqueuer.codegen.generatedCode;
   }
 
   /**
    * The generated code as a js AST for compiled bailout methods. 
    */
-  final Map<Element, jsAst.Expression> generatedBailoutCode =
-      new Map<Element, jsAst.Expression>();
+  final Map<Element, js.Expression> generatedBailoutCode =
+      new Map<Element, js.Expression>();
 
   ClassElement jsStringClass;
   ClassElement jsArrayClass;
@@ -959,12 +959,12 @@
     optimizer.optimize(work, graph, false);
     if (work.allowSpeculativeOptimization
         && optimizer.trySpeculativeOptimizations(work, graph)) {
-      jsAst.Expression code = generator.generateBailoutMethod(work, graph);
+      js.Expression code = generator.generateBailoutMethod(work, graph);
       generatedBailoutCode[element] = code;
       optimizer.prepareForSpeculativeOptimizations(work, graph);
       optimizer.optimize(work, graph, true);
     }
-    jsAst.Expression code = generator.generateCode(work, graph);
+    js.Expression code = generator.generateCode(work, graph);
     generatedCode[element] = code;
     invalidateAfterCodegen.forEach(eagerRecompile);
     invalidateAfterCodegen.clear();
@@ -985,7 +985,7 @@
    */
   String assembleCode(Element element) {
     assert(invariant(element, element.isDeclaration));
-    return jsAst.prettyPrint(generatedCode[element], compiler).getText();
+    return js.prettyPrint(generatedCode[element], compiler).getText();
   }
 
   void assembleProgram() {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
index 896044d..86717ae 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
@@ -19,7 +19,7 @@
    * canonical name unless the constant can be emitted multiple times (as for
    * numbers and strings).
    */
-  jsAst.Expression reference(Constant constant) {
+  js.Expression reference(Constant constant) {
     return _referenceEmitter.generate(constant);
   }
 
@@ -27,14 +27,14 @@
    * Constructs an expression like [reference], but the expression is valid
    * during isolate initialization.
    */
-  jsAst.Expression referenceInInitializationContext(Constant constant) {
+  js.Expression referenceInInitializationContext(Constant constant) {
     return _referenceEmitter.generateInInitializationContext(constant);
   }
 
   /**
    * Constructs an expression used to initialize a canonicalized constant.
    */
-  jsAst.Expression initializationExpression(Constant constant) {
+  js.Expression initializationExpression(Constant constant) {
     return _initializerEmitter.generate(constant);
   }
 }
@@ -43,74 +43,74 @@
  * Visitor for generating JavaScript expressions to refer to [Constant]s.
  * Do not use directly, use methods from [ConstantEmitter].
  */
-class ConstantReferenceEmitter implements ConstantVisitor<jsAst.Expression> {
+class ConstantReferenceEmitter implements ConstantVisitor<js.Expression> {
   final Compiler compiler;
   final Namer namer;
   bool inIsolateInitializationContext = false;
 
   ConstantReferenceEmitter(this.compiler, this.namer);
 
-  jsAst.Expression generate(Constant constant) {
+  js.Expression generate(Constant constant) {
     inIsolateInitializationContext = false;
     return _visit(constant);
   }
 
-  jsAst.Expression generateInInitializationContext(Constant constant) {
+  js.Expression generateInInitializationContext(Constant constant) {
     inIsolateInitializationContext = true;
     return _visit(constant);
   }
 
-  jsAst.Expression _visit(Constant constant) {
+  js.Expression _visit(Constant constant) {
     return constant.accept(this);
   }
 
-  jsAst.Expression visitSentinel(SentinelConstant constant) {
-    return new jsAst.VariableUse(namer.CURRENT_ISOLATE);
+  js.Expression visitSentinel(SentinelConstant constant) {
+    return new js.VariableUse(namer.CURRENT_ISOLATE);
   }
 
-  jsAst.Expression visitFunction(FunctionConstant constant) {
+  js.Expression visitFunction(FunctionConstant constant) {
     return inIsolateInitializationContext
-        ? new jsAst.VariableUse(namer.isolatePropertiesAccess(constant.element))
-        : new jsAst.VariableUse(namer.isolateAccess(constant.element));
+        ? new js.VariableUse(namer.isolatePropertiesAccess(constant.element))
+        : new js.VariableUse(namer.isolateAccess(constant.element));
   }
 
-  jsAst.Expression visitNull(NullConstant constant) {
-    return new jsAst.LiteralNull();
+  js.Expression visitNull(NullConstant constant) {
+    return new js.LiteralNull();
   }
 
-  jsAst.Expression visitInt(IntConstant constant) {
-    return new jsAst.LiteralNumber('${constant.value}');
+  js.Expression visitInt(IntConstant constant) {
+    return new js.LiteralNumber('${constant.value}');
   }
 
-  jsAst.Expression visitDouble(DoubleConstant constant) {
+  js.Expression visitDouble(DoubleConstant constant) {
     double value = constant.value;
     if (value.isNaN) {
-      return new jsAst.LiteralNumber("(0/0)");
+      return new js.LiteralNumber("(0/0)");
     } else if (value == double.INFINITY) {
-      return new jsAst.LiteralNumber("(1/0)");
+      return new js.LiteralNumber("(1/0)");
     } else if (value == -double.INFINITY) {
-      return new jsAst.LiteralNumber("(-1/0)");
+      return new js.LiteralNumber("(-1/0)");
     } else {
-      return new jsAst.LiteralNumber("$value");
+      return new js.LiteralNumber("$value");
     }
   }
 
-  jsAst.Expression visitTrue(TrueConstant constant) {
+  js.Expression visitTrue(TrueConstant constant) {
     if (compiler.enableMinification) {
       // Use !0 for true.
-      return new jsAst.Prefix("!", new jsAst.LiteralNumber("0"));
+      return new js.Prefix("!", new js.LiteralNumber("0"));
     } else {
-      return new jsAst.LiteralBool(true);
+      return new js.LiteralBool(true);
     }
 
   }
 
-  jsAst.Expression visitFalse(FalseConstant constant) {
+  js.Expression visitFalse(FalseConstant constant) {
     if (compiler.enableMinification) {
       // Use !1 for false.
-      return new jsAst.Prefix("!", new jsAst.LiteralNumber("1"));
+      return new js.Prefix("!", new js.LiteralNumber("1"));
     } else {
-      return new jsAst.LiteralBool(false);
+      return new js.LiteralBool(false);
     }
   }
 
@@ -119,44 +119,44 @@
    * a form that is valid as JavaScript string literal content.
    * The string is assumed quoted by double quote characters.
    */
-  jsAst.Expression visitString(StringConstant constant) {
+  js.Expression visitString(StringConstant constant) {
     // TODO(sra): If the string is long *and repeated* (and not on a hot path)
     // then it should be assigned to a name.  We don't have reference counts (or
     // profile information) here, so this is the wrong place.
     StringBuffer sb = new StringBuffer();
     writeJsonEscapedCharsOn(constant.value.slowToString(), sb);
-    return new jsAst.LiteralString('"$sb"');
+    return new js.LiteralString('"$sb"');
   }
 
-  jsAst.Expression emitCanonicalVersion(Constant constant) {
+  js.Expression emitCanonicalVersion(Constant constant) {
     String name = namer.constantName(constant);
     if (inIsolateInitializationContext) {
       //  $isolateName.$isolatePropertiesName.$name
-      return new jsAst.PropertyAccess.field(
-          new jsAst.PropertyAccess.field(
-              new jsAst.VariableUse(namer.isolateName),
+      return new js.PropertyAccess.field(
+          new js.PropertyAccess.field(
+              new js.VariableUse(namer.isolateName),
               namer.isolatePropertiesName),
           name);
     } else {
-      return new jsAst.PropertyAccess.field(
-          new jsAst.VariableUse(namer.CURRENT_ISOLATE),
+      return new js.PropertyAccess.field(
+          new js.VariableUse(namer.CURRENT_ISOLATE),
           name);
     }
   }
 
-  jsAst.Expression visitList(ListConstant constant) {
+  js.Expression visitList(ListConstant constant) {
     return emitCanonicalVersion(constant);
   }
 
-  jsAst.Expression visitMap(MapConstant constant) {
+  js.Expression visitMap(MapConstant constant) {
     return emitCanonicalVersion(constant);
   }
 
-  jsAst.Expression visitType(TypeConstant constant) {
+  js.Expression visitType(TypeConstant constant) {
     return emitCanonicalVersion(constant);
   }
 
-  jsAst.Expression visitConstructed(ConstructedConstant constant) {
+  js.Expression visitConstructed(ConstructedConstant constant) {
     return emitCanonicalVersion(constant);
   }
 }
@@ -165,90 +165,90 @@
  * Visitor for generating JavaScript expressions to initialize [Constant]s.
  * Do not use directly; use methods from [ConstantEmitter].
  */
-class ConstantInitializerEmitter implements ConstantVisitor<jsAst.Expression> {
+class ConstantInitializerEmitter implements ConstantVisitor<js.Expression> {
   final Compiler compiler;
   final Namer namer;
   final ConstantReferenceEmitter referenceEmitter;
 
   ConstantInitializerEmitter(this.compiler, this.namer, this.referenceEmitter);
 
-  jsAst.Expression generate(Constant constant) {
+  js.Expression generate(Constant constant) {
     return _visit(constant);
   }
 
-  jsAst.Expression _visit(Constant constant) {
+  js.Expression _visit(Constant constant) {
     return constant.accept(this);
   }
 
-  jsAst.Expression _reference(Constant constant) {
+  js.Expression _reference(Constant constant) {
     return referenceEmitter.generateInInitializationContext(constant);
   }
 
-  jsAst.Expression visitSentinel(SentinelConstant constant) {
+  js.Expression visitSentinel(SentinelConstant constant) {
     compiler.internalError(
         "The parameter sentinel constant does not need specific JS code");
   }
 
-  jsAst.Expression visitFunction(FunctionConstant constant) {
+  js.Expression visitFunction(FunctionConstant constant) {
     compiler.internalError(
         "The function constant does not need specific JS code");
   }
 
-  jsAst.Expression visitNull(NullConstant constant) {
+  js.Expression visitNull(NullConstant constant) {
     return _reference(constant);
   }
 
-  jsAst.Expression visitInt(IntConstant constant) {
+  js.Expression visitInt(IntConstant constant) {
     return _reference(constant);
   }
 
-  jsAst.Expression visitDouble(DoubleConstant constant) {
+  js.Expression visitDouble(DoubleConstant constant) {
     return _reference(constant);
   }
 
-  jsAst.Expression visitTrue(TrueConstant constant) {
+  js.Expression visitTrue(TrueConstant constant) {
     return _reference(constant);
   }
 
-  jsAst.Expression visitFalse(FalseConstant constant) {
+  js.Expression visitFalse(FalseConstant constant) {
     return _reference(constant);
   }
 
-  jsAst.Expression visitString(StringConstant constant) {
+  js.Expression visitString(StringConstant constant) {
     // TODO(sra): Some larger strings are worth sharing.
     return _reference(constant);
   }
 
-  jsAst.Expression visitList(ListConstant constant) {
-    return new jsAst.Call(
-        new jsAst.PropertyAccess.field(
-            new jsAst.VariableUse(namer.isolateName),
+  js.Expression visitList(ListConstant constant) {
+    return new js.Call(
+        new js.PropertyAccess.field(
+            new js.VariableUse(namer.isolateName),
             'makeConstantList'),
-        [new jsAst.ArrayInitializer.from(_array(constant.entries))]);
+        [new js.ArrayInitializer.from(_array(constant.entries))]);
   }
 
   String getJsConstructor(ClassElement element) {
     return namer.isolatePropertiesAccess(element);
   }
 
-  jsAst.Expression visitMap(MapConstant constant) {
-    jsAst.Expression jsMap() {
-      List<jsAst.Property> properties = <jsAst.Property>[];
+  js.Expression visitMap(MapConstant constant) {
+    js.Expression jsMap() {
+      List<js.Property> properties = <js.Property>[];
       int valueIndex = 0;
       for (int i = 0; i < constant.keys.entries.length; i++) {
         StringConstant key = constant.keys.entries[i];
         if (key.value == MapConstant.PROTO_PROPERTY) continue;
 
         // Keys in literal maps must be emitted in place.
-        jsAst.Literal keyExpression = _visit(key);
-        jsAst.Expression valueExpression =
+        js.Literal keyExpression = _visit(key);
+        js.Expression valueExpression =
             _reference(constant.values[valueIndex++]);
-        properties.add(new jsAst.Property(keyExpression, valueExpression));
+        properties.add(new js.Property(keyExpression, valueExpression));
       }
       if (valueIndex != constant.values.length) {
         compiler.internalError("Bad value count.");
       }
-      return new jsAst.ObjectInitializer(properties);
+      return new js.ObjectInitializer(properties);
     }
 
     void badFieldCountError() {
@@ -258,7 +258,7 @@
 
     ClassElement classElement = constant.type.element;
 
-    List<jsAst.Expression> arguments = <jsAst.Expression>[];
+    List<js.Expression> arguments = <js.Expression>[];
 
     // The arguments of the JavaScript constructor for any given Dart class
     // are in the same order as the members of the class element.
@@ -267,7 +267,7 @@
         (ClassElement enclosing, Element field) {
           if (field.name == MapConstant.LENGTH_NAME) {
             arguments.add(
-                new jsAst.LiteralNumber('${constant.keys.entries.length}'));
+                new js.LiteralNumber('${constant.keys.entries.length}'));
           } else if (field.name == MapConstant.JS_OBJECT_NAME) {
             arguments.add(jsMap());
           } else if (field.name == MapConstant.KEYS_NAME) {
@@ -288,12 +288,12 @@
       badFieldCountError();
     }
 
-    return new jsAst.New(
-        new jsAst.VariableUse(getJsConstructor(classElement)),
+    return new js.New(
+        new js.VariableUse(getJsConstructor(classElement)),
         arguments);
   }
 
-  jsAst.Expression visitType(TypeConstant constant) {
+  js.Expression visitType(TypeConstant constant) {
     SourceString helperSourceName = const SourceString('createRuntimeType');
     Element helper = compiler.findHelper(helperSourceName);
     JavaScriptBackend backend = compiler.backend;
@@ -301,22 +301,22 @@
     DartType type = constant.representedType;
     Element element = type.element;
     String name = backend.rti.getRawTypeRepresentation(type);
-    jsAst.Expression typeName = new jsAst.LiteralString("'$name'");
-    return new jsAst.Call(
-        new jsAst.PropertyAccess.field(
-            new jsAst.VariableUse(namer.CURRENT_ISOLATE),
+    js.Expression typeName = new js.LiteralString("'$name'");
+    return new js.Call(
+        new js.PropertyAccess.field(
+            new js.VariableUse(namer.CURRENT_ISOLATE),
             helperName),
         [typeName]);
   }
 
-  jsAst.Expression visitConstructed(ConstructedConstant constant) {
-    return new jsAst.New(
-        new jsAst.VariableUse(getJsConstructor(constant.type.element)),
+  js.Expression visitConstructed(ConstructedConstant constant) {
+    return new js.New(
+        new js.VariableUse(getJsConstructor(constant.type.element)),
         _array(constant.fields));
   }
 
-  List<jsAst.Expression> _array(List<Constant> values) {
-    List<jsAst.Expression> valueList = <jsAst.Expression>[];
+  List<js.Expression> _array(List<Constant> values) {
+    List<js.Expression> valueList = <js.Expression>[];
     for (int i = 0; i < values.length; i++) {
       valueList.add(_reference(values[i]));
     }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index c91a3c3..b238df6 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -27,22 +27,20 @@
 /**
  * A convenient type alias for some functions that emit keyed values.
  */
-typedef void DefineStubFunction(String invocationName, jsAst.Expression value);
+typedef void DefineStubFunction(String invocationName, js.Expression value);
 
 /**
  * A data structure for collecting fragments of a class definition.
  */
 class ClassBuilder {
-  final List<jsAst.Property> properties = <jsAst.Property>[];
+  final List<js.Property> properties = <js.Property>[];
 
   // Has the same signature as [DefineStubFunction].
-  void addProperty(String name, jsAst.Expression value) {
-    properties.add(new jsAst.Property(js.string(name), value));
+  void addProperty(String name, js.Expression value) {
+    properties.add(new js.Property(js.string(name), value));
   }
 
-  jsAst.Expression toObjectInitializer() {
-    return new jsAst.ObjectInitializer(properties);
-  }
+  js.Expression toObjectInitializer() => new js.ObjectInitializer(properties);
 }
 
 /**
@@ -128,11 +126,11 @@
     });
   }
 
-  jsAst.Expression constantReference(Constant value) {
+  js.Expression constantReference(Constant value) {
     return constantEmitter.reference(value);
   }
 
-  jsAst.Expression constantInitializerExpression(Constant value) {
+  js.Expression constantInitializerExpression(Constant value) {
     return constantEmitter.initializationExpression(value);
   }
 
@@ -174,100 +172,42 @@
   const GETTER_SETTER_CODE = 0x3d;
   const GETTER_CODE = 0x3e;
   const RENAMING_FLAG = 0x40;
+  String needsGetterCode(String variable) => '($variable & 3) > 0';
+  String needsSetterCode(String variable) => '($variable & 2) == 0';
+  String isRenaming(String variable) => '($variable & $RENAMING_FLAG) != 0';
 
-  jsAst.Expression needsGetterCode(String variable) {
-    // ($variable & 3) > 0
-    return (js[variable] & 3) > 0;
+  String get generateAccessorFunction {
+    return """
+function generateAccessor(field, prototype) {
+  var len = field.length;
+  var lastCharCode = field.charCodeAt(len - 1);
+  var needsAccessor = (lastCharCode & $SUFFIX_MASK) >= $FIRST_SUFFIX_CODE;
+  if (needsAccessor) {
+    var needsGetter = ${needsGetterCode('lastCharCode')};
+    var needsSetter = ${needsSetterCode('lastCharCode')};
+    var renaming = ${isRenaming('lastCharCode')};
+    var accessorName = field = field.substring(0, len - 1);
+    if (renaming) {
+      var divider = field.indexOf(":");
+      accessorName = field.substring(0, divider);
+      field = field.substring(divider + 1);
+    }
+    if (needsGetter) {
+      var getterString = "return this." + field + ";";
+      prototype["${namer.getterPrefix}" + accessorName] =
+          new Function(getterString);
+    }
+    if (needsSetter) {
+      var setterString = "this." + field + " = v;";
+      prototype["${namer.setterPrefix}" + accessorName] =
+          new Function("v", setterString);
+    }
+  }
+  return field;
+}""";
   }
 
-  jsAst.Expression needsSetterCode(String variable) {
-    // ($variable & 2) == 0
-    return (js[variable] & 2).equals(0);
-  }
-
-  jsAst.Expression isRenaming(String variable) {
-    // ($variable & $RENAMING_FLAG) != 0
-    return (js[variable] & RENAMING_FLAG).notEquals(0);
-  }
-
-  jsAst.FunctionDeclaration get generateAccessorFunction {
-    // function generateAccessor(field, prototype) {
-    jsAst.Fun fun = js.fun(['field', 'prototype'], [
-
-      // var len = field.length;
-      js['len'].def(js['field']['length']),
-
-      // var lastCharCode = field.charCodeAt(len - 1);
-      js['lastCharCode'].def(js['field']['charCodeAt'](js['len'] - 1)),
-
-      // var needsAccessor =
-      //     (lastCharCode & $SUFFIX_MASK) >= $FIRST_SUFFIX_CODE;
-      js['needsAccessor'].def(
-          (js['lastCharCode'] & SUFFIX_MASK) >= FIRST_SUFFIX_CODE),
-
-      // if (needsAccessor) {
-      js.if_('needsAccessor', [
-        // var needsGetter = ${needsGetterCode('lastCharCode')};
-        js['needsGetter'].def(needsGetterCode('lastCharCode')),
-
-        // var needsSetter = ${needsSetterCode('lastCharCode')};
-        js['needsSetter'].def(needsSetterCode('lastCharCode')),
-
-        // var renaming = ${isRenaming('lastCharCode')};
-        js['renaming'].def(isRenaming('lastCharCode')),
-
-        // var accessorName = field = field.substring(0, len - 1);
-        js['accessorName'].def(
-            js['field'].assign(js['field']['substring']([0, js['len'] - 1]))),
-
-        // if (renaming) {
-        js.if_('renaming', [
-          // var divider = field.indexOf(":");
-          js['divider'].def(js['field']['indexOf'](js.string(':'))),
-
-          // accessorName = field.substring(0, divider);
-          js['accessorName'].assign(js['field']['substring']([0, 'divider'])),
-
-          // field = field.substring(divider + 1);
-          js['field'].assign(js['field']['substring'](js['divider'] + 1))
-        ]),
-
-        // if (needsGetter) {
-        js.if_('needsGetter', [
-          // var getterString = "return this." + field + ";";
-          js['getterString'].def(js.string('return this.') + 'field'),
-
-          // prototype["${namer.getterPrefix}" + accessorName] =
-          //     new Function(getterString);
-          js['prototype'][js.string(namer.getterPrefix) + 'accessorName']
-              .assign(js['Function'].newWith([js['getterString']]))
-        ]),
-
-        // if (needsSetter) {
-        js.if_('needsSetter', [
-          // var setterString = "this." + field + " = v;";
-          js['setterString'].def(
-              js.string('this.') + 'field' + js.string('$_=${_}v')),
-
-          // prototype["${namer.setterPrefix}" + accessorName] =
-          //     new Function("v", setterString);
-          js['prototype'][js.string(namer.setterPrefix) + 'accessorName']
-              .assign(js['Function'].newWith([js.string('v'),
-                                              js['setterString']]))
-        ]),
-
-      ]),
-
-      // return field;
-      js.return_('field')
-    ]);
-
-    return new jsAst.FunctionDeclaration(
-        new jsAst.VariableDeclaration('generateAccessor'),
-        fun);
-  }
-
-  jsAst.Fun get defineClassFunction {
+  String get defineClassFunction {
     // First the class name, then the field names in an array and the members
     // (inside an Object literal).
     // The caller can also pass in the constructor as a function if needed.
@@ -281,68 +221,33 @@
     //   this.x = t - v;
     //  },
     // });
-
-    // function(cls, fields, prototype) {
-    return js.fun(['cls', 'fields', 'prototype'], [
-
-      // var constructor;
-      js['constructor'].def(),
-
-      // if (typeof fields == 'function') {
-      js.if_(js['fields'].typeof.equals(js.string('function')), [
-        // constructor = fields;
-        js['constructor'].assign('fields')
-      ], /* else */ [
-        // var str = "function " + cls + "(";
-        js['str'].def(js.string('function ') + 'cls' + js.string('(')),
-
-        // var body = "";
-        js['body'].def(js.string('')),
-
-        // for (var i = 0; i < fields.length; i++) {
-        js.for_(js['i'].def(0),
-                js['i'] < js['fields']['length'],
-                js['i'].plusPlus, [
-          // if (i != 0) str += ", ";
-          js.if_(js['i'].notEquals(0), js['str'].update('+', js.string(', '))),
-
-          // var field = fields[i];
-          js['field'].def(js['fields'][js['i']]),
-
-          // field = generateAccessor(field, prototype);
-          js['field'].assign(js['generateAccessor'](['field', 'prototype'])),
-
-          // str += field;
-          js['str'].update('+', 'field'),
-
-          // body += "this." + field + " = " + field + ";\\n";
-          js['body'].update('+',
-                            js.string('this.') + 'field' + js.string(" = ") +
-                            'field' + js.string(r';\n'))
-        ]),
-
-        // str += ") {" + body + "}\\nreturn " + cls;
-        js['str'].update(
-            '+',
-            js.string(') {') + 'body' + js.string(r'}\nreturn ') + 'cls'),
-
-        // constructor = new Function(str)();
-        js['constructor'].assign(js['Function'].newWith([js['str']])())
-      ]),
-
-      // constructor.prototype = prototype;
-      js['constructor']['prototype'].assign('prototype'),
-
-      // constructor.builtin\$cls = cls;
-      js['constructor'][r'builtin$cls'].assign('cls'),
-
-      // return constructor;
-      js.return_('constructor')
-    ]);
+    return """
+function(cls, fields, prototype) {
+  var constructor;
+  if (typeof fields == 'function') {
+    constructor = fields;
+  } else {
+    var str = "function " + cls + "(";
+    var body = "";
+    for (var i = 0; i < fields.length; i++) {
+      if (i != 0) str += ", ";
+      var field = fields[i];
+      field = generateAccessor(field, prototype);
+      str += field;
+      body += "this." + field + " = " + field + ";\\n";
+    }
+    str += ") {" + body + "}\\n";
+    str += "return " + cls + ";";
+    constructor = new Function(str)();
+  }
+  constructor.prototype = prototype;
+  constructor.builtin\$cls = cls;
+  return constructor;
+}""";
   }
 
   /** Needs defineClass to be defined. */
-  List buildProtoSupportCheck() {
+  String get protoSupportCheck {
     // On Firefox and Webkit browsers we can manipulate the __proto__
     // directly. Opera claims to have __proto__ support, but it is buggy.
     // So we have to do more checks.
@@ -351,33 +256,18 @@
     // If the browser does not support __proto__ we need to instantiate an
     // object with the correct (internal) prototype set up correctly, and then
     // copy the members.
-    // TODO(8541): Remove this work around.
 
-    return [
-      // var $supportsProtoName = false;
-      js[supportsProtoName].def(false),
-
-      // var tmp = $defineClassName('c', ['f?'], {}).prototype;
-      js['tmp'].def(
-          js[defineClassName](
-              [js.string('c'),
-               new jsAst.ArrayInitializer.from([js.string('f?')]),
-               {}])['prototype']),
-
-      // if (tmp.__proto__) {
-      js.if_(js['tmp']['__proto__'], [
-        // tmp.__proto__ = {};
-        js['tmp']['__proto__'].assign({}),
-
-        // if (typeof tmp.get\$f != 'undefined') $supportsProtoName = true;
-        js.if_(js['tmp'][r'get$f'].typeof.notEquals(js.string('undefined')),
-               js[supportsProtoName].assign(true))
-
-      ])
-    ];
+    return '''
+var $supportsProtoName = false;
+var tmp = $defineClassName('c', ['f?'], {}).prototype;
+if (tmp.__proto__) {
+  tmp.__proto__ = {};
+  if (typeof tmp.get\$f !== 'undefined') $supportsProtoName = true;
+}
+''';
   }
 
-  jsAst.Fun get finishClassesFunction {
+  String get finishClassesFunction {
     // 'defineClass' does not require the classes to be constructed in order.
     // Classes are initially just stored in the 'pendingClasses' field.
     // 'finishClasses' takes all pending classes and sets up the prototype.
@@ -390,171 +280,67 @@
     // For engines where we have access to the '__proto__' we can manipulate
     // the object literal directly. For other engines we have to create a new
     // object and copy over the members.
-
-    // function(collectedClasses) {
-    return js.fun(['collectedClasses'], [
-
-      // var hasOwnProperty = Object.prototype.hasOwnProperty;
-      js['hasOwnProperty'].def(js['Object']['prototype']['hasOwnProperty']),
-
-      // for (var cls in collectedClasses) {
-      js.forIn('cls', 'collectedClasses', [
-        // if (hasOwnProperty.call(collectedClasses, cls)) {
-        js.if_(js['hasOwnProperty']['call'](['collectedClasses', 'cls']),[
-
-          // var desc = collectedClasses[cls];
-          js['desc'].def(js['collectedClasses'][js['cls']]),
-
-          /* The 'fields' are either a constructor function or a
-           * string encoding fields, constructor and superclass.  Get
-           * the superclass and the fields in the format
-           * Super;field1,field2 from the null-string property on the
-           * descriptor.
-           */
-          // var fields = desc[''], supr;
-          (() {
-            var fields = js['desc'][''];
-            var supr = js['supr'].def(null).declarations.single;
-            var fieldsAndSupr = js['fields'].def(fields);
-            fieldsAndSupr.declarations.add(supr);
-            return fieldsAndSupr;
-          })(),
-
-          // if (typeof fields == 'string') {
-          js.if_(js['fields'].typeof.equals(js.string('string')), [
-            // var s = fields.split(';');
-            js['s'].def(js['fields']['split'](js.string(';'))),
-
-            // supr = s[0];
-            js['supr'].assign(js['s'][0]),
-
-            // fields = s[1] == '' ? [] : s[1].split(',');
-            js['fields'].assign(
-                new jsAst.Conditional(
-                    js['s'][1].equals(js.string('')),
-                    new jsAst.ArrayInitializer(0, []),
-                    js['s'][1]['split'](js.string(',')))),
-          ], /* else */ [
-            // supr = desc['super'];
-            js['supr'].assign(js['desc']['super'])
-          ]),
-
-          // $isolatePropertiesName[cls] = $defineClassName(cls, fields, desc);
-          js[isolatePropertiesName][js['cls']].assign(
-              js[defineClassName](['cls', 'fields', 'desc'])),
-
-          // if (supr) $pendingClassesName[cls] = supr;
-          js.if_(js['supr'],
-                 js[pendingClassesName][js['cls']].assign(js['supr']))
-        ])
-      ]),
-
-
-      // var pendingClasses = $pendingClassesName;
-      js['pendingClasses'].def(js[pendingClassesName]),
-
-      /* FinishClasses can be called multiple times. This means that we need to
-         clear the pendingClasses property. */
-      // $pendingClassesName = {};
-      js[pendingClassesName].assign({}),
-
-      // var finishedClasses = {};
-      js['finishedClasses'].def({}),
-
-      // function finishClass(cls) { ... }
-      buildFinishClass(),
-
-      // for (var cls in pendingClasses) finishClass(cls);
-      js.forIn('cls', 'pendingClasses', js['finishClass']('cls'))
-    ]);
+    return '''
+function(collectedClasses) {
+  var hasOwnProperty = Object.prototype.hasOwnProperty;
+  for (var cls in collectedClasses) {
+    if (hasOwnProperty.call(collectedClasses, cls)) {
+      var desc = collectedClasses[cls];
+'''/* The 'fields' are either a constructor function or a string encoding
+      fields, constructor and superclass.  Get the superclass and the fields
+      in the format Super;field1,field2 from the null-string property on the
+      descriptor. */'''
+      var fields = desc[''], supr;
+      if (typeof fields == 'string') {
+        var s = fields.split(';'); supr = s[0];
+        fields = s[1] == '' ? [] : s[1].split(',');
+      } else {
+        supr = desc['super'];
+      }
+      $isolatePropertiesName[cls] = $defineClassName(cls, fields, desc);
+      if (supr) $pendingClassesName[cls] = supr;
+    }
+  }
+  var pendingClasses = $pendingClassesName;
+'''/* FinishClasses can be called multiple times. This means that we need to
+      clear the pendingClasses property. */'''
+  $pendingClassesName = {};
+  var finishedClasses = {};
+  function finishClass(cls) {
+'''/* Opera does not support 'getOwnPropertyNames'. Therefore we use
+      hasOwnProperty instead. */'''
+    var hasOwnProperty = Object.prototype.hasOwnProperty;
+    if (hasOwnProperty.call(finishedClasses, cls)) return;
+    finishedClasses[cls] = true;
+    var superclass = pendingClasses[cls];
+'''/* The superclass is only false (empty string) for Dart's Object class. */'''
+    if (!superclass) return;
+    finishClass(superclass);
+    var constructor = $isolatePropertiesName[cls];
+    var superConstructor = $isolatePropertiesName[superclass];
+    var prototype = constructor.prototype;
+    if ($supportsProtoName) {
+      prototype.__proto__ = superConstructor.prototype;
+      prototype.constructor = constructor;
+    } else {
+      function tmp() {};
+      tmp.prototype = superConstructor.prototype;
+      var newPrototype = new tmp();
+      constructor.prototype = newPrototype;
+      newPrototype.constructor = constructor;
+      for (var member in prototype) {
+        if (!member) continue;  '''/* Short version of: if (member == '') */'''
+        if (hasOwnProperty.call(prototype, member)) {
+          newPrototype[member] = prototype[member];
+        }
+      }
+    }
+  }
+  for (var cls in pendingClasses) finishClass(cls);
+}''';
   }
 
-  jsAst.FunctionDeclaration buildFinishClass() {
-    // function finishClass(cls) {
-    jsAst.Fun fun = js.fun(['cls'], [
-
-      // TODO(8540): Remove this work around.
-      /* Opera does not support 'getOwnPropertyNames'. Therefore we use
-         hasOwnProperty instead. */
-
-      // var hasOwnProperty = Object.prototype.hasOwnProperty;
-      js['hasOwnProperty'].def(js['Object']['prototype']['hasOwnProperty']),
-
-      // if (hasOwnProperty.call(finishedClasses, cls)) return;
-      js.if_(js['hasOwnProperty']['call'](['finishedClasses', 'cls']),
-             js.return_()),
-
-      // finishedClasses[cls] = true;
-      js['finishedClasses'][js['cls']].assign(true),
-
-      // var superclass = pendingClasses[cls];
-      js['superclass'].def(js['pendingClasses'][js['cls']]),
-
-      /* The superclass is only false (empty string) for Dart's Object class. */
-      // if (!superclass) return;
-      js.if_(js['superclass'].not, js.return_()),
-
-      // finishClass(superclass);
-      js['finishClass']('superclass'),
-
-      // var constructor = $isolatePropertiesName[cls];
-      js['constructor'].def(js[isolatePropertiesName][js['cls']]),
-
-      // var superConstructor = $isolatePropertiesName[superclass];
-      js['superConstructor'].def(js[isolatePropertiesName][js['superclass']]),
-
-      // var prototype = constructor.prototype;
-      js['prototype'].def(js['constructor']['prototype']),
-
-      // if ($supportsProtoName) {
-      js.if_(supportsProtoName, [
-        // prototype.__proto__ = superConstructor.prototype;
-        js['prototype']['__proto__'].assign(js['superConstructor']['prototype']),
-
-        // prototype.constructor = constructor;
-        js['prototype']['constructor'].assign('constructor')
-
-      ], /* else */ [
-        // function tmp() {};
-        new jsAst.FunctionDeclaration(
-            new jsAst.VariableDeclaration('tmp'),
-            js.fun([], [])),
-
-        // tmp.prototype = superConstructor.prototype;
-        js['tmp']['prototype'].assign(js['superConstructor']['prototype']),
-
-        // var newPrototype = new tmp();
-        js['newPrototype'].def(js['tmp'].newWith([])),
-
-        // constructor.prototype = newPrototype;
-        js['constructor']['prototype'].assign('newPrototype'),
-
-        // newPrototype.constructor = constructor;
-        js['newPrototype']['constructor'].assign('constructor'),
-
-        // for (var member in prototype) {
-        js.forIn('member', 'prototype', [
-          /* Short version of: if (member == '') */
-          // if (!member) continue;
-          js.if_(js['member'].not, new jsAst.Continue(null)),
-
-          // if (hasOwnProperty.call(prototype, member)) {
-          js.if_(js['hasOwnProperty']['call'](['prototype', 'member']), [
-            // newPrototype[member] = prototype[member];
-            js['newPrototype'][js['member']].assign(
-                js['prototype'][js['member']])
-          ])
-        ])
-
-      ])
-    ]);
-
-    return new jsAst.FunctionDeclaration(
-        new jsAst.VariableDeclaration('finishClass'),
-        fun);
-  }
-
-  jsAst.Fun get finishIsolateConstructorFunction {
+  String get finishIsolateConstructorFunction {
     String isolate = namer.isolateName;
     // We replace the old Isolate function with a new one that initializes
     // all its field with the initial (and often final) value of all globals.
@@ -576,178 +362,91 @@
     //
     // We also copy over old values like the prototype, and the
     // isolateProperties themselves.
-
-    // function(oldIsolate) {
-    return js.fun('oldIsolate', [
-      // var isolateProperties = oldIsolate.${namer.isolatePropertiesName};
-      js['isolateProperties'].def(
-                   js['oldIsolate'][namer.isolatePropertiesName]),
-
-      // var isolatePrototype = oldIsolate.prototype;
-      js['isolatePrototype'].def(js['oldIsolate']['prototype']),
-
-      // var str = "{\\n";
-      js['str'].def(js.string(r'{\n')),
-
-      // str += "var properties = $isolate.${namer.isolatePropertiesName};\\n";
-      js['str'].update('+', js.string('var properties = '
-                                      '$isolate.${namer.isolatePropertiesName};'
-                                      r'\n')),
-
-      // var hasOwnProperty = Object.prototype.hasOwnProperty;
-      js['hasOwnProperty'].def(js['Object']['prototype']['hasOwnProperty']),
-
-      // for (var staticName in isolateProperties) {
-      js.forIn('staticName', 'isolateProperties', [
-
-        // if (hasOwnProperty.call(isolateProperties, staticName)) {
-        js.if_(js['hasOwnProperty']['call'](['isolateProperties',
-                                             'staticName']), [
-
-          //str += "this." + staticName + "= properties." + staticName + ";\\n";
-          js['str'].update(
-              '+',
-              js.string("this.") + 'staticName' + js.string("= properties.") +
-              'staticName' + js.string(r';\n'))
-        ])
-      ]),
-
-      // str += "}\\n";
-      js['str'].update('+', js.string(r'}\n')),
-
-      // var newIsolate = new Function(str);
-      js['newIsolate'].def(js['Function'].newWith([js['str']])),
-
-      // newIsolate.prototype = isolatePrototype;
-      js['newIsolate']['prototype'].assign('isolatePrototype'),
-
-      // isolatePrototype.constructor = newIsolate;
-      js['isolatePrototype']['constructor'].assign('newIsolate'),
-
-      // newIsolate.${namer.isolatePropertiesName} = isolateProperties;
-      js['newIsolate'][namer.isolatePropertiesName].assign('isolateProperties'),
-
-      // return newIsolate;
-      js.return_('newIsolate')
-    ]);
+    return """function(oldIsolate) {
+  var isolateProperties = oldIsolate.${namer.isolatePropertiesName};
+  var isolatePrototype = oldIsolate.prototype;
+  var str = "{\\n";
+  str += "var properties = $isolate.${namer.isolatePropertiesName};\\n";
+  for (var staticName in isolateProperties) {
+    if (Object.prototype.hasOwnProperty.call(isolateProperties, staticName)) {
+      str += "this." + staticName + "= properties." + staticName + ";\\n";
+    }
+  }
+  str += "}\\n";
+  var newIsolate = new Function(str);
+  newIsolate.prototype = isolatePrototype;
+  isolatePrototype.constructor = newIsolate;
+  newIsolate.${namer.isolatePropertiesName} = isolateProperties;
+  return newIsolate;
+}""";
   }
 
-  jsAst.Fun get lazyInitializerFunction {
+  String get lazyInitializerFunction {
     String isolate = namer.CURRENT_ISOLATE;
-
-    // function(prototype, staticName, fieldName, getterName, lazyValue) {
-    var parameters = <String>['prototype', 'staticName', 'fieldName',
-                              'getterName', 'lazyValue'];
-    return js.fun(parameters, [
-      // var getter = new Function("{ return $isolate." + fieldName + ";}");
-      js['getter'].def(js['Function'].newWith([
-          js.string("{ return $isolate.") + 'fieldName' + js.string('}')]))
-    ]..addAll(addLazyInitializerLogic())
-    );
+    return """
+function(prototype, staticName, fieldName, getterName, lazyValue) {
+  var getter = new Function("{ return $isolate." + fieldName + ";}");
+$lazyInitializerLogic
+}""";
   }
 
-  List addLazyInitializerLogic() {
+  String get lazyInitializerLogic {
     String isolate = namer.CURRENT_ISOLATE;
     JavaScriptBackend backend = compiler.backend;
     String cyclicThrow = namer.isolateAccess(backend.cyclicThrowHelper);
-
-    return [
-      // var sentinelUndefined = {};
-      js['sentinelUndefined'].def({}),
-
-      // var sentinelInProgress = {};
-      js['sentinelInProgress'].def({}),
-
-      // prototype[fieldName] = sentinelUndefined;
-      js['prototype'][js['fieldName']].assign('sentinelUndefined'),
-
-      // prototype[getterName] = function() {
-      js['prototype'][js['getterName']].assign(js.fun([], [
-        // var result = $isolate[fieldName];
-        js['result'].def(js[isolate][js['fieldName']]),
-
-        // try {
-        js.try_([
-          // if (result === sentinelUndefined) {
-          js.if_(js['result'].strictEquals('sentinelUndefined'), [
-
-            // $isolate[fieldName] = sentinelInProgress;
-            js[isolate][js['fieldName']].assign('sentinelInProgress'),
-
-            // try {
-            js.try_([
-              // result = $isolate[fieldName] = lazyValue();
-              js['result'].assign(
-                  js[isolate][js['fieldName']].assign(js['lazyValue']()))
-
-            ], finallyPart: [
-              // Use try-finally, not try-catch/throw as it destroys the
-              // stack trace.
-
-              // if (result === sentinelUndefined) {
-              js.if_(js['result'].strictEquals('sentinelUndefined'), [
-                // if ($isolate[fieldName] === sentinelInProgress) {
-                js.if_(js[isolate][js['fieldName']]
-                       .strictEquals('sentinelInProgress'), [
-
-                  // $isolate[fieldName] = null;
-                  js[isolate][js['fieldName']].assign(new jsAst.LiteralNull())
-                ])
-              ])
-            ])
-          ], /* else */ [
-            // } else if (result === sentinelInProgress) {
-            js.if_(js['result'].strictEquals('sentinelInProgress'),
-              // $cyclicThrow(staticName);
-              js[cyclicThrow]('staticName')
-            )
-          ]),
-
-          // return result;
-          js.return_('result')
-
-        ], finallyPart: [
-          // $isolate[getterName] = getter;
-          js[isolate][js['getterName']].assign('getter')
-        ])
-      ]))
-    ];
+    return """
+  var sentinelUndefined = {};
+  var sentinelInProgress = {};
+  prototype[fieldName] = sentinelUndefined;
+  prototype[getterName] = function() {
+    var result = $isolate[fieldName];
+    try {
+      if (result === sentinelUndefined) {
+        $isolate[fieldName] = sentinelInProgress;
+        try {
+          result = $isolate[fieldName] = lazyValue();
+        } finally {
+""" // Use try-finally, not try-catch/throw as it destroys the stack trace.
+"""
+          if (result === sentinelUndefined) {
+            if ($isolate[fieldName] === sentinelInProgress) {
+              $isolate[fieldName] = null;
+            }
+          }
+        }
+      } else if (result === sentinelInProgress) {
+        $cyclicThrow(staticName);
+      }
+      return result;
+    } finally {
+      $isolate[getterName] = getter;
+    }
+  };""";
   }
 
-  List buildDefineClassAndFinishClassFunctionsIfNecessary() {
-    if (!needsDefineClass) return [];
-    return [
-      // Declare a function called "generateAccessor".  This is used in
+  void addDefineClassAndFinishClassFunctionsIfNecessary(CodeBuffer buffer) {
+    if (needsDefineClass) {
+      // Declare function called generateAccessor.  This is used in
       // defineClassFunction (it's a local declaration in init()).
-      generateAccessorFunction,
-
-      // $generateAccessorHolder = generateAccessor;
-      js[generateAccessorHolder].assign('generateAccessor'),
-
-      // $defineClassName = $defineClassFunction;
-      js[defineClassName].assign(defineClassFunction)
-    ]
-    ..addAll(buildProtoSupportCheck())
-    ..addAll([
-      // $pendingClassesName = {};
-      js[pendingClassesName].assign({}),
-
-      js[finishClassesName].assign(finishClassesFunction)
-    ]);
+      buffer.add("$generateAccessorFunction$N");
+      buffer.add("$generateAccessorHolder = generateAccessor$N");
+      buffer.add("$defineClassName = $defineClassFunction$N");
+      buffer.add(protoSupportCheck);
+      buffer.add("$pendingClassesName = {}$N");
+      buffer.add("$finishClassesName = $finishClassesFunction$N");
+    }
   }
 
-  List buildLazyInitializerFunctionIfNecessary() {
-    if (!needsLazyInitializer) return [];
-
-    // $lazyInitializerName = $lazyInitializerFunction
-    return [js[lazyInitializerName].assign(lazyInitializerFunction)];
+  void addLazyInitializerFunctionIfNecessary(CodeBuffer buffer) {
+    if (needsLazyInitializer) {
+      buffer.add("$lazyInitializerName = $lazyInitializerFunction$N");
+    }
   }
 
-  List buildFinishIsolateConstructor() {
-    return [
-      // $finishIsolateConstructorName = $finishIsolateConstructorFunction
-      js[finishIsolateConstructorName].assign(finishIsolateConstructorFunction)
-    ];
+  void emitFinishIsolateConstructor(CodeBuffer buffer) {
+    String name = finishIsolateConstructorName;
+    String value = finishIsolateConstructorFunction;
+    buffer.add("$name = $value$N");
   }
 
   void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) {
@@ -800,19 +499,19 @@
     String receiverArgumentName = r'$receiver';
 
     // The parameters that this stub takes.
-    List<jsAst.Parameter> parametersBuffer =
-        new List<jsAst.Parameter>.fixedLength(
+    List<js.Parameter> parametersBuffer =
+        new List<js.Parameter>.fixedLength(
             selector.argumentCount + extraArgumentCount);
     // The arguments that will be passed to the real method.
-    List<jsAst.Expression> argumentsBuffer =
-        new List<jsAst.Expression>.fixedLength(
+    List<js.Expression> argumentsBuffer =
+        new List<js.Expression>.fixedLength(
             parameters.parameterCount + extraArgumentCount);
 
     int count = 0;
     if (isInterceptorClass) {
       count++;
-      parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName);
-      argumentsBuffer[0] = js[receiverArgumentName];
+      parametersBuffer[0] = new js.Parameter(receiverArgumentName);
+      argumentsBuffer[0] = new js.VariableUse(receiverArgumentName);
     }
 
     int indexOfLastOptionalArgumentInParameters = positionalArgumentCount - 1;
@@ -824,17 +523,17 @@
       assert(jsName != receiverArgumentName);
       int optionalParameterStart = positionalArgumentCount + extraArgumentCount;
       if (count < optionalParameterStart) {
-        parametersBuffer[count] = new jsAst.Parameter(jsName);
-        argumentsBuffer[count] = js[jsName];
+        parametersBuffer[count] = new js.Parameter(jsName);
+        argumentsBuffer[count] = new js.VariableUse(jsName);
       } else {
         int index = names.indexOf(element.name);
         if (index != -1) {
           indexOfLastOptionalArgumentInParameters = count;
           // The order of the named arguments is not the same as the
           // one in the real method (which is in Dart source order).
-          argumentsBuffer[count] = js[jsName];
+          argumentsBuffer[count] = new js.VariableUse(jsName);
           parametersBuffer[optionalParameterStart + index] =
-              new jsAst.Parameter(jsName);
+              new js.Parameter(jsName);
         // Note that [elements] may be null for a synthesized [member].
         } else if (elements != null && elements.isParameterChecked(element)) {
           argumentsBuffer[count] = constantReference(SentinelConstant.SENTINEL);
@@ -855,16 +554,20 @@
       count++;
     });
 
-    List body;
+    List<js.Statement> body;
     if (member.hasFixedBackendName()) {
       body = nativeEmitter.generateParameterStubStatements(
           member, invocationName, parametersBuffer, argumentsBuffer,
           indexOfLastOptionalArgumentInParameters);
     } else {
-      body = [js.return_(js['this'][namer.getName(member)](argumentsBuffer))];
+      body = <js.Statement>[
+          new js.Return(
+              new js.VariableUse('this')
+                  .dot(namer.getName(member))
+                  .callWith(argumentsBuffer))];
     }
 
-    jsAst.Fun function = js.fun(parametersBuffer, body);
+    js.Fun function = new js.Fun(parametersBuffer, new js.Block(body));
 
     defineStub(invocationName, function);
   }
@@ -1023,7 +726,7 @@
         || member.isAccessor()) {
       if (member.isAbstract(compiler)) return;
       JavaScriptBackend backend = compiler.backend;
-      jsAst.Expression code = backend.generatedCode[member];
+      js.Expression code = backend.generatedCode[member];
       if (code == null) return;
       builder.addProperty(namer.getName(member), code);
       code = backend.generatedBailoutCode[member];
@@ -1085,12 +788,12 @@
         includeSuperMembers: false);
 
     void generateIsTest(Element other) {
-      jsAst.Expression code;
+      js.Expression code;
       if (compiler.objectClass == other) return;
       if (nativeEmitter.requiresNativeIsCheck(other)) {
-        code = js.fun([], [js.return_(true)]);
+        code = js.fun([], js.block1(js.return_(new js.LiteralBool(true))));
       } else {
-        code = new jsAst.LiteralBool(true);
+        code = new js.LiteralBool(true);
       }
       builder.addProperty(namer.operatorIs(other), code);
     }
@@ -1098,20 +801,21 @@
     void generateSubstitution(Element other, {bool emitNull: false}) {
       RuntimeTypeInformation rti = backend.rti;
       // TODO(karlklose): support typedefs with variables.
-      jsAst.Expression expression;
+      js.Expression expression;
       bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
       if (other.kind == ElementKind.CLASS) {
         String substitution = rti.getSupertypeSubstitution(classElement, other,
             alwaysGenerateFunction: true);
         if (substitution != null) {
-          expression = new jsAst.LiteralExpression(substitution);
+          expression = new js.LiteralExpression(substitution);
         } else if (emitNull || needsNativeCheck) {
-          expression = new jsAst.LiteralNull();
+          expression = new js.LiteralNull();
         }
       }
       if (expression != null) {
         if (needsNativeCheck) {
-          expression = js.fun([], js.return_(expression));
+          expression =
+              new js.Fun([], new js.Block([new js.Return(expression)]));
         }
         builder.addProperty(namer.substitutionName(other), expression);
       }
@@ -1143,7 +847,7 @@
           ? js.equals
           : js.strictEquals;
       builder.addProperty(name, js.fun(['receiver', 'a'],
-          js.block(js.return_(kind(js['receiver'], js['a'])))));
+          js.block1(js.return_(kind(js.use('receiver'), js.use('a'))))));
     }
   }
 
@@ -1305,14 +1009,17 @@
                       ClassBuilder builder) {
     String getterName = namer.getterNameFromAccessorName(accessorName);
     builder.addProperty(getterName,
-        js.fun([], js.return_(js['this'][fieldName])));
+        js.fun([], js.block1(js.return_(js.use('this').dot(fieldName)))));
   }
 
   void generateSetter(Element member, String fieldName, String accessorName,
                       ClassBuilder builder) {
     String setterName = namer.setterNameFromAccessorName(accessorName);
     builder.addProperty(setterName,
-        js.fun(['v'], js['this'][fieldName].assign('v')));
+        js.fun(['v'],
+            js.block1(
+                new js.ExpressionStatement(
+                    js.assign(js.use('this').dot(fieldName), js.use('v'))))));
   }
 
   bool canGenerateCheckedSetter(Element member) {
@@ -1337,14 +1044,19 @@
     SourceString helper = compiler.backend.getCheckedModeHelper(type);
     FunctionElement helperElement = compiler.findHelper(helper);
     String helperName = namer.isolateAccess(helperElement);
-    List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']];
+    List<js.Expression> arguments = <js.Expression>[js.use('v')];
     if (helperElement.computeSignature(compiler).parameterCount != 1) {
       arguments.add(js.string(namer.operatorIs(type.element)));
     }
 
     String setterName = namer.setterNameFromAccessorName(accessorName);
     builder.addProperty(setterName,
-        js.fun(['v'], js['this'][fieldName].assign(js[helperName](arguments))));
+        js.fun(['v'],
+            js.block1(
+                new js.ExpressionStatement(
+                    js.assign(
+                        js.use('this').dot(fieldName),
+                        js.call(js.use(helperName), arguments))))));
   }
 
   void emitClassConstructor(ClassElement classElement, ClassBuilder builder) {
@@ -1476,9 +1188,11 @@
     emitClassGettersSetters(classElement, builder);
     emitInstanceMembers(classElement, builder);
 
-    jsAst.Expression init =
-        js[classesCollector][className].assign(builder.toObjectInitializer());
-    buffer.add(jsAst.prettyPrint(init, compiler));
+    js.Expression init =
+        js.assign(
+            js.use(classesCollector).dot(className),
+            builder.toObjectInitializer());
+    buffer.add(js.prettyPrint(init, compiler));
     buffer.add('$N$n');
   }
 
@@ -1504,23 +1218,29 @@
     // emit all possible sends on intercepted methods.
     for (Selector selector in
          backend.usedInterceptors.toList()..sort(_compareSelectorNames)) {
-      List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
-      List<jsAst.Expression> arguments = <jsAst.Expression>[];
-      parameters.add(new jsAst.Parameter('receiver'));
+      List<js.Parameter> parameters = <js.Parameter>[];
+      List<js.Expression> arguments = <js.Expression>[];
+      parameters.add(new js.Parameter('receiver'));
 
       String name = backend.namer.invocationName(selector);
       if (selector.isSetter()) {
-        parameters.add(new jsAst.Parameter('value'));
-        arguments.add(js['value']);
+        parameters.add(new js.Parameter('value'));
+        arguments.add(new js.VariableUse('value'));
       } else {
         for (int i = 0; i < selector.argumentCount; i++) {
           String argName = 'a$i';
-          parameters.add(new jsAst.Parameter(argName));
-          arguments.add(js[argName]);
+          parameters.add(new js.Parameter(argName));
+          arguments.add(new js.VariableUse(argName));
         }
       }
-      jsAst.Fun function =
-          js.fun(parameters, js.return_(js['receiver'][name](arguments)));
+      js.Fun function =
+          new js.Fun(parameters,
+              new js.Block(
+                  <js.Statement>[
+                      new js.Return(
+                          new js.VariableUse('receiver')
+                              .dot(name)
+                              .callWith(arguments))]));
       builder.addProperty(name, function);
     }
   }
@@ -1750,10 +1470,10 @@
 
   void emitStaticFunction(CodeBuffer buffer,
                           String name,
-                          jsAst.Expression functionExpression) {
-    jsAst.Expression assignment =
-        js[isolateProperties][name].assign(functionExpression);
-    buffer.add(jsAst.prettyPrint(assignment, compiler));
+                          js.Expression functionExpression) {
+    js.Expression assignment =
+        js.assign(js.use(isolateProperties).dot(name), functionExpression);
+    buffer.add(js.prettyPrint(assignment, compiler));
     buffer.add('$N$n');
   }
 
@@ -1770,9 +1490,9 @@
             .toSet();
 
     for (Element element in Elements.sortedByPosition(elements)) {
-      jsAst.Expression code = backend.generatedCode[element];
+      js.Expression code = backend.generatedCode[element];
       emitStaticFunction(buffer, namer.getName(element), code);
-      jsAst.Expression bailoutCode = backend.generatedBailoutCode[element];
+      js.Expression bailoutCode = backend.generatedBailoutCode[element];
       if (bailoutCode != null) {
         pendingElementsWithBailouts.remove(element);
         emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
@@ -1782,7 +1502,7 @@
     // Is it possible the primary function was inlined but the bailout was not?
     for (Element element in
              Elements.sortedByPosition(pendingElementsWithBailouts)) {
-      jsAst.Expression bailoutCode = backend.generatedBailoutCode[element];
+      js.Expression bailoutCode = backend.generatedBailoutCode[element];
       emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
     }
   }
@@ -1804,11 +1524,13 @@
       String fieldAccess = '$isolateProperties.$staticName';
       buffer.add("$fieldAccess.$invocationName$_=$_$fieldAccess$N");
 
-      addParameterStubs(callElement, (String name, jsAst.Expression value) {
-        jsAst.Expression assignment =
-            js[isolateProperties][staticName][name].assign(value);
+      addParameterStubs(callElement, (String name, js.Expression value) {
+        js.Expression assignment =
+            js.assign(
+                js.use(isolateProperties).dot(staticName).dot(name),
+                value);
         buffer.add(
-            jsAst.prettyPrint(assignment.toStatement(), compiler));
+            js.prettyPrint(new js.ExpressionStatement(assignment), compiler));
         buffer.add('$N');
       });
 
@@ -1927,32 +1649,37 @@
       String invocationName = namer.instanceMethodName(callElement);
 
       List<String> parameters = <String>[];
-      List<jsAst.Expression> arguments = <jsAst.Expression>[];
+      List<js.Expression> arguments = <js.Expression>[];
       if (inInterceptor) {
-        arguments.add(js['this'][fieldNames[2]]);
+        arguments.add(js.use('this').dot(fieldNames[2]));
       }
       for (int i = 0; i < parameterCount; i++) {
         String name = 'p$i';
         parameters.add(name);
-        arguments.add(js[name]);
+        arguments.add(js.use(name));
       }
 
-      jsAst.Expression fun = js.fun(
-          parameters,
-          js.return_(
-              js['this'][fieldNames[0]][js['this'][fieldNames[1]]](arguments)));
+      js.Expression fun =
+          js.fun(parameters,
+              js.block1(
+                  js.return_(
+                      new js.PropertyAccess(
+                          js.use('this').dot(fieldNames[0]),
+                          js.use('this').dot(fieldNames[1]))
+                      .callWith(arguments))));
       boundClosureBuilder.addProperty(invocationName, fun);
 
       addParameterStubs(callElement, boundClosureBuilder.addProperty);
       typedefChecks.forEach((Element typedef) {
         String operator = namer.operatorIs(typedef);
-        boundClosureBuilder.addProperty(operator, new jsAst.LiteralBool(true));
+        boundClosureBuilder.addProperty(operator, new js.LiteralBool(true));
       });
 
-      jsAst.Expression init =
-          js[classesCollector][mangledName].assign(
+      js.Expression init =
+          js.assign(
+              js.use(classesCollector).dot(mangledName),
               boundClosureBuilder.toObjectInitializer());
-      boundClosureBuffer.add(jsAst.prettyPrint(init, compiler));
+      boundClosureBuffer.add(js.prettyPrint(init, compiler));
       boundClosureBuffer.add("$N");
 
       closureClass = namer.isolateAccess(closureClassElement);
@@ -1968,17 +1695,19 @@
     String targetName = namer.instanceMethodName(member);
 
     List<String> parameters = <String>[];
-    List<jsAst.Expression> arguments = <jsAst.Expression>[];
-    arguments.add(js['this']);
+    List<js.Expression> arguments = <js.Expression>[];
+    arguments.add(js.use('this'));
     arguments.add(js.string(targetName));
     if (inInterceptor) {
       parameters.add(extraArg);
-      arguments.add(js[extraArg]);
+      arguments.add(js.use(extraArg));
     }
 
-    jsAst.Expression getterFunction = js.fun(
-        parameters,
-        js.return_(js[closureClass].newWith(arguments)));
+    js.Expression getterFunction =
+        js.fun(parameters,
+            js.block1(
+                js.return_(
+                    new js.New(js.use(closureClass), arguments))));
 
     defineStub(getterName, getterFunction);
   }
@@ -2001,18 +1730,18 @@
 
     const String receiverArgumentName = r'$receiver';
 
-    jsAst.Expression buildGetter() {
+    js.Expression buildGetter() {
       if (member.isGetter()) {
         String getterName = namer.getterName(member);
-        return js['this'][getterName](
+        return new js.VariableUse('this').dot(getterName).callWith(
             isInterceptorClass
-                ? <jsAst.Expression>[js[receiverArgumentName]]
-                : <jsAst.Expression>[]);
+                ? <js.Expression>[new js.VariableUse(receiverArgumentName)]
+                : <js.Expression>[]);
       } else {
         String fieldName = member.hasFixedBackendName()
             ? member.fixedBackendName()
             : namer.instanceFieldName(member);
-        return js['this'][fieldName];
+        return new js.VariableUse('this').dot(fieldName);
       }
     }
 
@@ -2031,21 +1760,25 @@
         Selector callSelector = new Selector.callClosureFrom(selector);
         String closureCallName = namer.invocationName(callSelector);
 
-        List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
-        List<jsAst.Expression> arguments = <jsAst.Expression>[];
+        List<js.Parameter> parameters = <js.Parameter>[];
+        List<js.Expression> arguments = <js.Expression>[];
         if (isInterceptorClass) {
-          parameters.add(new jsAst.Parameter(receiverArgumentName));
+          parameters.add(new js.Parameter(receiverArgumentName));
         }
 
         for (int i = 0; i < selector.argumentCount; i++) {
           String name = 'arg$i';
-          parameters.add(new jsAst.Parameter(name));
-          arguments.add(js[name]);
+          parameters.add(new js.Parameter(name));
+          arguments.add(new js.VariableUse(name));
         }
 
-        jsAst.Fun function = js.fun(
-            parameters,
-            js.return_(buildGetter()[closureCallName](arguments)));
+        js.Fun function =
+            new js.Fun(parameters,
+                new js.Block(
+                    <js.Statement>[
+                        new js.Return(
+                            buildGetter().dot(closureCallName)
+                                .callWith(arguments))]));
 
         defineStub(invocationName, function);
       }
@@ -2059,10 +1792,13 @@
     for (Element element in Elements.sortedByPosition(staticNonFinalFields)) {
       compiler.withCurrentElement(element, () {
         Constant initialValue = handler.getInitialValueFor(element);
-        jsAst.Expression init =
-          js[isolateProperties][namer.getName(element)].assign(
-              constantEmitter.referenceInInitializationContext(initialValue));
-        buffer.add(jsAst.prettyPrint(init, compiler));
+        js.Expression init =
+            new js.Assignment(
+                new js.PropertyAccess.field(
+                    new js.VariableUse(isolateProperties),
+                    namer.getName(element)),
+                constantEmitter.referenceInInitializationContext(initialValue));
+        buffer.add(js.prettyPrint(init, compiler));
         buffer.add('$N');
       });
     }
@@ -2077,31 +1813,31 @@
       needsLazyInitializer = true;
       for (VariableElement element in Elements.sortedByPosition(lazyFields)) {
         assert(backend.generatedBailoutCode[element] == null);
-        jsAst.Expression code = backend.generatedCode[element];
+        js.Expression code = backend.generatedCode[element];
         assert(code != null);
         // The code only computes the initial value. We build the lazy-check
         // here:
         //   lazyInitializer(prototype, 'name', fieldName, getterName, initial);
         // The name is used for error reporting. The 'initial' must be a
         // closure that constructs the initial value.
-        List<jsAst.Expression> arguments = <jsAst.Expression>[];
-        arguments.add(js[isolateProperties]);
+        List<js.Expression> arguments = <js.Expression>[];
+        arguments.add(js.use(isolateProperties));
         arguments.add(js.string(element.name.slowToString()));
         arguments.add(js.string(namer.getName(element)));
         arguments.add(js.string(namer.getLazyInitializerName(element)));
         arguments.add(code);
-        jsAst.Expression getter = buildLazyInitializedGetter(element);
+        js.Expression getter = buildLazyInitializedGetter(element);
         if (getter != null) {
           arguments.add(getter);
         }
-        jsAst.Expression init = js[lazyInitializerName](arguments);
-        buffer.add(jsAst.prettyPrint(init, compiler));
+        js.Expression init = js.call(js.use(lazyInitializerName), arguments);
+        buffer.add(js.prettyPrint(init, compiler));
         buffer.add("$N");
       }
     }
   }
 
-  jsAst.Expression buildLazyInitializedGetter(VariableElement element) {
+  js.Expression buildLazyInitializedGetter(VariableElement element) {
     // Nothing to do, the 'lazy' function will create the getter.
     return null;
   }
@@ -2125,9 +1861,13 @@
         addedMakeConstantList = true;
         emitMakeConstantList(buffer);
       }
-      jsAst.Expression init = js[isolateProperties][name].assign(
-          constantInitializerExpression(constant));
-      buffer.add(jsAst.prettyPrint(init, compiler));
+      js.Expression init =
+          new js.Assignment(
+              new js.PropertyAccess.field(
+                  new js.VariableUse(isolateProperties),
+                  name),
+              constantInitializerExpression(constant));
+      buffer.add(js.prettyPrint(init, compiler));
       buffer.add('$N');
     }
   }
@@ -2195,17 +1935,17 @@
       return result;
     }
 
-    jsAst.Expression generateMethod(String jsName, Selector selector) {
+    js.Expression generateMethod(String jsName, Selector selector) {
       // Values match JSInvocationMirror in js-helper library.
       int type = selector.invocationMirrorKind;
       String methodName = selector.invocationMirrorMemberName;
-      List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
+      List<js.Parameter> parameters = <js.Parameter>[];
       CodeBuffer args = new CodeBuffer();
       for (int i = 0; i < selector.argumentCount; i++) {
-        parameters.add(new jsAst.Parameter('\$$i'));
+        parameters.add(new js.Parameter('\$$i'));
       }
 
-      List<jsAst.Expression> argNames =
+      List<js.Expression> argNames =
           selector.getOrderedNamedArguments().map((SourceString name) =>
               js.string(name.slowToString())).toList();
 
@@ -2214,15 +1954,26 @@
       String createInvocationMirror = namer.getName(
           compiler.createInvocationMirrorElement);
 
-      jsAst.Expression expression = js['this'][noSuchMethodName](
-          js[namer.CURRENT_ISOLATE][createInvocationMirror]([
-              js.string(methodName),
-              js.string(internalName),
-              type,
-              new jsAst.ArrayInitializer.from(
-                  parameters.map((param) => js[param.name]).toList()),
-              new jsAst.ArrayInitializer.from(argNames)]));
-      return js.fun(parameters, js.return_(expression));
+      js.Expression expression =
+          new js.This()
+          .dot(noSuchMethodName)
+          .callWith(
+              <js.Expression>[
+                  new js.VariableUse(namer.CURRENT_ISOLATE)
+                  .dot(createInvocationMirror)
+                  .callWith(
+                      <js.Expression>[
+                          js.string(methodName),
+                          js.string(internalName),
+                          new js.LiteralNumber('$type'),
+                          new js.ArrayInitializer.from(
+                              parameters.map((param) => js.use(param.name))
+                                        .toList()),
+                          new js.ArrayInitializer.from(argNames)])]);
+      js.Expression function =
+          new js.Fun(parameters,
+              new js.Block(<js.Statement>[new js.Return(expression)]));
+      return function;
     }
 
     void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) {
@@ -2314,7 +2065,7 @@
         if (holders.every(hasMatchingMember)) continue;
         String jsName = namer.invocationMirrorInternalName(selector);
         if (!addedJsNames.contains(jsName)) {
-          jsAst.Expression method = generateMethod(jsName, selector);
+          js.Expression method = generateMethod(jsName, selector);
           defineStub(jsName, method);
           addedJsNames.add(jsName);
         }
@@ -2393,34 +2144,36 @@
                                 String objectName,
                                 String key,
                                 Collection<ClassElement> classes) {
-    jsAst.Statement buildReturnInterceptor(ClassElement cls) {
-      return js.return_(js[namer.isolateAccess(cls)]['prototype']);
+    js.Statement buildReturnInterceptor(ClassElement cls) {
+      return js.return_(js.fieldAccess(js.use(namer.isolateAccess(cls)),
+                                       'prototype'));
     }
 
-    jsAst.VariableUse receiver = js['receiver'];
+    js.VariableUse receiver = js.use('receiver');
     JavaScriptBackend backend = compiler.backend;
 
     /**
      * Build a JavaScrit AST node for doing a type check on
      * [cls]. [cls] must be an interceptor class.
      */
-    jsAst.Statement buildInterceptorCheck(ClassElement cls) {
-      jsAst.Expression condition;
+    js.Statement buildInterceptorCheck(ClassElement cls) {
+      js.Expression condition;
       assert(backend.isInterceptorClass(cls));
       if (cls == backend.jsBoolClass) {
-        condition = receiver.typeof.equals(js.string('boolean'));
+        condition = js.equals(js.typeOf(receiver), js.string('boolean'));
       } else if (cls == backend.jsIntClass ||
                  cls == backend.jsDoubleClass ||
                  cls == backend.jsNumberClass) {
         throw 'internal error';
       } else if (cls == backend.jsArrayClass) {
-        condition = receiver['constructor'].equals('Array');
+        condition = js.equals(js.fieldAccess(receiver, 'constructor'),
+                              js.use('Array'));
       } else if (cls == backend.jsStringClass) {
-        condition = receiver.typeof.equals(js.string('string'));
+        condition = js.equals(js.typeOf(receiver), js.string('string'));
       } else if (cls == backend.jsNullClass) {
-        condition = receiver.equals(new jsAst.LiteralNull());
+        condition = js.equals(receiver, new js.LiteralNull());
       } else if (cls == backend.jsFunctionClass) {
-        condition = receiver.typeof.equals(js.string('function'));
+        condition = js.equals(js.typeOf(receiver), js.string('function'));
       } else {
         throw 'internal error';
       }
@@ -2452,28 +2205,31 @@
     }
     if (hasInt) hasNumber = true;
 
-    jsAst.Block block = new jsAst.Block.empty();
+    js.Block block = new js.Block.empty();
 
     if (hasNumber) {
-      jsAst.Statement whenNumber;
+      js.Statement whenNumber;
 
       /// Note: there are two number classes in play: Dart's [num],
       /// and JavaScript's Number (typeof receiver == 'number').  This
       /// is the fallback used when we have determined that receiver
       /// is a JavaScript Number.
-      jsAst.Return returnNumberClass = buildReturnInterceptor(
+      js.Return returnNumberClass = buildReturnInterceptor(
           hasDouble ? backend.jsDoubleClass : backend.jsNumberClass);
 
       if (hasInt) {
-        jsAst.Expression isInt = js['Math']['floor'](receiver).equals(receiver);
-        whenNumber = js.block([
-            js.if_(isInt, buildReturnInterceptor(backend.jsIntClass)),
-            returnNumberClass]);
+        js.Expression isInt =
+            js.equals(js.call(js.fieldAccess(js.use('Math'), 'floor'),
+                              [receiver]),
+                      receiver);
+        (whenNumber = js.emptyBlock()).statements
+          ..add(js.if_(isInt, buildReturnInterceptor(backend.jsIntClass)))
+          ..add(returnNumberClass);
       } else {
         whenNumber = returnNumberClass;
       }
       block.statements.add(
-          js.if_(receiver.typeof.equals(js.string('number')),
+          js.if_(js.equals(js.typeOf(receiver), js.string('number')),
                  whenNumber));
     }
 
@@ -2486,7 +2242,7 @@
       // Returning "undefined" here will provoke a JavaScript
       // TypeError which is later identified as a null-error by
       // [unwrapException] in js_helper.dart.
-      block.statements.add(js.if_(receiver.equals(new jsAst.LiteralNull()),
+      block.statements.add(js.if_(js.equals(receiver, new js.LiteralNull()),
                                   js.return_(js.undefined())));
     }
     if (hasFunction) {
@@ -2500,11 +2256,12 @@
     if (hasArray) {
       block.statements.add(buildInterceptorCheck(backend.jsArrayClass));
     }
-    block.statements.add(js.return_(js[objectName]['prototype']));
+    block.statements.add(js.return_(js.fieldAccess(js.use(objectName),
+                                                   'prototype')));
 
-    buffer.add(jsAst.prettyPrint(
-        js[isolateProperties][key].assign(js.fun(['receiver'], block)),
-        compiler));
+    js.PropertyAccess name = js.fieldAccess(js.use(isolateProperties), key);
+    buffer.add(js.prettyPrint(js.assign(name, js.fun(['receiver'], block)),
+                              compiler));
     buffer.add(N);
   }
 
@@ -2564,49 +2321,40 @@
       String getInterceptorName =
           namer.getInterceptorName(backend.getInterceptorMethod, classes);
 
-      List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
-      List<jsAst.Expression> arguments = <jsAst.Expression>[];
-      parameters.add(new jsAst.Parameter('receiver'));
-      arguments.add(js['receiver']);
+      List<js.Parameter> parameters = <js.Parameter>[];
+      List<js.Expression> arguments = <js.Expression>[];
+      parameters.add(new js.Parameter('receiver'));
+      arguments.add(js.use('receiver'));
 
       if (selector.isSetter()) {
-        parameters.add(new jsAst.Parameter('value'));
-        arguments.add(js['value']);
+        parameters.add(new js.Parameter('value'));
+        arguments.add(js.use('value'));
       } else {
         for (int i = 0; i < selector.argumentCount; i++) {
           String argName = 'a$i';
-          parameters.add(new jsAst.Parameter(argName));
-          arguments.add(js[argName]);
+          parameters.add(new js.Parameter(argName));
+          arguments.add(js.use(argName));
         }
       }
 
       String invocationName = backend.namer.invocationName(selector);
-      jsAst.Fun function = js.fun(parameters, js.return_(
-          js[isolateProperties][getInterceptorName]('receiver')[invocationName](
-              arguments)));
+      js.Fun function =
+          new js.Fun(parameters,
+              js.block1(js.return_(
+                        js.use(isolateProperties)
+                            .dot(getInterceptorName)
+                            .callWith([js.use('receiver')])
+                            .dot(invocationName)
+                            .callWith(arguments))));
 
-      jsAst.PropertyAccess property =
-          js[isolateProperties][oneShotInterceptorName];
+      js.PropertyAccess property =
+          js.fieldAccess(js.use(isolateProperties), oneShotInterceptorName);
 
-      buffer.add(jsAst.prettyPrint(property.assign(function), compiler));
+      buffer.add(js.prettyPrint(js.assign(property, function), compiler));
       buffer.add(N);
     }
   }
 
-  void emitInitFunction(CodeBuffer buffer) {
-    jsAst.Fun fun = js.fun([], [
-      // $isolateProperties = {};
-      js[isolateProperties].assign({}),
-    ]
-    ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary())
-    ..addAll(buildLazyInitializerFunctionIfNecessary())
-    ..addAll(buildFinishIsolateConstructor())
-    );
-    jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration(
-        new jsAst.VariableDeclaration('init'), fun);
-    buffer.add(jsAst.prettyPrint(decl, compiler).getText());
-  }
-
   String assembleProgram() {
     measure(() {
       computeNeededClasses();
@@ -2656,7 +2404,12 @@
 
       nativeEmitter.assembleCode(mainBuffer);
       emitMain(mainBuffer);
-      emitInitFunction(mainBuffer);
+      mainBuffer.add('function init()$_{\n');
+      mainBuffer.add('$isolateProperties$_=$_{}$N');
+      addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer);
+      addLazyInitializerFunctionIfNecessary(mainBuffer);
+      emitFinishIsolateConstructor(mainBuffer);
+      mainBuffer.add('}\n');
       compiler.assembledCode = mainBuffer.getText();
 
       if (generateSourceMap) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
index 8a2f2b8..0bfb5df 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
@@ -10,18 +10,15 @@
 import '../../compiler.dart' as api;
 import '../elements/elements.dart';
 import '../elements/modelx.dart' show FunctionElementX;
-
-// TODO(ahe): There seems to be a bug in the VM, so we have to hide "js".
-import '../dart2jslib.dart' hide Selector, js;
+import '../dart2jslib.dart' hide Selector;
 import '../dart_types.dart';
-import '../js/js.dart' as jsAst;
-import '../js/js.dart' show js; // TODO(ahe): VM bug, see above.
+import '../js/js.dart' as js;
 import '../native_handler.dart' as native;
 import '../source_file.dart';
 import '../source_map_builder.dart';
-import '../ssa/ssa.dart' hide js; // TODO(ahe): VM bug, see above.
+import '../ssa/ssa.dart';
 import '../tree/tree.dart';
-import '../universe/universe.dart' hide js; // TODO(ahe): VM bug, see above.
+import '../universe/universe.dart';
 import '../util/characters.dart';
 import '../util/util.dart';
 
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
index 9c96a80..0343457 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
@@ -138,11 +138,11 @@
     if (builder.properties.isEmpty) return;
 
     String nativeTag = toNativeTag(classElement);
-    jsAst.Expression definition =
-        js[defineNativeClassName](
-            [js.string(nativeTag), builder.toObjectInitializer()]);
+    js.Expression definition =
+        js.call(js.use(defineNativeClassName),
+                [js.string(nativeTag), builder.toObjectInitializer()]);
 
-    nativeBuffer.add(jsAst.prettyPrint(definition, compiler));
+    nativeBuffer.add(js.prettyPrint(definition, compiler));
     nativeBuffer.add('$N$n');
 
     classesWithDynamicDispatch.add(classElement);
@@ -153,10 +153,9 @@
     return result == null ? const<ClassElement>[] : result;
   }
 
-  void potentiallyConvertDartClosuresToJs(
-      List<jsAst.Statement> statements,
-      FunctionElement member,
-      List<jsAst.Parameter> stubParameters) {
+  void potentiallyConvertDartClosuresToJs(List<js.Statement> statements,
+                                          FunctionElement member,
+                                          List<js.Parameter> stubParameters) {
     FunctionSignature parameters = member.computeSignature(compiler);
     Element converter =
         compiler.findHelper(const SourceString('convertDartClosureToJS'));
@@ -167,7 +166,7 @@
       String name = parameter.name.slowToString();
       // If [name] is not in [stubParameters], then the parameter is an optional
       // parameter that was not provided for this stub.
-      for (jsAst.Parameter stubParameter in stubParameters) {
+      for (js.Parameter stubParameter in stubParameters) {
         if (stubParameter.name == name) {
           DartType type = parameter.computeType(compiler).unalias(compiler);
           if (type is FunctionType) {
@@ -176,12 +175,11 @@
             int arity = type.computeArity();
 
             statements.add(
-                new jsAst.ExpressionStatement(
+                new js.ExpressionStatement(
                     js.assign(
-                        js[name],
-                        js[closureConverter](
-                            [js[name],
-                             new jsAst.LiteralNumber('$arity')]))));
+                        js.use(name),
+                        js.use(closureConverter).callWith(
+                            [js.use(name), new js.LiteralNumber('$arity')]))));
             break;
           }
         }
@@ -189,11 +187,11 @@
     });
   }
 
-  List<jsAst.Statement> generateParameterStubStatements(
+  List<js.Statement> generateParameterStubStatements(
       Element member,
       String invocationName,
-      List<jsAst.Parameter> stubParameters,
-      List<jsAst.Expression> argumentsBuffer,
+      List<js.Parameter> stubParameters,
+      List<js.Expression> argumentsBuffer,
       int indexOfLastOptionalArgumentInParameters) {
     // The target JS function may check arguments.length so we need to
     // make sure not to pass any unspecified optional arguments to it.
@@ -207,11 +205,11 @@
     ClassElement classElement = member.enclosingElement;
     String nativeTagInfo = classElement.nativeTagInfo.slowToString();
 
-    List<jsAst.Statement> statements = <jsAst.Statement>[];
+    List<js.Statement> statements = <js.Statement>[];
     potentiallyConvertDartClosuresToJs(statements, member, stubParameters);
 
     String target;
-    List<jsAst.Expression> arguments;
+    List<js.Expression> arguments;
 
     if (!nativeMethods.contains(member)) {
       // When calling a method that has a native body, we call it with our
@@ -226,16 +224,16 @@
           0, indexOfLastOptionalArgumentInParameters + 1);
     }
     statements.add(
-        new jsAst.Return(
-            new jsAst.VariableUse('this')[target](arguments)));
+        new js.Return(
+            new js.VariableUse('this').dot(target).callWith(arguments)));
 
     if (!overriddenMethods.contains(member)) {
       // Call the method directly.
       return statements;
     } else {
-      return <jsAst.Statement>[
+      return <js.Statement>[
           generateMethodBodyWithPrototypeCheck(
-              invocationName, new jsAst.Block(statements), stubParameters)];
+              invocationName, new js.Block(statements), stubParameters)];
     }
   }
 
@@ -244,24 +242,26 @@
   // super class. If the method is not available, we make a direct call to
   // Object.prototype.$methodName.  This method will patch the prototype of
   // 'this' to the real method.
-  jsAst.Statement generateMethodBodyWithPrototypeCheck(
+  js.Statement generateMethodBodyWithPrototypeCheck(
       String methodName,
-      jsAst.Statement body,
-      List<jsAst.Parameter> parameters) {
+      js.Statement body,
+      List<js.Parameter> parameters) {
     return js.if_(
-        js['Object']['getPrototypeOf']('this')['hasOwnProperty'](
-            js.string(methodName)),
+        js.use('Object').dot('getPrototypeOf')
+            .callWith([js.use('this')])
+            .dot('hasOwnProperty').callWith([js.string(methodName)]),
         body,
         js.return_(
-            js['Object']['prototype'][methodName]['call'](
-                <jsAst.Expression>[js['this']]..addAll(
-                    parameters.map((param) => js[param.name])))));
+            js.use('Object').dot('prototype').dot(methodName).dot('call')
+            .callWith(
+                <js.Expression>[js.use('this')]..addAll(
+                    parameters.map((param) => js.use(param.name))))));
   }
 
-  jsAst.Block generateMethodBodyWithPrototypeCheckForElement(
+  js.Block generateMethodBodyWithPrototypeCheckForElement(
       FunctionElement element,
-      jsAst.Block body,
-      List<jsAst.Parameter> parameters) {
+      js.Block body,
+      List<js.Parameter> parameters) {
     ElementKind kind = element.kind;
     if (kind != ElementKind.FUNCTION &&
         kind != ElementKind.GETTER &&
@@ -270,7 +270,7 @@
     }
 
     String methodName = backend.namer.getName(element);
-    return new jsAst.Block(
+    return new js.Block(
         [generateMethodBodyWithPrototypeCheck(methodName, body, parameters)]);
   }
 
@@ -322,23 +322,23 @@
     // Temporary variables for common substrings.
     List<String> varNames = <String>[];
     // Values of temporary variables.
-    Map<String, jsAst.Expression> varDefns = new Map<String, jsAst.Expression>();
+    Map<String, js.Expression> varDefns = new Map<String, js.Expression>();
 
     // Expression to compute tags string for a class.  The expression will
     // initially be a string or expression building a string, but may be
     // replaced with a variable reference to the common substring.
-    Map<ClassElement, jsAst.Expression> tagDefns =
-        new Map<ClassElement, jsAst.Expression>();
+    Map<ClassElement, js.Expression> tagDefns =
+        new Map<ClassElement, js.Expression>();
 
-    jsAst.Expression makeExpression(ClassElement classElement) {
+    js.Expression makeExpression(ClassElement classElement) {
       // Expression fragments for this set of cls keys.
-      List<jsAst.Expression> expressions = <jsAst.Expression>[];
+      List<js.Expression> expressions = <js.Expression>[];
       // TODO: Remove if cls is abstract.
       List<String> subtags = [toNativeTag(classElement)];
       void walk(ClassElement cls) {
         for (final ClassElement subclass in getDirectSubclasses(cls)) {
           ClassElement tag = subclass;
-          jsAst.Expression existing = tagDefns[tag];
+          js.Expression existing = tagDefns[tag];
           if (existing == null) {
             // [subclass] is still within the subtree between dispatch classes.
             subtags.add(toNativeTag(tag));
@@ -346,19 +346,19 @@
           } else {
             // [subclass] is one of the preorderDispatchClasses, so CSE this
             // reference with the previous reference.
-            jsAst.VariableUse use = existing.asVariableUse();
+            js.VariableUse use = existing.asVariableUse();
             if (use != null && varDefns.containsKey(use.name)) {
               // We end up here if the subclasses have a DAG structure.  We
               // don't have DAGs yet, but if the dispatch is used for mixins
               // that will be a possibility.
               // Re-use the previously created temporary variable.
-              expressions.add(new jsAst.VariableUse(use.name));
+              expressions.add(new js.VariableUse(use.name));
             } else {
               String varName = 'v${varNames.length}_${tag.name.slowToString()}';
               varNames.add(varName);
               varDefns[varName] = existing;
-              tagDefns[tag] = new jsAst.VariableUse(varName);
-              expressions.add(new jsAst.VariableUse(varName));
+              tagDefns[tag] = new js.VariableUse(varName);
+              expressions.add(new js.VariableUse(varName));
             }
           }
         }
@@ -368,12 +368,12 @@
       if (!subtags.isEmpty) {
         expressions.add(js.string(subtags.join('|')));
       }
-      jsAst.Expression expression;
+      js.Expression expression;
       if (expressions.length == 1) {
         expression = expressions[0];
       } else {
-        jsAst.Expression array = new jsAst.ArrayInitializer.from(expressions);
-        expression = array['join']([js.string('|')]);
+        js.Expression array = new js.ArrayInitializer.from(expressions);
+        expression = js.call(array.dot('join'), [js.string('|')]);
       }
       return expression;
     }
@@ -384,47 +384,46 @@
 
     // Write out a thunk that builds the metadata.
     if (!tagDefns.isEmpty) {
-      List<jsAst.Statement> statements = <jsAst.Statement>[];
+      List<js.Statement> statements = <js.Statement>[];
 
-      List<jsAst.VariableInitialization> initializations =
-          <jsAst.VariableInitialization>[];
+      List<js.VariableInitialization> initializations =
+          <js.VariableInitialization>[];
       for (final String varName in varNames) {
         initializations.add(
-            new jsAst.VariableInitialization(
-                new jsAst.VariableDeclaration(varName),
+            new js.VariableInitialization(
+                new js.VariableDeclaration(varName),
                 varDefns[varName]));
       }
       if (!initializations.isEmpty) {
         statements.add(
-            new jsAst.ExpressionStatement(
-                new jsAst.VariableDeclarationList(initializations)));
+            new js.ExpressionStatement(
+                new js.VariableDeclarationList(initializations)));
       }
 
       // [table] is a list of lists, each inner list of the form:
       //   [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag]
       // E.g.
       //   [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...]
-      jsAst.Expression table =
-          new jsAst.ArrayInitializer.from(
+      js.Expression table =
+          new js.ArrayInitializer.from(
               preorderDispatchClasses.map((cls) =>
-                  new jsAst.ArrayInitializer.from([
+                  new js.ArrayInitializer.from([
                       js.string(toNativeTag(cls)),
                       tagDefns[cls]])));
 
       //  $.dynamicSetMetadata(table);
       statements.add(
-          new jsAst.ExpressionStatement(
-              new jsAst.Call(
-                  new jsAst.VariableUse(dynamicSetMetadataName),
+          new js.ExpressionStatement(
+              new js.Call(
+                  new js.VariableUse(dynamicSetMetadataName),
                   [table])));
 
       //  (function(){statements})();
       if (emitter.compiler.enableMinification) nativeBuffer.add(';');
       nativeBuffer.add(
-          jsAst.prettyPrint(
-              new jsAst.ExpressionStatement(
-                  new jsAst.Call(new jsAst.Fun([], new jsAst.Block(statements)),
-                                 [])),
+          js.prettyPrint(
+              new js.ExpressionStatement(
+                  new js.Call(new js.Fun([], new js.Block(statements)), [])),
               compiler));
     }
   }
@@ -461,10 +460,10 @@
     targetBuffer.add('$defineNativeClassName = '
                      '$defineNativeClassFunction$N$n');
 
-    List<jsAst.Property> objectProperties = <jsAst.Property>[];
+    List<js.Property> objectProperties = <js.Property>[];
 
-    void addProperty(String name, jsAst.Expression value) {
-      objectProperties.add(new jsAst.Property(js.string(name), value));
+    void addProperty(String name, js.Expression value) {
+      objectProperties.add(new js.Property(js.string(name), value));
     }
 
     // Because of native classes, we have to generate some is checks
@@ -479,14 +478,16 @@
         if (element.isObject(compiler)) continue;
         String name = backend.namer.operatorIs(element);
         addProperty(name,
-            js.fun([], js.return_(new jsAst.LiteralBool(false))));
+            js.fun([], js.block1(js.return_(new js.LiteralBool(false)))));
       }
     }
     emitIsChecks();
 
-    jsAst.Expression makeCallOnThis(String functionName) {
-      return js.fun([], js.return_(js[functionName]('this')));
-    }
+    js.Expression makeCallOnThis(String functionName) =>
+        js.fun([],
+            js.block1(
+                js.return_(
+                    js.call(js.use(functionName), [js.use('this')]))));
 
     // In order to have the toString method on every native class,
     // we must patch the JS Object prototype with a helper method.
@@ -502,8 +503,8 @@
     // Same as above, but for operator==.
     String equalsName = backend.namer.publicInstanceMethodNameByArity(
         const SourceString('=='), 1);
-    addProperty(equalsName, js.fun(['a'],
-        js.return_(js.strictEquals(new jsAst.This(), js['a']))));
+    addProperty(equalsName, js.fun(['a'], js.block1(
+        js.return_(js.strictEquals(new js.This(), js.use('a'))))));
 
     // If the native emitter has been asked to take care of the
     // noSuchMethod handlers, we do that now.
@@ -514,25 +515,28 @@
     // If we have any properties to add to Object.prototype, we run
     // through them and add them using defineProperty.
     if (!objectProperties.isEmpty) {
-      jsAst.Expression init =
-          js.fun(['table'],
-              new jsAst.ForIn(
-                  new jsAst.VariableDeclarationList(
-                      [new jsAst.VariableInitialization(
-                          new jsAst.VariableDeclaration('key'),
-                          null)]),
-                  js['table'],
-                  new jsAst.ExpressionStatement(
-                      js[defPropName](
-                          [js['Object']['prototype'],
-                           js['key'],
-                           new jsAst.PropertyAccess(js['table'],
-                                                    js['key'])]))))(
-              new jsAst.ObjectInitializer(objectProperties));
+      js.Expression init =
+          js.call(
+              js.fun(['table'],
+                  js.block1(
+                      new js.ForIn(
+                          new js.VariableDeclarationList(
+                              [new js.VariableInitialization(
+                                  new js.VariableDeclaration('key'),
+                                  null)]),
+                          js.use('table'),
+                          new js.ExpressionStatement(
+                              js.call(
+                                  js.use(defPropName),
+                                  [js.use('Object').dot('prototype'),
+                                   js.use('key'),
+                                   new js.PropertyAccess(js.use('table'),
+                                                         js.use('key'))]))))),
+              [new js.ObjectInitializer(objectProperties)]);
 
       if (emitter.compiler.enableMinification) targetBuffer.add(';');
-      targetBuffer.add(jsAst.prettyPrint(
-          new jsAst.ExpressionStatement(init), compiler));
+      targetBuffer.add(js.prettyPrint(
+          new js.ExpressionStatement(init), compiler));
       targetBuffer.add('\n');
     }
 
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart b/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
index 91a6782..e33ae3f 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
@@ -230,7 +230,7 @@
 
   bool every(bool f(E element)) => IterableMixinWorkaround.every(this, f);
 
-  Iterable<E> get reversed => IterableMixinWorkaround.reversedList(this);
+  List<E> get reversed => IterableMixinWorkaround.reversedList(this);
 
   void sort([int compare(E a, E b)]) {
     checkMutable(this, 'sort');
diff --git a/sdk/lib/collection/collections.dart b/sdk/lib/collection/collections.dart
index 18c1d7b..81dd6da 100644
--- a/sdk/lib/collection/collections.dart
+++ b/sdk/lib/collection/collections.dart
@@ -318,7 +318,7 @@
   }
 
   static Iterable mapList(List list, f(var element)) {
-    return new MappedListIterable(list, f);
+    return new MappedListIterable(list, f, 0, null);
   }
 
   static List mappedByList(List list, f(var element)) {
@@ -333,7 +333,7 @@
   static Iterable takeList(List list, int n) {
     // The generic type is currently lost. It will be fixed with mixins.
     // This is currently a List as well as an Iterable.
-    return new SubListIterable(list, 0, n);
+    return new ListView(list, 0, n);
   }
 
   static Iterable takeWhile(Iterable iterable, bool test(var value)) {
@@ -344,7 +344,7 @@
   static Iterable skipList(List list, int n) {
     // The generic type is currently lost. It will be fixed with mixins.
     // This is currently a List as well as an Iterable.
-    return new SubListIterable(list, n, null);
+    return new ListView(list, n, null);
   }
 
   static Iterable skipWhile(Iterable iterable, bool test(var value)) {
@@ -352,8 +352,8 @@
     return new SkipWhileIterable(iterable, test);
   }
 
-  static Iterable reversedList(List l) {
-    return new ReversedListIterable(l);
+  static List reversedList(List l) {
+    return new ReversedListView(l, 0, null);
   }
 
   static void sortList(List l, int compare(a, b)) {
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index ecb5535..10ba3e0 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -77,9 +77,13 @@
   void addAll(Iterable<E> iterable);
 
   /**
-   * Returns an [Iterable] of the elements of this [List] in reverse order.
+   * Returns a reversed fixed-length view of this [List].
+   *
+   * The reversed list has elements in the opposite order of this list.
+   * It is backed by this list, but will stop working if this list
+   * becomes shorter than its current length.
    */
-  Iterable<E> get reversed;
+  List<E> get reversed;
 
   /**
    * Sorts the list according to the order specified by the [compare] function.
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 86dfb92..8688fea 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -7266,7 +7266,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<DomMimeType> get reversed {
+  List<DomMimeType> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -7523,7 +7523,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<DomPlugin> get reversed {
+  List<DomPlugin> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -7887,7 +7887,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<String> get reversed {
+  List<String> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -8165,7 +8165,7 @@
     }
   }
 
-  Iterable<Element> get reversed {
+  List<Element> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -8399,7 +8399,7 @@
     throw new UnsupportedError('');
   }
 
-  Iterable<Element> get reversed {
+  List<Element> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -10729,7 +10729,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<File> get reversed {
+  List<File> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -11289,7 +11289,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<num> get reversed {
+  List<num> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -11508,7 +11508,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<num> get reversed {
+  List<num> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -12036,7 +12036,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -12246,7 +12246,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -14268,7 +14268,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -14487,7 +14487,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -14706,7 +14706,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -17198,7 +17198,7 @@
     return this[index];
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -17607,7 +17607,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -19927,7 +19927,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<SourceBuffer> get reversed {
+  List<SourceBuffer> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -20210,7 +20210,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<SpeechGrammar> get reversed {
+  List<SpeechGrammar> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -20781,7 +20781,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Map> get reversed {
+  List<Map> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -21867,7 +21867,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<TextTrackCue> get reversed {
+  List<TextTrackCue> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -22075,7 +22075,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<TextTrack> get reversed {
+  List<TextTrack> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -22490,7 +22490,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Touch> get reversed {
+  List<Touch> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -22939,7 +22939,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -23158,7 +23158,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -23377,7 +23377,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -23593,7 +23593,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -27312,7 +27312,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<ClientRect> get reversed {
+  List<ClientRect> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -27512,7 +27512,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<CssRule> get reversed {
+  List<CssRule> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -27712,7 +27712,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<CssValue> get reversed {
+  List<CssValue> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -27912,7 +27912,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Entry> get reversed {
+  List<Entry> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -28112,7 +28112,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<EntrySync> get reversed {
+  List<EntrySync> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -28312,7 +28312,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Gamepad> get reversed {
+  List<Gamepad> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -28575,7 +28575,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<MediaStream> get reversed {
+  List<MediaStream> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -28775,7 +28775,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -28999,7 +28999,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<SpeechInputResult> get reversed {
+  List<SpeechInputResult> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -29199,7 +29199,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<SpeechRecognitionResult> get reversed {
+  List<SpeechRecognitionResult> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -29399,7 +29399,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<StyleSheet> get reversed {
+  List<StyleSheet> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index db5b57a..ff46655 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -7967,7 +7967,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<DomMimeType> get reversed {
+  List<DomMimeType> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -8238,7 +8238,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<DomPlugin> get reversed {
+  List<DomPlugin> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -8627,7 +8627,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<String> get reversed {
+  List<String> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -8926,7 +8926,7 @@
     }
   }
 
-  Iterable<Element> get reversed {
+  List<Element> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -9160,7 +9160,7 @@
     throw new UnsupportedError('');
   }
 
-  Iterable<Element> get reversed {
+  List<Element> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -11465,7 +11465,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<File> get reversed {
+  List<File> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -12079,7 +12079,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<num> get reversed {
+  List<num> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -12317,7 +12317,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<num> get reversed {
+  List<num> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -12915,7 +12915,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -13127,7 +13127,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -15488,7 +15488,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -15726,7 +15726,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -15964,7 +15964,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -18735,7 +18735,7 @@
     return this[index];
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -19141,7 +19141,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -21768,7 +21768,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<SourceBuffer> get reversed {
+  List<SourceBuffer> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -22089,7 +22089,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<SpeechGrammar> get reversed {
+  List<SpeechGrammar> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -22747,7 +22747,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Map> get reversed {
+  List<Map> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -24069,7 +24069,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<TextTrackCue> get reversed {
+  List<TextTrackCue> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -24281,7 +24281,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<TextTrack> get reversed {
+  List<TextTrack> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -24700,7 +24700,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Touch> get reversed {
+  List<Touch> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -25194,7 +25194,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -25432,7 +25432,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -25670,7 +25670,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -25906,7 +25906,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<int> get reversed {
+  List<int> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -29584,7 +29584,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<ClientRect> get reversed {
+  List<ClientRect> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -29788,7 +29788,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<CssRule> get reversed {
+  List<CssRule> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -29992,7 +29992,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<CssValue> get reversed {
+  List<CssValue> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -30339,7 +30339,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Entry> get reversed {
+  List<Entry> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -30543,7 +30543,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<EntrySync> get reversed {
+  List<EntrySync> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -30747,7 +30747,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Gamepad> get reversed {
+  List<Gamepad> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -31042,7 +31042,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<MediaStream> get reversed {
+  List<MediaStream> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -31246,7 +31246,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -31474,7 +31474,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<SpeechInputResult> get reversed {
+  List<SpeechInputResult> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -31678,7 +31678,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<SpeechRecognitionResult> get reversed {
+  List<SpeechRecognitionResult> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -31882,7 +31882,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<StyleSheet> get reversed {
+  List<StyleSheet> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
diff --git a/sdk/lib/html/html_common/filtered_element_list.dart b/sdk/lib/html/html_common/filtered_element_list.dart
index 9820f1a..330b0df 100644
--- a/sdk/lib/html/html_common/filtered_element_list.dart
+++ b/sdk/lib/html/html_common/filtered_element_list.dart
@@ -69,7 +69,7 @@
     return element is Element && _childNodes.contains(element);
   }
 
-  Iterable<Element> get reversed => _filtered.reversed;
+  List<Element> get reversed => _filtered.reversed;
 
   void sort([int compare(Element a, Element b)]) {
     throw new UnsupportedError('TODO(jacobr): should we impl?');
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index df439d6..09a63ec 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -3149,7 +3149,7 @@
 
   // clear() defined by IDL.
 
-  Iterable<Length> get reversed {
+  List<Length> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -3776,7 +3776,7 @@
 
   // clear() defined by IDL.
 
-  Iterable<Number> get reversed {
+  List<Number> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -4679,7 +4679,7 @@
 
   // clear() defined by IDL.
 
-  Iterable<PathSeg> get reversed {
+  List<PathSeg> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -5566,7 +5566,7 @@
 
   // clear() defined by IDL.
 
-  Iterable<String> get reversed {
+  List<String> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -6732,7 +6732,7 @@
 
   // clear() defined by IDL.
 
-  Iterable<Transform> get reversed {
+  List<Transform> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -7254,7 +7254,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<ElementInstance> get reversed {
+  List<ElementInstance> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index 98cb362..debc991 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -3413,7 +3413,7 @@
 
   // clear() defined by IDL.
 
-  Iterable<Length> get reversed {
+  List<Length> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -4117,7 +4117,7 @@
 
   // clear() defined by IDL.
 
-  Iterable<Number> get reversed {
+  List<Number> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -5297,7 +5297,7 @@
 
   // clear() defined by IDL.
 
-  Iterable<PathSeg> get reversed {
+  List<PathSeg> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -6282,7 +6282,7 @@
 
   // clear() defined by IDL.
 
-  Iterable<String> get reversed {
+  List<String> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -7537,7 +7537,7 @@
 
   // clear() defined by IDL.
 
-  Iterable<Transform> get reversed {
+  List<Transform> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -8113,7 +8113,7 @@
     throw new UnsupportedError("Cannot clear immutable List.");
   }
 
-  Iterable<ElementInstance> get reversed {
+  List<ElementInstance> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
diff --git a/tests/corelib/iterable_skip_test.dart b/tests/corelib/iterable_skip_test.dart
index 2889c9c..fff6db7 100644
--- a/tests/corelib/iterable_skip_test.dart
+++ b/tests/corelib/iterable_skip_test.dart
@@ -13,7 +13,7 @@
   Set set2 = new Set();
 
   Iterable<int> skip0 = list1.skip(0);
-  Expect.isTrue(skip0 is! List);
+  Expect.isTrue(skip0 is List);
   Iterator<int> it = skip0.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -26,8 +26,8 @@
   Expect.isNull(it.current);
 
   Iterable<int> skip1 = list1.skip(1);
-  Expect.isTrue(skip1 is! List);
-  Expect.isTrue(skip1.skip(2).skip(1) is! List);
+  Expect.isTrue(skip1 is List);
+  Expect.isTrue(skip1.skip(2).skip(1) is List);
   it = skip1.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -38,8 +38,8 @@
   Expect.isNull(it.current);
 
   Iterable<int> skip2 = list1.skip(2);
-  Expect.isTrue(skip2 is! List);
-  Expect.isTrue(skip2.skip(2).skip(1) is! List);
+  Expect.isTrue(skip2 is List);
+  Expect.isTrue(skip2.skip(2).skip(1) is List);
   it = skip2.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -48,16 +48,16 @@
   Expect.isNull(it.current);
 
   Iterable<int> skip3 = list1.skip(3);
-  Expect.isTrue(skip3 is! List);
-  Expect.isTrue(skip3.skip(2).skip(1) is! List);
+  Expect.isTrue(skip3 is List);
+  Expect.isTrue(skip3.skip(2).skip(1) is List);
   it = skip3.iterator;
   Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
   Expect.isNull(it.current);
 
   Iterable<int> skip4 = list1.skip(4);
-  Expect.isTrue(skip4 is! List);
-  Expect.isTrue(skip4.skip(2).skip(1) is! List);
+  Expect.isTrue(skip4 is List);
+  Expect.isTrue(skip4.skip(2).skip(1) is List);
   it = skip4.iterator;
   Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
@@ -102,8 +102,8 @@
   Expect.isNull(it.current);
 
   skip0 = list2.skip(0);
-  Expect.isTrue(skip0 is! List);
-  Expect.isTrue(skip0.skip(2).skip(1) is! List);
+  Expect.isTrue(skip0 is List);
+  Expect.isTrue(skip0.skip(2).skip(1) is List);
   it = skip0.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -114,8 +114,8 @@
   Expect.isNull(it.current);
 
   skip1 = list2.skip(1);
-  Expect.isTrue(skip1 is! List);
-  Expect.isTrue(skip1.skip(2).skip(1) is! List);
+  Expect.isTrue(skip1 is List);
+  Expect.isTrue(skip1.skip(2).skip(1) is List);
   it = skip1.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -124,32 +124,32 @@
   Expect.isNull(it.current);
 
   skip2 = list2.skip(2);
-  Expect.isTrue(skip2 is! List);
-  Expect.isTrue(skip2.skip(2).skip(1) is! List);
+  Expect.isTrue(skip2 is List);
+  Expect.isTrue(skip2.skip(2).skip(1) is List);
   it = skip2.iterator;
   Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
   Expect.isNull(it.current);
 
   skip3 = list2.skip(3);
-  Expect.isTrue(skip3 is! List);
-  Expect.isTrue(skip3.skip(2).skip(1) is! List);
+  Expect.isTrue(skip3 is List);
+  Expect.isTrue(skip3.skip(2).skip(1) is List);
   it = skip3.iterator;
   Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
   Expect.isNull(it.current);
 
   Iterable<String> skip02 = list3.skip(0);
-  Expect.isTrue(skip02 is! List);
-  Expect.isTrue(skip02.skip(2).skip(1) is! List);
+  Expect.isTrue(skip02 is List);
+  Expect.isTrue(skip02.skip(2).skip(1) is List);
   Iterator<String> it2 = skip02.iterator;
   Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
   Expect.isNull(it2.current);
 
   Iterable<String> skip12 = list3.skip(1);
-  Expect.isTrue(skip12 is! List);
-  Expect.isTrue(skip12.skip(2).skip(1) is! List);
+  Expect.isTrue(skip12 is List);
+  Expect.isTrue(skip12.skip(2).skip(1) is List);
   it2 = skip12.iterator;
   Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
diff --git a/tests/corelib/iterable_take_test.dart b/tests/corelib/iterable_take_test.dart
index 3910769..c775c52 100644
--- a/tests/corelib/iterable_take_test.dart
+++ b/tests/corelib/iterable_take_test.dart
@@ -13,12 +13,16 @@
   Set set2 = new Set();
 
   Iterable<int> take0 = list1.take(0);
+  Expect.isTrue(take0 is List);
+  Expect.isTrue(take0.take(2).take(1) is List);
   Iterator<int> it = take0.iterator;
   Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
   Expect.isNull(it.current);
 
   Iterable<int> take1 = list1.take(1);
+  Expect.isTrue(take1 is List);
+  Expect.isTrue(take1.take(2).take(1) is List);
   it = take1.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -28,6 +32,8 @@
 
   Iterable<int> take2 = list1.take(2);
   it = take2.iterator;
+  Expect.isTrue(take2 is List);
+  Expect.isTrue(take2.take(2).take(1) is List);
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
   Expect.equals(1, it.current);
@@ -37,6 +43,8 @@
   Expect.isNull(it.current);
 
   Iterable<int> take3 = list1.take(3);
+  Expect.isTrue(take3 is List);
+  Expect.isTrue(take3.take(2).take(1) is List);
   it = take3.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -49,6 +57,8 @@
   Expect.isNull(it.current);
 
   Iterable<int> take4 = list1.take(4);
+  Expect.isTrue(take4 is List);
+  Expect.isTrue(take4.take(2).take(1) is List);
   it = take4.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -105,12 +115,16 @@
   Expect.isNull(it.current);
 
   take0 = list2.take(0);
+  Expect.isTrue(take0 is List);
+  Expect.isTrue(take0.take(2).take(1) is List);
   it = take0.iterator;
   Expect.isNull(it.current);
   Expect.isFalse(it.moveNext());
   Expect.isNull(it.current);
 
   take1 = list2.take(1);
+  Expect.isTrue(take1 is List);
+  Expect.isTrue(take1.take(2).take(1) is List);
   it = take1.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -119,6 +133,8 @@
   Expect.isNull(it.current);
 
   take2 = list2.take(2);
+  Expect.isTrue(take2 is List);
+  Expect.isTrue(take2.take(2).take(1) is List);
   it = take2.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -129,6 +145,8 @@
   Expect.isNull(it.current);
 
   take3 = list2.take(3);
+  Expect.isTrue(take3 is List);
+  Expect.isTrue(take3.take(2).take(1) is List);
   it = take3.iterator;
   Expect.isNull(it.current);
   Expect.isTrue(it.moveNext());
@@ -139,12 +157,16 @@
   Expect.isNull(it.current);
 
   Iterable<String> take02 = list3.take(0);
+  Expect.isTrue(take02 is List);
+  Expect.isTrue(take02.take(2).take(1) is List);
   Iterator<String> it2 = take02.iterator;
   Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
   Expect.isNull(it2.current);
 
   Iterable<String> take12 = list3.take(1);
+  Expect.isTrue(take12 is List);
+  Expect.isTrue(take12.take(2).take(1) is List);
   it2 = take12.iterator;
   Expect.isNull(it2.current);
   Expect.isFalse(it2.moveNext());
diff --git a/tests/corelib/list_reversed_test.dart b/tests/corelib/list_reversed_test.dart
index dda5b56..03b99ce 100644
--- a/tests/corelib/list_reversed_test.dart
+++ b/tests/corelib/list_reversed_test.dart
@@ -7,11 +7,6 @@
   testOperations();
 }
 
-class ThrowMarker {
-  const ThrowMarker();
-  String toString() => "<<THROWS>>";
-}
-
 void testOperations() {
   // Comparison lists.
   List l = const [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
@@ -19,116 +14,27 @@
   // A base list that starts out like l.
   List base = l.toList();
   // A lazy reverse of base.
-  Iterable reversed = base.reversed;
+  List reversed = base.reversed;
 
-  Expect.listEquals(r, reversed.toList());
-  Expect.listEquals(l, reversed.toList().reversed.toList());
+  Expect.listEquals(r, reversed);
+  Expect.listEquals(l, reversed.reversed);
   for (int i = 0; i < r.length; i++) {
-    Expect.equals(r[i], reversed.elementAt(i));
+    Expect.equals(r[i], reversed[i]);
   }
   Expect.equals(4, base.indexOf(5));
-  Expect.equals(5, reversed.toList().indexOf(5));
+  Expect.equals(5, reversed.indexOf(5));
 
-  // Reversed followed by combinations of skip and take.
+  // Combinations of start and end relative to start/end of list.
   List subr = [8, 7, 6, 5, 4, 3];
-  Expect.listEquals(subr, reversed.skip(2).take(6).toList());
-  Expect.listEquals(subr, reversed.take(8).skip(2).toList());
-  Expect.listEquals(subr,
-      reversed.toList().reversed.skip(2).take(6).toList().reversed.toList());
-  Expect.listEquals(subr,
-      reversed.toList().reversed.take(8).skip(2).toList().reversed.toList());
-  Expect.listEquals(subr,
-      reversed.take(8).toList().reversed.take(6).toList().reversed.toList());
-  Expect.listEquals(subr,
-      reversed.toList().reversed.take(8).toList().reversed.take(6).toList());
-  Expect.listEquals(subr,
-      reversed.toList().reversed.skip(2).toList().reversed.skip(2).toList());
-  Expect.listEquals(subr,
-      reversed.skip(2).toList().reversed.skip(2).toList().reversed.toList());
-
-
-  void testList(List list) {
-    var throws = const ThrowMarker();
-    void testEquals(v1, v2, path) {
-      if (v1 is Iterable) {
-        Iterator i1 = v1.iterator;
-        Iterator i2 = v2.iterator;
-        int index = 0;
-        while (i1.moveNext()) {
-          Expect.isTrue(i2.moveNext(),
-              "Too few actual values. Expected[$index] == ${i1.current}");
-          testEquals(i1.current, i2.current, "$path[$index]");
-          index++;
-        }
-        Expect.isFalse(i2.moveNext(),
-              "Too many actual values. Actual[$index] == ${i2.current}");
-      } else {
-        Expect.equals(v1, v2, path);
-      }
-    }
-
-    void testOp(operation(Iterable reversedList), name) {
-      List reversedList = new List(list.length);
-      for (int i = 0; i < list.length; i++) {
-        reversedList[i] = list[list.length - 1 - i];
-      }
-      Iterable reversed = list.reversed;
-      var expect;
-      try {
-        expect = operation(reversedList);
-      } catch (e) {
-        expect = throws;
-      }
-      var actual;
-      try {
-        actual = operation(reversed);
-      } catch (e) {
-        actual = throws;
-      }
-      testEquals(expect, actual, "$name: $list");
-    }
-    testOp((i) => i.first, "first");
-    testOp((i) => i.last, "last");
-    testOp((i) => i.single, "single");
-    testOp((i) => i.firstMatching((n) => n < 5), "firstMatching<5");
-    testOp((i) => i.firstMatching((n) => n < 10), "firstMatching<10");
-    testOp((i) => i.lastMatching((n) => n < 5), "lastMatching<5");
-    testOp((i) => i.lastMatching((n) => n < 10), "lastMatching<10");
-    testOp((i) => i.singleMatching((n) => n < 5), "singelMatching<5");
-    testOp((i) => i.singleMatching((n) => n < 10), "singelMatching<10");
-    testOp((i) => i.contains(5), "contains(5)");
-    testOp((i) => i.contains(10), "contains(10)");
-    testOp((i) => i.any((n) => n < 5), "any<5");
-    testOp((i) => i.any((n) => n < 10), "any<10");
-    testOp((i) => i.every((n) => n < 5), "every<5");
-    testOp((i) => i.every((n) => n < 10), "every<10");
-    testOp((i) => i.max(), "max");
-    testOp((i) => i.min(), "min");
-    testOp((i) => i.reduce(0, (a, b) => a + b), "reduce-sum");
-    testOp((i) => i.join("-"), "join-");
-    testOp((i) => i.join(""), "join");
-    testOp((i) => i.join(), "join-null");
-    testOp((i) => i.map((n) => n * 2), "map*2");
-    testOp((i) => i.where((n) => n < 5), "where<5");
-    testOp((i) => i.where((n) => n < 10), "where<10");
-    testOp((i) => i.expand((n) => []), "expand[]");
-    testOp((i) => i.expand((n) => [n]), "expand[n]");
-    testOp((i) => i.expand((n) => [n, n]), "expand[n, n]");
-  }
-
-  // Combinations of lists with 0, 1 and more elements.
-  testList([]);
-  testList([0]);
-  testList([10]);
-  testList([0, 1]);
-  testList([0, 10]);
-  testList([10, 11]);
-  testList([0, 5, 10]);
-  testList([10, 5, 0]);
-  testList([0, 1, 2, 3]);
-  testList([3, 4, 5, 6]);
-  testList([10, 11, 12, 13]);
+  Expect.listEquals(subr, reversed.skip(2).take(6));
+  Expect.listEquals(subr, reversed.take(8).skip(2));
+  Expect.listEquals(subr, reversed.reversed.skip(2).take(6).reversed);
+  Expect.listEquals(subr, reversed.reversed.take(8).skip(2).reversed);
+  Expect.listEquals(subr, reversed.take(8).reversed.take(6).reversed);
+  Expect.listEquals(subr, reversed.reversed.take(8).reversed.take(6));
+  Expect.listEquals(subr, reversed.reversed.skip(2).reversed.skip(2));
+  Expect.listEquals(subr, reversed.skip(2).reversed.skip(2).reversed);
 
   // Reverse const list.
-  Expect.listEquals(r, l.reversed.toList());
+  Expect.listEquals(r, l.reversed);
 }
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index cbaa158..9652300 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -45,7 +45,6 @@
 
 [ $runtime == vm && $system == windows ]
 io/file_system_links_test: Skip  # No links on Windows.
-io/socket_stream_close_test: Fail, Pass # Issue 8556.
 
 [ $compiler == none && $runtime == drt ]
 io/*: Skip # Don't run tests using dart:io in the browser
diff --git a/tools/VERSION b/tools/VERSION
index 453bc99..9ad9fa1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
-MINOR 1
-BUILD 2
-PATCH 0
+MINOR 3
+BUILD 7
+PATCH 1
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 5e5f0fc..791b1ab 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -149,7 +149,7 @@
     }
   }
 
-  Iterable<Element> get reversed {
+  List<Element> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
@@ -383,7 +383,7 @@
     throw new UnsupportedError('');
   }
 
-  Iterable<Element> get reversed {
+  List<Element> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate
index 4f8e0e5..ceeb922 100644
--- a/tools/dom/templates/html/impl/impl_Node.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -200,7 +200,7 @@
     return this[index];
   }
 
-  Iterable<Node> get reversed {
+  List<Node> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }
 
diff --git a/tools/dom/templates/immutable_list_mixin.darttemplate b/tools/dom/templates/immutable_list_mixin.darttemplate
index 3ec2b79..2c8bf68 100644
--- a/tools/dom/templates/immutable_list_mixin.darttemplate
+++ b/tools/dom/templates/immutable_list_mixin.darttemplate
@@ -107,7 +107,7 @@
   // clear() defined by IDL.
 $endif
 
-  Iterable<$E> get reversed {
+  List<$E> get reversed {
     return IterableMixinWorkaround.reversedList(this);
   }