Version 0.3.5.0 .

svn merge -r 18113:18264 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@18267 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/compiler/java/com/google/dart/compiler/SystemLibraryManager.java b/compiler/java/com/google/dart/compiler/SystemLibraryManager.java
index 63626bc..a86558e 100644
--- a/compiler/java/com/google/dart/compiler/SystemLibraryManager.java
+++ b/compiler/java/com/google/dart/compiler/SystemLibraryManager.java
@@ -138,7 +138,10 @@
     HashSet<String> explicitShortNames = new HashSet<String>();
     
     for (Entry<String, DartLibrary> entry : declaredLibraries.entrySet()) {
-      if (entry.getValue().getCategory().equals("Internal")){
+      if (entry.getValue().getCategory().equals("Internal")
+          // TODO(8365): the following line allows dart:_collection-dev to
+          // be imported even though it's a hidden library.
+          && !entry.getKey().equals("dart:_collection-dev")) {
         continue;
       }
       String shortName = entry.getKey().trim();
diff --git a/compiler/javatests/com/google/dart/compiler/DartCompilerListenerTest.java b/compiler/javatests/com/google/dart/compiler/DartCompilerListenerTest.java
index ec97e7a..c6fbf39 100644
--- a/compiler/javatests/com/google/dart/compiler/DartCompilerListenerTest.java
+++ b/compiler/javatests/com/google/dart/compiler/DartCompilerListenerTest.java
@@ -4,6 +4,8 @@
 
 package com.google.dart.compiler;
 
+import com.google.dart.compiler.resolver.TypeErrorCode;
+
 /**
  * Testing implementation of {@link DartCompilerListener}.
  */
@@ -49,6 +51,11 @@
 
   @Override
   public void onError(DartCompilationError event) {
+    // ignore deprecated
+    if (event.getErrorCode() == TypeErrorCode.DEPRECATED_ELEMENT) {
+      return;
+    }
+    // validate
     String reportedSrcName = (event.getSource() != null)
         ? event.getSource().getName()
         : null;
diff --git a/pkg/analyzer-experimental/README b/pkg/analyzer-experimental/README.md
similarity index 100%
rename from pkg/analyzer-experimental/README
rename to pkg/analyzer-experimental/README.md
diff --git a/pkg/http/lib/src/multipart_request.dart b/pkg/http/lib/src/multipart_request.dart
index 9bb1c46..b311b8e 100644
--- a/pkg/http/lib/src/multipart_request.dart
+++ b/pkg/http/lib/src/multipart_request.dart
@@ -73,7 +73,7 @@
   ///
   /// This doesn't need to be closed. When the request is sent, whichever files
   /// are written to this sink at that point will be used.
-  Sink<MultipartFile> get files => _files;
+  StreamSink<MultipartFile> get files => _files;
 
   /// The private version of [files], typed so that the underlying collection is
   /// accessible.
diff --git a/pkg/http/lib/src/streamed_request.dart b/pkg/http/lib/src/streamed_request.dart
index a87d27b..b313f68 100644
--- a/pkg/http/lib/src/streamed_request.dart
+++ b/pkg/http/lib/src/streamed_request.dart
@@ -24,7 +24,7 @@
   /// buffered.
   ///
   /// Closing this signals the end of the request.
-  Sink<List<int>> get sink => _controller.sink;
+  StreamSink<List<int>> get sink => _controller.sink;
 
   /// The controller for [sink], from which [BaseRequest] will read data for
   /// [finalize].
diff --git a/pkg/unittest/coverage_controller.js b/pkg/unittest/lib/coverage_controller.js
similarity index 100%
rename from pkg/unittest/coverage_controller.js
rename to pkg/unittest/lib/coverage_controller.js
diff --git a/pkg/unittest/lib/src/basematcher.dart b/pkg/unittest/lib/src/basematcher.dart
index 2859336..a74928c 100644
--- a/pkg/unittest/lib/src/basematcher.dart
+++ b/pkg/unittest/lib/src/basematcher.dart
@@ -23,10 +23,9 @@
 
 /**
  * BaseMatcher is the base class for all matchers. To implement a new
- * matcher, either add a class that implements from IMatcher or
- * a class that inherits from Matcher. Inheriting from Matcher has
- * the benefit that a default implementation of describeMismatch will
- * be provided.
+ * matcher, either add a class that implements Matcher or a class that
+ * extends BaseMatcher. Extending BaseMatcher has the benefit that a
+ * default implementation of describeMismatch will be provided.
  */
 abstract class BaseMatcher implements Matcher {
   const BaseMatcher();
diff --git a/pkg/unittest/lib/src/core_matchers.dart b/pkg/unittest/lib/src/core_matchers.dart
index 489fecd..449990b 100644
--- a/pkg/unittest/lib/src/core_matchers.dart
+++ b/pkg/unittest/lib/src/core_matchers.dart
@@ -632,14 +632,16 @@
 
 /**
  * Returns a matcher that uses an arbitrary function that returns
- * true or false for the actual value.
+ * true or false for the actual value. For example:
+ *
+ *     expect(v, predicate((x) => ((x % 2) == 0), "is even"))
  */
-Matcher predicate(f, [description ='satisfies function']) =>
+Matcher predicate(Function f, [description ='satisfies function']) =>
     new _Predicate(f, description);
 
 class _Predicate extends BaseMatcher {
 
-  final _matcher;
+  final Function _matcher;
   final String _description;
 
   const _Predicate(this._matcher, this._description);
diff --git a/pkg/unittest/test_controller.js b/pkg/unittest/lib/test_controller.js
similarity index 100%
rename from pkg/unittest/test_controller.js
rename to pkg/unittest/lib/test_controller.js
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index ea44bea..0bd231d 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -468,7 +468,7 @@
  * tracked and reported. [callback] should take between 0 and 4 positional
  * arguments (named arguments are not supported here).
  */
-Function _expectAsync(Function callback, [int count = 1]) {
+Function _expectAsync(Function callback, {int count: 1}) {
   return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke;
 }
 
@@ -481,7 +481,7 @@
  * arguments are not supported).
  */
 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function expectAsync0(Function callback, [int count = 1]) {
+Function expectAsync0(Function callback, {int count: 1}) {
   return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke0;
 }
 
@@ -493,7 +493,7 @@
 
 /** Like [expectAsync0] but [callback] should take 2 positional arguments. */
 // TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function expectAsync2(Function callback, [int count = 1]) {
+Function expectAsync2(Function callback, {int count: 1}) {
   return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke2;
 }
 
diff --git a/pkg/unittest/static/coverage_controller.js b/pkg/unittest/static/coverage_controller.js
deleted file mode 100644
index 78ddb9d..0000000
--- a/pkg/unittest/static/coverage_controller.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2011, 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.
-
-/**
- * Coverage controller logic - used by coverage test harness to embed tests in
- * DumpRenderTree and extract coverage information.
- */
-
-var LONG_LINE = 60000;
-
-function onReceive(e) {
-  if (e.data == 'unittest-suite-done') {
-    var s = JSON.stringify(top._$jscoverage);
-    var res = '';
-    // DumpRenderTree has a bug on lines longer than 2^16, so we split them
-    while (s.length > LONG_LINE) {
-      res += s.substr(0, LONG_LINE) + '<br>\n';
-      s = s.substr(LONG_LINE);
-    }
-    res += s;
-    window.document.body.innerHTML = res;
-    window.layoutTestController.notifyDone();
-  }
-}
-
-if (window.layoutTestController) {
-  window.layoutTestController.dumpAsText();
-  window.layoutTestController.waitUntilDone();
-  window.addEventListener("message", onReceive, false);
-}
diff --git a/pkg/unittest/static/test_controller.js b/pkg/unittest/static/test_controller.js
deleted file mode 100644
index b5734b9..0000000
--- a/pkg/unittest/static/test_controller.js
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2011, 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.
-
-/**
- * Test controller logic - used by unit test harness to embed tests in
- * DumpRenderTree.
- */
-
-if (navigator.webkitStartDart) {
-  navigator.webkitStartDart();
-}
-
-// testRunner is provided by DRT or WebKit's layout tests.
-// It is not available in selenium tests.
-var testRunner = window.testRunner || window.layoutTestController;
-
-var waitForDone = false;
-
-function processMessage(msg) {
-  if (typeof msg != 'string') return;
-  if (msg == 'unittest-suite-done') {
-    if (testRunner) testRunner.notifyDone();
-  } else if (msg == 'unittest-suite-wait-for-done') {
-    waitForDone = true;
-    if (testRunner) testRunner.startedDartTest = true;
-  } else if (msg == 'dart-calling-main') {
-    if (testRunner) testRunner.startedDartTest = true;
-  } else if (msg == 'dart-main-done') {
-    if (!waitForDone) {
-      window.postMessage('unittest-suite-success', '*');
-    }
-  } else if (msg == 'unittest-suite-success') {
-    dartPrint('PASS');
-    if (testRunner) testRunner.notifyDone();
-  } else if (msg == 'unittest-suite-fail') {
-    showErrorAndExit('Some tests failed.');
-  }
-}
-
-function onReceive(e) {
-  processMessage(e.data);
-}
-
-if (testRunner) {
-  testRunner.dumpAsText();
-  testRunner.waitUntilDone();
-}
-window.addEventListener("message", onReceive, false);
-
-function showErrorAndExit(message) {
-  if (message) {
-    dartPrint('Error: ' + String(message));
-  }
-  // dart/tools/testing/run_selenium.py is looking for either PASS or
-  // FAIL and will continue polling until one of these words show up.
-  dartPrint('FAIL');
-  if (testRunner) testRunner.notifyDone();
-}
-
-function onLoad(e) {
-  // needed for dartium compilation errors.
-  if (window.compilationError) {
-    showErrorAndExit(window.compilationError);
-  }
-}
-
-window.addEventListener("DOMContentLoaded", onLoad, false);
-
-// If nobody intercepts the error, finish the test.
-window.addEventListener("error", function(e) {
-  // needed for dartium compilation errors.
-  showErrorAndExit(e && e.message);
-}, false);
-
-document.addEventListener('readystatechange', function () {
-  if (document.readyState != "loaded") return;
-  // If 'startedDartTest' is not set, that means that the test did not have
-  // a chance to load. This will happen when a load error occurs in the VM.
-  // Give the machine time to start up.
-  setTimeout(function() {
-    // A window.postMessage might have been enqueued after this timeout.
-    // Just sleep another time to give the browser the time to process the
-    // posted message.
-    setTimeout(function() {
-      if (testRunner && !testRunner.startedDartTest) {
-        testRunner.notifyDone();
-      }
-    }, 0);
-  }, 50);
-});
-
-// dart2js will generate code to call this function to handle the Dart
-// [print] method. The base [Configuration] (config.html) calls
-// [print] with the secret messages "unittest-suite-success" and
-// "unittest-suite-wait-for-done". These messages are then posted so
-// processMessage above will see them.
-function dartPrint(msg) {
-  if ((msg === 'unittest-suite-success')
-      || (msg === 'unittest-suite-wait-for-done')) {
-    window.postMessage(msg, '*');
-    return;
-  }
-  var pre = document.createElement("pre");
-  pre.appendChild(document.createTextNode(String(msg)));
-  document.body.appendChild(pre);
-}
-
-// dart2js will generate code to call this function instead of calling
-// Dart [main] directly. The argument is a closure that invokes main.
-function dartMainRunner(main) {
-  window.postMessage('dart-calling-main', '*');
-  try {
-    main();
-  } catch (e) {
-    window.postMessage('unittest-suite-fail', '*');
-    return;
-  }
-  window.postMessage('dart-main-done', '*');
-}
diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
index 25d465d..583d737 100644
--- a/runtime/bin/dbg_connection.cc
+++ b/runtime/bin/dbg_connection.cc
@@ -264,7 +264,7 @@
 
 void DebuggerConnectionHandler::CloseDbgConnection() {
   if (debug_fd_ >= 0) {
-    // TODO(hausner): need a Socket::Close() function.
+    Socket::Close(debug_fd_);
   }
   if (msgbuf_ != NULL) {
     delete msgbuf_;
diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc
index f3f471f..8b40073 100644
--- a/runtime/bin/directory_android.cc
+++ b/runtime/bin/directory_android.cc
@@ -6,6 +6,7 @@
 
 #include <dirent.h>
 #include <errno.h>
+#include <string.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -13,12 +14,36 @@
 #include "bin/file.h"
 #include "bin/platform.h"
 
+class PathBuffer {
+ public:
+  PathBuffer() : length(0) { }
 
-static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
-  strncpy(dest, src, n);
-  dest[n - 1] = '\0';
-  return dest;
-}
+
+
+  char data[PATH_MAX + 1];
+  int length;
+
+  bool Add(const char* name) {
+    size_t written = snprintf(data + length,
+                              PATH_MAX - length,
+                              "%s",
+                              name);
+    data[PATH_MAX] = '\0';
+    if (written == strnlen(name, PATH_MAX + 1)) {
+      length += written;
+      return true;
+    } else {
+      errno = ENAMETOOLONG;
+      return false;
+    }
+  }
+
+  void Reset(int new_length) {
+    length = new_length;
+    data[length] = '\0';
+  }
+};
+
 
 
 // Forward declarations.
@@ -28,76 +53,56 @@
 static bool DeleteRecursively(const char* dir_name);
 
 
-static bool ComputeFullPath(const char* dir_name,
-                            char* path,
-                            int* path_length) {
-  char* abs_path;
-  do {
-    abs_path = realpath(dir_name, path);
-  } while (abs_path == NULL && errno == EINTR);
-  if (abs_path == NULL) {
-    return false;
-  }
-  *path_length = strlen(path);
-  size_t written = snprintf(path + *path_length,
-                            PATH_MAX - *path_length,
-                            "%s",
-                            File::PathSeparator());
-  if (written != strlen(File::PathSeparator())) {
-    return false;
-  }
-  *path_length += written;
-  return true;
-}
-
-
-static bool HandleDir(char* dir_name,
-                      char* path,
-                      int path_length,
-                      bool recursive,
-                      DirectoryListing *listing) {
-  if (strcmp(dir_name, ".") != 0 &&
-      strcmp(dir_name, "..") != 0) {
-    size_t written = snprintf(path + path_length,
-                              PATH_MAX - path_length,
-                              "%s",
-                              dir_name);
-    if (written != strlen(dir_name)) {
-      return false;
-    }
-    bool ok = listing->HandleDirectory(path);
-    if (!ok) return ok;
-    if (recursive) {
-      return ListRecursively(path, recursive, listing);
-    }
-  }
-  return true;
-}
-
-
-static bool HandleFile(char* file_name,
-                       char* path,
-                       int path_length,
-                       DirectoryListing *listing) {
-  // TODO(sgjesse): Pass flags to indicate whether file responses are
-  // needed.
-  size_t written = snprintf(path + path_length,
-                            PATH_MAX - path_length,
-                            "%s",
-                            file_name);
-  if (written != strlen(file_name)) {
-    return false;
-  }
-  return listing->HandleFile(path);
-}
-
-
 static void PostError(DirectoryListing *listing,
                       const char* dir_name) {
   listing->HandleError(dir_name);
 }
 
 
+static PathBuffer* ComputeFullPath(const char* dir_name) {
+  PathBuffer* path = new PathBuffer();
+  char* abs_path;
+  do {
+    abs_path = realpath(dir_name, path->data);
+  } while (abs_path == NULL && errno == EINTR);
+  if (abs_path == NULL) {
+    delete path;
+    return NULL;
+  }
+  path->length = strnlen(path->data, PATH_MAX);
+  if (path->Add(File::PathSeparator())) {
+    return path;
+  } else {
+    delete path;
+    return NULL;
+  }
+}
+
+static bool HandleDir(char* dir_name,
+                      PathBuffer* path,
+                      bool recursive,
+                      DirectoryListing *listing) {
+  if (strcmp(dir_name, ".") == 0) return true;
+  if (strcmp(dir_name, "..") == 0) return true;
+  if (!path->Add(dir_name)) {
+    PostError(listing, path->data);
+    return false;
+  }
+  return listing->HandleDirectory(path->data) &&
+      (!recursive || ListRecursively(path->data, recursive, listing));
+}
+
+static bool HandleFile(char* file_name,
+                       PathBuffer* path,
+                       DirectoryListing *listing) {
+  if (!path->Add(file_name)) {
+    PostError(listing, path->data);
+    return false;
+  }
+  return listing->HandleFile(path->data);
+}
+
+
 static bool ListRecursively(const char* dir_name,
                             bool recursive,
                             DirectoryListing *listing) {
@@ -115,38 +120,32 @@
   // recursive traversal. path_length does not always equal
   // strlen(path) but indicates the current prefix of path that is the
   // path of the current directory in the traversal.
-  char *path = static_cast<char*>(malloc(PATH_MAX));
-  ASSERT(path != NULL);
-  int path_length = 0;
-  bool valid = ComputeFullPath(dir_name, path, &path_length);
-  if (!valid) {
-    free(path);
+  PathBuffer* path = ComputeFullPath(dir_name);
+  if (path == NULL) {
     PostError(listing, dir_name);
     return false;
   }
-
-  // Iterated the directory and post the directories and files to the
+  // Iterate the directory and post the directories and files to the
   // ports.
-  int read = 0;
+  int path_length = path->length;
+  int status = 0;
   bool success = true;
   dirent entry;
   dirent* result;
-  while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
-                                              &entry,
-                                              &result))) == 0 &&
+  while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
+                                                &entry,
+                                                &result))) == 0 &&
          result != NULL) {
     switch (entry.d_type) {
       case DT_DIR:
         success = HandleDir(entry.d_name,
                             path,
-                            path_length,
                             recursive,
                             listing) && success;
         break;
       case DT_REG:
         success = HandleFile(entry.d_name,
                              path,
-                             path_length,
                              listing) && success;
         break;
       case DT_LNK:
@@ -156,30 +155,25 @@
         // the actual entry type. Notice that stat returns the type of
         // the file pointed to.
         struct stat entry_info;
-        size_t written = snprintf(path + path_length,
-                                  PATH_MAX - path_length,
-                                  "%s",
-                                  entry.d_name);
-        if (written != strlen(entry.d_name)) {
+        if (!path->Add(entry.d_name)) {
           success = false;
           break;
         }
-        int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info));
+        int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
         if (stat_success == -1) {
           success = false;
-          PostError(listing, path);
+          PostError(listing, path->data);
           break;
         }
+        path->Reset(path_length);
         if (S_ISDIR(entry_info.st_mode)) {
           success = HandleDir(entry.d_name,
                               path,
-                              path_length,
                               recursive,
                               listing) && success;
         } else if (S_ISREG(entry_info.st_mode)) {
           success = HandleFile(entry.d_name,
                                path,
-                               path_length,
                                listing) && success;
         }
         ASSERT(!S_ISLNK(entry_info.st_mode));
@@ -188,10 +182,11 @@
       default:
         break;
     }
+    path->Reset(path_length);
   }
 
-  if (read != 0) {
-    errno = read;
+  if (status != 0) {
+    errno = status;
     success = false;
     PostError(listing, dir_name);
   }
@@ -200,41 +195,23 @@
     success = false;
     PostError(listing, dir_name);
   }
-  free(path);
+  delete path;
 
   return success;
 }
 
 
 static bool DeleteFile(char* file_name,
-                       char* path,
-                       int path_length) {
-  size_t written = snprintf(path + path_length,
-                            PATH_MAX - path_length,
-                            "%s",
-                            file_name);
-  if (written != strlen(file_name)) {
-    return false;
-  }
-  return (remove(path) == 0);
+                       PathBuffer* path) {
+  return path->Add(file_name) && remove(path->data) == 0;
 }
 
 
 static bool DeleteDir(char* dir_name,
-                      char* path,
-                      int path_length) {
-  if (strcmp(dir_name, ".") != 0 &&
-      strcmp(dir_name, "..") != 0) {
-    size_t written = snprintf(path + path_length,
-                              PATH_MAX - path_length,
-                              "%s",
-                              dir_name);
-    if (written != strlen(dir_name)) {
-      return false;
-    }
-    return DeleteRecursively(path);
-  }
-  return true;
+                      PathBuffer* path) {
+  if (strcmp(dir_name, ".") == 0) return true;
+  if (strcmp(dir_name, "..") == 0) return true;
+  return path->Add(dir_name) && DeleteRecursively(path->data);
 }
 
 
@@ -260,19 +237,12 @@
 
   // Compute full path for the directory currently being deleted.  The
   // path buffer will be used to construct the current path in the
-  // recursive traversal. path_length does not always equal
-  // strlen(path) but indicates the current prefix of path that is the
-  // path of the current directory in the traversal.
-  char *path = static_cast<char*>(malloc(PATH_MAX));
-  ASSERT(path != NULL);
-  int path_length = 0;
-  bool valid = ComputeFullPath(dir_name, path, &path_length);
-  if (!valid) {
-    free(path);
-    return false;
-  }
+  // recursive traversal.
+  PathBuffer* path = ComputeFullPath(dir_name);
+  if (path == NULL) return false;
 
   // Iterate the directory and delete all files and directories.
+  int path_length = path->length;
   int read = 0;
   bool success = true;
   dirent entry;
@@ -284,49 +254,46 @@
          success) {
     switch (entry.d_type) {
       case DT_DIR:
-        success = success && DeleteDir(entry.d_name, path, path_length);
+        success = success && DeleteDir(entry.d_name, path);
         break;
       case DT_REG:
       case DT_LNK:
         // Treat all links as files. This will delete the link which
         // is what we want no matter if the link target is a file or a
         // directory.
-        success = success && DeleteFile(entry.d_name, path, path_length);
+        success = success && DeleteFile(entry.d_name, path);
         break;
       case DT_UNKNOWN: {
         // On some file systems the entry type is not determined by
         // readdir_r. For those we use lstat to determine the entry
         // type.
         struct stat entry_info;
-        size_t written = snprintf(path + path_length,
-                                  PATH_MAX - path_length,
-                                  "%s",
-                                  entry.d_name);
-        if (written != strlen(entry.d_name)) {
+        if (!path->Add(entry.d_name)) {
           success = false;
           break;
         }
-        int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
+        int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
         if (lstat_success == -1) {
           success = false;
           break;
         }
+        path->Reset(path_length);
         if (S_ISDIR(entry_info.st_mode)) {
-          success = success && DeleteDir(entry.d_name, path, path_length);
+          success = success && DeleteDir(entry.d_name, path);
         } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
           // Treat links as files. This will delete the link which is
           // what we want no matter if the link target is a file or a
           // directory.
-          success = success && DeleteFile(entry.d_name, path, path_length);
+          success = success && DeleteFile(entry.d_name, path);
         }
         break;
       }
       default:
         break;
     }
+    path->Reset(path_length);
   }
-
-  free(path);
+  delete path;
 
   if ((read != 0) ||
       (closedir(dir_pointer) == -1) ||
@@ -393,7 +360,7 @@
   // process umask.
   int result = TEMP_FAILURE_RETRY(mkdir(dir_name, 0777));
   // If the directory already exists, treat it as a success.
-  if (result == -1 && errno == EEXISTS)  {
+  if (result == -1 && errno == EEXIST) {
     return (Exists(dir_name) == EXISTS);
   }
   return (result == 0);
@@ -418,16 +385,9 @@
   // dir_template.  Creates the directory with the permissions specified
   // by the process umask.
   // The return value must be freed by the caller.
-  char* path = static_cast<char*>(malloc(PATH_MAX + 1));
-  SafeStrNCpy(path, const_template, PATH_MAX + 1);
-  int path_length = strlen(path);
-  if (path_length > 0) {
-    if ((path)[path_length - 1] == '/') {
-      snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX");
-    } else {
-      snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX");
-    }
-  } else {
+  PathBuffer* path = new PathBuffer();
+  path->Add(const_template);
+  if (path->length == 0) {
     // Android does not have a /tmp directory. A partial substitute,
     // suitable for bring-up work and tests, is to create a tmp
     // directory in /data/local/tmp.
@@ -439,17 +399,29 @@
     if (stat(ANDROID_TEMP_DIR, &st) != 0) {
       mkdir(ANDROID_TEMP_DIR, 0777);
     }
-    snprintf(path, PATH_MAX, ANDROID_TEMP_DIR "/temp_dir1_XXXXXX");
+    path->Add(ANDROID_TEMP_DIR "/tmp/temp_dir1_");
+  } else if ((path->data)[path->length - 1] == '/') {
+    path->Add("temp_dir_");
+  }
+  if (!path->Add("XXXXXX")) {
+    // Pattern has overflowed.
+    delete path;
+    return NULL;
   }
   char* result;
   do {
-    result = MakeTempDirectory(path);
+    result = MakeTempDirectory(path->data);
   } while (result == NULL && errno == EINTR);
   if (result == NULL) {
-    free(path);
+    delete path;
     return NULL;
   }
-  return path;
+  int length = strnlen(path->data, PATH_MAX);
+  result = static_cast<char*>(malloc(length + 1));
+  strncpy(result, path->data, length);
+  result[length] = '\0';
+  delete path;
+  return result;
 }
 
 
diff --git a/runtime/bin/directory_linux.cc b/runtime/bin/directory_linux.cc
index 241fce2..7b94aac 100644
--- a/runtime/bin/directory_linux.cc
+++ b/runtime/bin/directory_linux.cc
@@ -6,6 +6,7 @@
 
 #include <dirent.h>
 #include <errno.h>
+#include <string.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -13,12 +14,35 @@
 #include "bin/file.h"
 #include "bin/platform.h"
 
+class PathBuffer {
+ public:
+  PathBuffer() : length(0) { }
 
-static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
-  strncpy(dest, src, n);
-  dest[n - 1] = '\0';
-  return dest;
-}
+
+
+  char data[PATH_MAX + 1];
+  int length;
+
+  bool Add(const char* name) {
+    size_t written = snprintf(data + length,
+                              PATH_MAX - length,
+                              "%s",
+                              name);
+    data[PATH_MAX] = '\0';
+    if (written == strnlen(name, PATH_MAX + 1)) {
+      length += written;
+      return true;
+    } else {
+      errno = ENAMETOOLONG;
+      return false;
+    }
+  }
+
+  void Reset(int new_length) {
+    length = new_length;
+    data[length] = '\0';
+  }
+};
 
 
 // Forward declarations.
@@ -28,76 +52,56 @@
 static bool DeleteRecursively(const char* dir_name);
 
 
-static bool ComputeFullPath(const char* dir_name,
-                            char* path,
-                            int* path_length) {
-  char* abs_path;
-  do {
-    abs_path = realpath(dir_name, path);
-  } while (abs_path == NULL && errno == EINTR);
-  if (abs_path == NULL) {
-    return false;
-  }
-  *path_length = strlen(path);
-  size_t written = snprintf(path + *path_length,
-                            PATH_MAX - *path_length,
-                            "%s",
-                            File::PathSeparator());
-  if (written != strlen(File::PathSeparator())) {
-    return false;
-  }
-  *path_length += written;
-  return true;
-}
-
-
-static bool HandleDir(char* dir_name,
-                      char* path,
-                      int path_length,
-                      bool recursive,
-                      DirectoryListing *listing) {
-  if (strcmp(dir_name, ".") != 0 &&
-      strcmp(dir_name, "..") != 0) {
-    size_t written = snprintf(path + path_length,
-                              PATH_MAX - path_length,
-                              "%s",
-                              dir_name);
-    if (written != strlen(dir_name)) {
-      return false;
-    }
-    bool ok = listing->HandleDirectory(path);
-    if (!ok) return ok;
-    if (recursive) {
-      return ListRecursively(path, recursive, listing);
-    }
-  }
-  return true;
-}
-
-
-static bool HandleFile(char* file_name,
-                       char* path,
-                       int path_length,
-                       DirectoryListing *listing) {
-  // TODO(sgjesse): Pass flags to indicate whether file responses are
-  // needed.
-  size_t written = snprintf(path + path_length,
-                            PATH_MAX - path_length,
-                            "%s",
-                            file_name);
-  if (written != strlen(file_name)) {
-    return false;
-  }
-  return listing->HandleFile(path);
-}
-
-
 static void PostError(DirectoryListing *listing,
                       const char* dir_name) {
   listing->HandleError(dir_name);
 }
 
 
+static PathBuffer* ComputeFullPath(const char* dir_name) {
+  PathBuffer* path = new PathBuffer();
+  char* abs_path;
+  do {
+    abs_path = realpath(dir_name, path->data);
+  } while (abs_path == NULL && errno == EINTR);
+  if (abs_path == NULL) {
+    delete path;
+    return NULL;
+  }
+  path->length = strnlen(path->data, PATH_MAX);
+  if (path->Add(File::PathSeparator())) {
+    return path;
+  } else {
+    delete path;
+    return NULL;
+  }
+}
+
+static bool HandleDir(char* dir_name,
+                      PathBuffer* path,
+                      bool recursive,
+                      DirectoryListing *listing) {
+  if (strcmp(dir_name, ".") == 0) return true;
+  if (strcmp(dir_name, "..") == 0) return true;
+  if (!path->Add(dir_name)) {
+    PostError(listing, path->data);
+    return false;
+  }
+  return listing->HandleDirectory(path->data) &&
+      (!recursive || ListRecursively(path->data, recursive, listing));
+}
+
+static bool HandleFile(char* file_name,
+                       PathBuffer* path,
+                       DirectoryListing *listing) {
+  if (!path->Add(file_name)) {
+    PostError(listing, path->data);
+    return false;
+  }
+  return listing->HandleFile(path->data);
+}
+
+
 static bool ListRecursively(const char* dir_name,
                             bool recursive,
                             DirectoryListing *listing) {
@@ -115,38 +119,32 @@
   // recursive traversal. path_length does not always equal
   // strlen(path) but indicates the current prefix of path that is the
   // path of the current directory in the traversal.
-  char *path = static_cast<char*>(malloc(PATH_MAX));
-  ASSERT(path != NULL);
-  int path_length = 0;
-  bool valid = ComputeFullPath(dir_name, path, &path_length);
-  if (!valid) {
-    free(path);
+  PathBuffer* path = ComputeFullPath(dir_name);
+  if (path == NULL) {
     PostError(listing, dir_name);
     return false;
   }
-
-  // Iterated the directory and post the directories and files to the
+  // Iterate the directory and post the directories and files to the
   // ports.
-  int read = 0;
+  int path_length = path->length;
+  int status = 0;
   bool success = true;
   dirent entry;
   dirent* result;
-  while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
-                                              &entry,
-                                              &result))) == 0 &&
+  while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
+                                                &entry,
+                                                &result))) == 0 &&
          result != NULL) {
     switch (entry.d_type) {
       case DT_DIR:
         success = HandleDir(entry.d_name,
                             path,
-                            path_length,
                             recursive,
                             listing) && success;
         break;
       case DT_REG:
         success = HandleFile(entry.d_name,
                              path,
-                             path_length,
                              listing) && success;
         break;
       case DT_LNK:
@@ -156,30 +154,25 @@
         // the actual entry type. Notice that stat returns the type of
         // the file pointed to.
         struct stat entry_info;
-        size_t written = snprintf(path + path_length,
-                                  PATH_MAX - path_length,
-                                  "%s",
-                                  entry.d_name);
-        if (written != strlen(entry.d_name)) {
+        if (!path->Add(entry.d_name)) {
           success = false;
           break;
         }
-        int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info));
+        int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
         if (stat_success == -1) {
           success = false;
-          PostError(listing, path);
+          PostError(listing, path->data);
           break;
         }
+        path->Reset(path_length);
         if (S_ISDIR(entry_info.st_mode)) {
           success = HandleDir(entry.d_name,
                               path,
-                              path_length,
                               recursive,
                               listing) && success;
         } else if (S_ISREG(entry_info.st_mode)) {
           success = HandleFile(entry.d_name,
                                path,
-                               path_length,
                                listing) && success;
         }
         ASSERT(!S_ISLNK(entry_info.st_mode));
@@ -188,10 +181,11 @@
       default:
         break;
     }
+    path->Reset(path_length);
   }
 
-  if (read != 0) {
-    errno = read;
+  if (status != 0) {
+    errno = status;
     success = false;
     PostError(listing, dir_name);
   }
@@ -200,41 +194,23 @@
     success = false;
     PostError(listing, dir_name);
   }
-  free(path);
+  delete path;
 
   return success;
 }
 
 
 static bool DeleteFile(char* file_name,
-                       char* path,
-                       int path_length) {
-  size_t written = snprintf(path + path_length,
-                            PATH_MAX - path_length,
-                            "%s",
-                            file_name);
-  if (written != strlen(file_name)) {
-    return false;
-  }
-  return (remove(path) == 0);
+                       PathBuffer* path) {
+  return path->Add(file_name) && remove(path->data) == 0;
 }
 
 
 static bool DeleteDir(char* dir_name,
-                      char* path,
-                      int path_length) {
-  if (strcmp(dir_name, ".") != 0 &&
-      strcmp(dir_name, "..") != 0) {
-    size_t written = snprintf(path + path_length,
-                              PATH_MAX - path_length,
-                              "%s",
-                              dir_name);
-    if (written != strlen(dir_name)) {
-      return false;
-    }
-    return DeleteRecursively(path);
-  }
-  return true;
+                      PathBuffer* path) {
+  if (strcmp(dir_name, ".") == 0) return true;
+  if (strcmp(dir_name, "..") == 0) return true;
+  return path->Add(dir_name) && DeleteRecursively(path->data);
 }
 
 
@@ -260,19 +236,12 @@
 
   // Compute full path for the directory currently being deleted.  The
   // path buffer will be used to construct the current path in the
-  // recursive traversal. path_length does not always equal
-  // strlen(path) but indicates the current prefix of path that is the
-  // path of the current directory in the traversal.
-  char *path = static_cast<char*>(malloc(PATH_MAX));
-  ASSERT(path != NULL);
-  int path_length = 0;
-  bool valid = ComputeFullPath(dir_name, path, &path_length);
-  if (!valid) {
-    free(path);
-    return false;
-  }
+  // recursive traversal.
+  PathBuffer* path = ComputeFullPath(dir_name);
+  if (path == NULL) return false;
 
   // Iterate the directory and delete all files and directories.
+  int path_length = path->length;
   int read = 0;
   bool success = true;
   dirent entry;
@@ -284,49 +253,46 @@
          success) {
     switch (entry.d_type) {
       case DT_DIR:
-        success = success && DeleteDir(entry.d_name, path, path_length);
+        success = success && DeleteDir(entry.d_name, path);
         break;
       case DT_REG:
       case DT_LNK:
         // Treat all links as files. This will delete the link which
         // is what we want no matter if the link target is a file or a
         // directory.
-        success = success && DeleteFile(entry.d_name, path, path_length);
+        success = success && DeleteFile(entry.d_name, path);
         break;
       case DT_UNKNOWN: {
         // On some file systems the entry type is not determined by
         // readdir_r. For those we use lstat to determine the entry
         // type.
         struct stat entry_info;
-        size_t written = snprintf(path + path_length,
-                                  PATH_MAX - path_length,
-                                  "%s",
-                                  entry.d_name);
-        if (written != strlen(entry.d_name)) {
+        if (!path->Add(entry.d_name)) {
           success = false;
           break;
         }
-        int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
+        int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
         if (lstat_success == -1) {
           success = false;
           break;
         }
+        path->Reset(path_length);
         if (S_ISDIR(entry_info.st_mode)) {
-          success = success && DeleteDir(entry.d_name, path, path_length);
+          success = success && DeleteDir(entry.d_name, path);
         } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
           // Treat links as files. This will delete the link which is
           // what we want no matter if the link target is a file or a
           // directory.
-          success = success && DeleteFile(entry.d_name, path, path_length);
+          success = success && DeleteFile(entry.d_name, path);
         }
         break;
       }
       default:
         break;
     }
+    path->Reset(path_length);
   }
-
-  free(path);
+  delete path;
 
   if ((read != 0) ||
       (closedir(dir_pointer) == -1) ||
@@ -397,27 +363,32 @@
   // dir_template.  Creates the directory with the permissions specified
   // by the process umask.
   // The return value must be freed by the caller.
-  char* path = static_cast<char*>(malloc(PATH_MAX + 1));
-  SafeStrNCpy(path, const_template, PATH_MAX + 1);
-  int path_length = strlen(path);
-  if (path_length > 0) {
-    if ((path)[path_length - 1] == '/') {
-      snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX");
-    } else {
-      snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX");
-    }
-  } else {
-    snprintf(path, PATH_MAX, "/tmp/temp_dir1_XXXXXX");
+  PathBuffer* path = new PathBuffer();
+  path->Add(const_template);
+  if (path->length == 0) {
+    path->Add("/tmp/temp_dir1_");
+  } else if ((path->data)[path->length - 1] == '/') {
+    path->Add("temp_dir_");
+  }
+  if (!path->Add("XXXXXX")) {
+    // Pattern has overflowed.
+    delete path;
+    return NULL;
   }
   char* result;
   do {
-    result = mkdtemp(path);
+    result = mkdtemp(path->data);
   } while (result == NULL && errno == EINTR);
   if (result == NULL) {
-    free(path);
+    delete path;
     return NULL;
   }
-  return path;
+  int length = strnlen(path->data, PATH_MAX);
+  result = static_cast<char*>(malloc(length + 1));
+  strncpy(result, path->data, length);
+  result[length] = '\0';
+  delete path;
+  return result;
 }
 
 
diff --git a/runtime/bin/directory_macos.cc b/runtime/bin/directory_macos.cc
index 241fce2..8a0f2b7 100644
--- a/runtime/bin/directory_macos.cc
+++ b/runtime/bin/directory_macos.cc
@@ -6,6 +6,7 @@
 
 #include <dirent.h>
 #include <errno.h>
+#include <string.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -13,12 +14,36 @@
 #include "bin/file.h"
 #include "bin/platform.h"
 
+class PathBuffer {
+ public:
+  PathBuffer() : length(0) { }
 
-static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
-  strncpy(dest, src, n);
-  dest[n - 1] = '\0';
-  return dest;
-}
+
+
+  char data[PATH_MAX + 1];
+  int length;
+
+  bool Add(const char* name) {
+    size_t written = snprintf(data + length,
+                              PATH_MAX - length,
+                              "%s",
+                              name);
+    data[PATH_MAX] = '\0';
+    if (written == strlen(name)) {
+      length += written;
+      return true;
+    } else {
+      errno = ENAMETOOLONG;
+      return false;
+    }
+  }
+
+  void Reset(int new_length) {
+    length = new_length;
+    data[length] = '\0';
+  }
+};
+
 
 
 // Forward declarations.
@@ -28,76 +53,56 @@
 static bool DeleteRecursively(const char* dir_name);
 
 
-static bool ComputeFullPath(const char* dir_name,
-                            char* path,
-                            int* path_length) {
-  char* abs_path;
-  do {
-    abs_path = realpath(dir_name, path);
-  } while (abs_path == NULL && errno == EINTR);
-  if (abs_path == NULL) {
-    return false;
-  }
-  *path_length = strlen(path);
-  size_t written = snprintf(path + *path_length,
-                            PATH_MAX - *path_length,
-                            "%s",
-                            File::PathSeparator());
-  if (written != strlen(File::PathSeparator())) {
-    return false;
-  }
-  *path_length += written;
-  return true;
-}
-
-
-static bool HandleDir(char* dir_name,
-                      char* path,
-                      int path_length,
-                      bool recursive,
-                      DirectoryListing *listing) {
-  if (strcmp(dir_name, ".") != 0 &&
-      strcmp(dir_name, "..") != 0) {
-    size_t written = snprintf(path + path_length,
-                              PATH_MAX - path_length,
-                              "%s",
-                              dir_name);
-    if (written != strlen(dir_name)) {
-      return false;
-    }
-    bool ok = listing->HandleDirectory(path);
-    if (!ok) return ok;
-    if (recursive) {
-      return ListRecursively(path, recursive, listing);
-    }
-  }
-  return true;
-}
-
-
-static bool HandleFile(char* file_name,
-                       char* path,
-                       int path_length,
-                       DirectoryListing *listing) {
-  // TODO(sgjesse): Pass flags to indicate whether file responses are
-  // needed.
-  size_t written = snprintf(path + path_length,
-                            PATH_MAX - path_length,
-                            "%s",
-                            file_name);
-  if (written != strlen(file_name)) {
-    return false;
-  }
-  return listing->HandleFile(path);
-}
-
-
 static void PostError(DirectoryListing *listing,
                       const char* dir_name) {
   listing->HandleError(dir_name);
 }
 
 
+static PathBuffer* ComputeFullPath(const char* dir_name) {
+  PathBuffer* path = new PathBuffer();
+  char* abs_path;
+  do {
+    abs_path = realpath(dir_name, path->data);
+  } while (abs_path == NULL && errno == EINTR);
+  if (abs_path == NULL) {
+    delete path;
+    return NULL;
+  }
+  path->length = strlen(path->data);
+  if (path->Add(File::PathSeparator())) {
+    return path;
+  } else {
+    delete path;
+    return NULL;
+  }
+}
+
+static bool HandleDir(char* dir_name,
+                      PathBuffer* path,
+                      bool recursive,
+                      DirectoryListing *listing) {
+  if (strcmp(dir_name, ".") == 0) return true;
+  if (strcmp(dir_name, "..") == 0) return true;
+  if (!path->Add(dir_name)) {
+    PostError(listing, path->data);
+    return false;
+  }
+  return listing->HandleDirectory(path->data) &&
+      (!recursive || ListRecursively(path->data, recursive, listing));
+}
+
+static bool HandleFile(char* file_name,
+                       PathBuffer* path,
+                       DirectoryListing *listing) {
+  if (!path->Add(file_name)) {
+    PostError(listing, path->data);
+    return false;
+  }
+  return listing->HandleFile(path->data);
+}
+
+
 static bool ListRecursively(const char* dir_name,
                             bool recursive,
                             DirectoryListing *listing) {
@@ -115,38 +120,32 @@
   // recursive traversal. path_length does not always equal
   // strlen(path) but indicates the current prefix of path that is the
   // path of the current directory in the traversal.
-  char *path = static_cast<char*>(malloc(PATH_MAX));
-  ASSERT(path != NULL);
-  int path_length = 0;
-  bool valid = ComputeFullPath(dir_name, path, &path_length);
-  if (!valid) {
-    free(path);
+  PathBuffer* path = ComputeFullPath(dir_name);
+  if (path == NULL) {
     PostError(listing, dir_name);
     return false;
   }
-
-  // Iterated the directory and post the directories and files to the
+  // Iterate the directory and post the directories and files to the
   // ports.
-  int read = 0;
+  int path_length = path->length;
+  int status = 0;
   bool success = true;
   dirent entry;
   dirent* result;
-  while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
-                                              &entry,
-                                              &result))) == 0 &&
+  while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
+                                                &entry,
+                                                &result))) == 0 &&
          result != NULL) {
     switch (entry.d_type) {
       case DT_DIR:
         success = HandleDir(entry.d_name,
                             path,
-                            path_length,
                             recursive,
                             listing) && success;
         break;
       case DT_REG:
         success = HandleFile(entry.d_name,
                              path,
-                             path_length,
                              listing) && success;
         break;
       case DT_LNK:
@@ -156,30 +155,25 @@
         // the actual entry type. Notice that stat returns the type of
         // the file pointed to.
         struct stat entry_info;
-        size_t written = snprintf(path + path_length,
-                                  PATH_MAX - path_length,
-                                  "%s",
-                                  entry.d_name);
-        if (written != strlen(entry.d_name)) {
+        if (!path->Add(entry.d_name)) {
           success = false;
           break;
         }
-        int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info));
+        int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
         if (stat_success == -1) {
           success = false;
-          PostError(listing, path);
+          PostError(listing, path->data);
           break;
         }
+        path->Reset(path_length);
         if (S_ISDIR(entry_info.st_mode)) {
           success = HandleDir(entry.d_name,
                               path,
-                              path_length,
                               recursive,
                               listing) && success;
         } else if (S_ISREG(entry_info.st_mode)) {
           success = HandleFile(entry.d_name,
                                path,
-                               path_length,
                                listing) && success;
         }
         ASSERT(!S_ISLNK(entry_info.st_mode));
@@ -188,10 +182,11 @@
       default:
         break;
     }
+    path->Reset(path_length);
   }
 
-  if (read != 0) {
-    errno = read;
+  if (status != 0) {
+    errno = status;
     success = false;
     PostError(listing, dir_name);
   }
@@ -200,41 +195,23 @@
     success = false;
     PostError(listing, dir_name);
   }
-  free(path);
+  delete path;
 
   return success;
 }
 
 
 static bool DeleteFile(char* file_name,
-                       char* path,
-                       int path_length) {
-  size_t written = snprintf(path + path_length,
-                            PATH_MAX - path_length,
-                            "%s",
-                            file_name);
-  if (written != strlen(file_name)) {
-    return false;
-  }
-  return (remove(path) == 0);
+                       PathBuffer* path) {
+  return path->Add(file_name) && remove(path->data) == 0;
 }
 
 
 static bool DeleteDir(char* dir_name,
-                      char* path,
-                      int path_length) {
-  if (strcmp(dir_name, ".") != 0 &&
-      strcmp(dir_name, "..") != 0) {
-    size_t written = snprintf(path + path_length,
-                              PATH_MAX - path_length,
-                              "%s",
-                              dir_name);
-    if (written != strlen(dir_name)) {
-      return false;
-    }
-    return DeleteRecursively(path);
-  }
-  return true;
+                      PathBuffer* path) {
+  if (strcmp(dir_name, ".") == 0) return true;
+  if (strcmp(dir_name, "..") == 0) return true;
+  return path->Add(dir_name) && DeleteRecursively(path->data);
 }
 
 
@@ -260,19 +237,12 @@
 
   // Compute full path for the directory currently being deleted.  The
   // path buffer will be used to construct the current path in the
-  // recursive traversal. path_length does not always equal
-  // strlen(path) but indicates the current prefix of path that is the
-  // path of the current directory in the traversal.
-  char *path = static_cast<char*>(malloc(PATH_MAX));
-  ASSERT(path != NULL);
-  int path_length = 0;
-  bool valid = ComputeFullPath(dir_name, path, &path_length);
-  if (!valid) {
-    free(path);
-    return false;
-  }
+  // recursive traversal.
+  PathBuffer* path = ComputeFullPath(dir_name);
+  if (path == NULL) return false;
 
   // Iterate the directory and delete all files and directories.
+  int path_length = path->length;
   int read = 0;
   bool success = true;
   dirent entry;
@@ -284,49 +254,46 @@
          success) {
     switch (entry.d_type) {
       case DT_DIR:
-        success = success && DeleteDir(entry.d_name, path, path_length);
+        success = success && DeleteDir(entry.d_name, path);
         break;
       case DT_REG:
       case DT_LNK:
         // Treat all links as files. This will delete the link which
         // is what we want no matter if the link target is a file or a
         // directory.
-        success = success && DeleteFile(entry.d_name, path, path_length);
+        success = success && DeleteFile(entry.d_name, path);
         break;
       case DT_UNKNOWN: {
         // On some file systems the entry type is not determined by
         // readdir_r. For those we use lstat to determine the entry
         // type.
         struct stat entry_info;
-        size_t written = snprintf(path + path_length,
-                                  PATH_MAX - path_length,
-                                  "%s",
-                                  entry.d_name);
-        if (written != strlen(entry.d_name)) {
+        if (!path->Add(entry.d_name)) {
           success = false;
           break;
         }
-        int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
+        int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
         if (lstat_success == -1) {
           success = false;
           break;
         }
+        path->Reset(path_length);
         if (S_ISDIR(entry_info.st_mode)) {
-          success = success && DeleteDir(entry.d_name, path, path_length);
+          success = success && DeleteDir(entry.d_name, path);
         } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
           // Treat links as files. This will delete the link which is
           // what we want no matter if the link target is a file or a
           // directory.
-          success = success && DeleteFile(entry.d_name, path, path_length);
+          success = success && DeleteFile(entry.d_name, path);
         }
         break;
       }
       default:
         break;
     }
+    path->Reset(path_length);
   }
-
-  free(path);
+  delete path;
 
   if ((read != 0) ||
       (closedir(dir_pointer) == -1) ||
@@ -397,27 +364,32 @@
   // dir_template.  Creates the directory with the permissions specified
   // by the process umask.
   // The return value must be freed by the caller.
-  char* path = static_cast<char*>(malloc(PATH_MAX + 1));
-  SafeStrNCpy(path, const_template, PATH_MAX + 1);
-  int path_length = strlen(path);
-  if (path_length > 0) {
-    if ((path)[path_length - 1] == '/') {
-      snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX");
-    } else {
-      snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX");
-    }
-  } else {
-    snprintf(path, PATH_MAX, "/tmp/temp_dir1_XXXXXX");
+  PathBuffer* path = new PathBuffer();
+  path->Add(const_template);
+  if (path->length == 0) {
+    path->Add("/tmp/temp_dir1_");
+  } else if ((path->data)[path->length - 1] == '/') {
+    path->Add("temp_dir_");
+  }
+  if (!path->Add("XXXXXX")) {
+    // Pattern has overflowed.
+    delete path;
+    return NULL;
   }
   char* result;
   do {
-    result = mkdtemp(path);
+    result = mkdtemp(path->data);
   } while (result == NULL && errno == EINTR);
   if (result == NULL) {
-    free(path);
+    delete path;
     return NULL;
   }
-  return path;
+  int length = strlen(path->data);
+  result = static_cast<char*>(malloc(length + 1));
+  strncpy(result, path->data, length);
+  result[length] = '\0';
+  delete path;
+  return result;
 }
 
 
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 87706e8..60d0fed 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -261,12 +261,7 @@
       return true;
     }
     IOBuffer::DisposeBuffer(buffer);
-
-    if (GetLastError() == ERROR_BROKEN_PIPE) {
-      event_handler_->HandleClosed(this);
-    } else {
-      event_handler_->HandleError(this);
-    }
+    HandleIssueError();
     return false;
   } else {
     // Completing asynchronously through thread.
@@ -301,13 +296,19 @@
     return true;
   }
   IOBuffer::DisposeBuffer(buffer);
+  HandleIssueError();
+  return false;
+}
 
-  if (GetLastError() == ERROR_BROKEN_PIPE) {
+
+void Handle::HandleIssueError() {
+  DWORD error = GetLastError();
+  if (error == ERROR_BROKEN_PIPE) {
     event_handler_->HandleClosed(this);
   } else {
     event_handler_->HandleError(this);
   }
-  return false;
+  SetLastError(error);
 }
 
 
@@ -329,6 +330,17 @@
 }
 
 
+void SocketHandle::HandleIssueError() {
+  int error = WSAGetLastError();
+  if (error == WSAECONNRESET) {
+    event_handler_->HandleClosed(this);
+  } else {
+    event_handler_->HandleError(this);
+  }
+  WSASetLastError(error);
+}
+
+
 bool ListenSocket::LoadAcceptEx() {
   // Load the AcceptEx function into memory using WSAIoctl.
   // The WSAIoctl function is an extension of the ioctlsocket()
@@ -564,12 +576,7 @@
   }
   IOBuffer::DisposeBuffer(buffer);
   pending_read_ = NULL;
-
-  if (WSAGetLastError() == WSAECONNRESET) {
-    event_handler_->HandleClosed(this);
-  } else {
-    event_handler_->HandleError(this);
-  }
+  HandleIssueError();
   return false;
 }
 
@@ -592,12 +599,7 @@
   }
   IOBuffer::DisposeBuffer(pending_write_);
   pending_write_ = NULL;
-
-  if (WSAGetLastError() == WSAECONNRESET) {
-    event_handler_->HandleClosed(this);
-  } else {
-    event_handler_->HandleError(this);
-  }
+  HandleIssueError();
   return false;
 }
 
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index 1aa2339..7b4902f 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -217,6 +217,7 @@
   Handle(HANDLE handle, Dart_Port port);
 
   virtual void AfterClose() = 0;
+  virtual void HandleIssueError();
 
   Type type_;
   HANDLE handle_;
@@ -260,6 +261,8 @@
   explicit SocketHandle(SOCKET s) : Handle(reinterpret_cast<HANDLE>(s)) {}
   SocketHandle(SOCKET s, Dart_Port port)
       : Handle(reinterpret_cast<HANDLE>(s), port) {}
+
+  virtual void HandleIssueError();
 };
 
 
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 1f21746..31e55a3 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -40,6 +40,7 @@
   static void GetError(intptr_t fd, OSError* os_error);
   static int GetType(intptr_t fd);
   static intptr_t GetStdioHandle(int num);
+  static void Close(intptr_t fd);
 
   // Perform a IPv4 hostname lookup. Returns the hostname string in
   // IPv4 dotted-decimal format.
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index cffae9f..3e41242 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -248,3 +248,15 @@
   }
   return socket;
 }
+
+
+void Socket::Close(intptr_t fd) {
+  ASSERT(fd >= 0);
+  int err = TEMP_FAILURE_RETRY(close(fd));
+  if (err != 0) {
+    const int kBufferSize = 1024;
+    char error_message[kBufferSize];
+    strerror_r(errno, error_message, kBufferSize);
+    Log::PrintErr("%s\n", error_message);
+  }
+}
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index 4740771..ff6c191 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -264,3 +264,15 @@
   }
   return socket;
 }
+
+
+void Socket::Close(intptr_t fd) {
+  ASSERT(fd >= 0);
+  int err = TEMP_FAILURE_RETRY(close(fd));
+  if (err != 0) {
+    const int kBufferSize = 1024;
+    char error_message[kBufferSize];
+    strerror_r(errno, error_message, kBufferSize);
+    Log::PrintErr("%s\n", error_message);
+  }
+}
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index 07a9edd..20364cb 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -250,3 +250,15 @@
   }
   return socket;
 }
+
+
+void Socket::Close(intptr_t fd) {
+  ASSERT(fd >= 0);
+  int err = TEMP_FAILURE_RETRY(close(fd));
+  if (err != 0) {
+    const int kBufferSize = 1024;
+    char error_message[kBufferSize];
+    strerror_r(errno, error_message, kBufferSize);
+    Log::PrintErr("%s\n", error_message);
+  }
+}
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index b252cff..a33d703 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -273,3 +273,9 @@
   ListenSocket* listen_socket = new ListenSocket(s);
   return reinterpret_cast<intptr_t>(listen_socket);
 }
+
+
+void Socket::Close(intptr_t fd) {
+  ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(fd);
+  client_socket->close();
+}
diff --git a/runtime/embedders/openglui/build_skia.sh b/runtime/embedders/openglui/build_skia.sh
index 34b0bb9..92b30ea 100755
--- a/runtime/embedders/openglui/build_skia.sh
+++ b/runtime/embedders/openglui/build_skia.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 function usage {
   echo "usage: $0 [ --help ] [ --android ] [ --arm | --x86] [--clean] [<Dart directory>]"
diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart
index 3b457fa..3ce453b 100644
--- a/runtime/lib/array.dart
+++ b/runtime/lib/array.dart
@@ -116,6 +116,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(E element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   Iterable<E> take(int n) {
     return IterableMixinWorkaround.takeList(this, n);
   }
@@ -350,6 +354,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(E element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   Iterable<E> take(int n) {
     return IterableMixinWorkaround.takeList(this, n);
   }
diff --git a/runtime/lib/byte_array.dart b/runtime/lib/byte_array.dart
index 906259c..14b1b17 100644
--- a/runtime/lib/byte_array.dart
+++ b/runtime/lib/byte_array.dart
@@ -246,10 +246,14 @@
     return IterableMixinWorkaround.reduce(this, initialValue, combine);
   }
 
-  Collection where(bool f(element)) {
+  Collection where(bool f(int element)) {
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(int element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   Iterable<int> take(int n) {
     return IterableMixinWorkaround.takeList(this, n);
   }
diff --git a/runtime/lib/double.cc b/runtime/lib/double.cc
index 2d3c5f8..e133681 100644
--- a/runtime/lib/double.cc
+++ b/runtime/lib/double.cc
@@ -79,12 +79,13 @@
     args.SetAt(0, String::Handle(String::New(error_msg)));
     Exceptions::ThrowByType(Exceptions::kUnsupported, args);
   }
-  if ((Smi::kMinValue <= val) && (val <= Smi::kMaxValue)) {
-    return Smi::New(static_cast<intptr_t>(val));
-  } else if ((Mint::kMinValue <= val) && (val <= Mint::kMaxValue)) {
-    return Mint::New(static_cast<int64_t>(val));
+  const Bigint& big = Bigint::Handle(BigintOperations::NewFromDouble(val));
+  if (BigintOperations::FitsIntoSmi(big)) {
+    return BigintOperations::ToSmi(big);
+  } else if (BigintOperations::FitsIntoMint(big)) {
+    return Mint::New(BigintOperations::ToMint(big));
   } else {
-    return BigintOperations::NewFromDouble(val);
+    return big.raw();
   }
 }
 
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index 137a583..bb87177 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -258,6 +258,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(T element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   Iterable<T> take(int n) {
     return IterableMixinWorkaround.takeList(this, n);
   }
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 7ed2000..e7edbe0 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -477,7 +477,6 @@
   if (!CanonicalizeUri(arguments->isolate(), root_lib, uri,
                        &canonical_uri, &error)) {
     const String& msg = String::Handle(String::New(error));
-    free(error);
     ThrowIsolateSpawnException(msg);
   }
 
diff --git a/runtime/lib/stopwatch_patch.dart b/runtime/lib/stopwatch_patch.dart
index 19645d1..2bdc2c5 100644
--- a/runtime/lib/stopwatch_patch.dart
+++ b/runtime/lib/stopwatch_patch.dart
@@ -4,7 +4,7 @@
 
 // A VM patch of the stopwatch part of dart:core.
 
-patch class _StopwatchImpl {
+patch class Stopwatch {
   // Returns the current clock tick.
   /* patch */ static int _now() native "Stopwatch_now";
 
diff --git a/runtime/tests/vm/dart/byte_array_optimized_test.dart b/runtime/tests/vm/dart/byte_array_optimized_test.dart
new file mode 100644
index 0000000..803944d
--- /dev/null
+++ b/runtime/tests/vm/dart/byte_array_optimized_test.dart
@@ -0,0 +1,2214 @@
+// 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 tag to be able to run in html test framework.
+library byte_array_test;
+
+import 'dart:scalarlist';
+
+// This test exercises optimized [] and []= operators
+// on byte array views.
+class OptimizedByteArrayTest {
+  static testInt8ListImpl(Int8List array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(10, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(10, array.lengthInBytes());
+    Expect.listEquals([0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0],
+                      array);
+    Expect.throws(() { array[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x100 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -10 + i;
+    }
+    Expect.listEquals([-10, -9, -8, -7, -6,
+                        -5, -4, -3, -2, -1],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x7F - i;
+    }
+    Expect.listEquals([127, 126, 125, 124, 123,
+                       122, 121, 120, 119, 118],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -0x80 + i;
+    }
+    Expect.listEquals([-128, -127, -126, -125, -124,
+                       -123, -122, -121, -120, -119],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Int8List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Int8List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    array.setRange(3, 4, [-128, 0, 1, 127]);
+    Expect.listEquals([0, 1, 2, -128, 0, 1, 127, 7, 8, 9],
+                      array);
+  }
+  static testInt8List() {
+    Expect.throws(() { new Int8List(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Int8List(10);
+    testInt8ListImpl(array);
+  }
+
+  static testUint8ListImpl(Uint8List array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(10, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(10, array.lengthInBytes());
+    Expect.listEquals([0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0],
+                      array);
+    Expect.throws(() { array[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x100 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xFF - i;
+    }
+    Expect.listEquals([0xFF, 0xFE, 0xFD, 0xFC, 0xFB,
+                       0xFA, 0xF9, 0xF8, 0xF7, 0xF6],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Uint8List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Uint8List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    array.setRange(3, 4, [257, 0, 1, 255]);
+    Expect.listEquals([0, 1, 2, 1, 0, 1, 255, 7, 8, 9],
+                      array);
+  }
+
+  static testUint8List() {
+    Expect.throws(() { new Uint8List(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Uint8List(10);
+    testUint8ListImpl(array);
+  }
+
+  static testInt16ListImpl(Int16List array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(10, array.length);
+    Expect.equals(2, array.bytesPerElement());
+    Expect.equals(20, array.lengthInBytes());
+    Expect.listEquals([0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0],
+                      array);
+    Expect.throws(() { array[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x10000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -10 + i;
+    }
+    Expect.listEquals([-10, -9, -8, -7, -6,
+                        -5, -4, -3, -2, -1],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x7FFF - i;
+    }
+    Expect.listEquals([0x7FFF, 0x7FFE, 0x7FFD, 0x7FFC, 0x7FFB,
+                       0x7FFA, 0x7FF9, 0x7FF8, 0x7FF7, 0x7FF6],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -0x8000 + i;
+    }
+    Expect.listEquals([-0x8000, -0x7FFF, -0x7FFE, -0x7FFD, -0x7FFC,
+                       -0x7FFB, -0x7FFA, -0x7FF9, -0x7FF8, -0x7FF7],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Int16List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Int16List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    array.setRange(3, 4, [-32768, 0, 1, 32767]);
+    Expect.listEquals([0, 1, 2, -32768, 0, 1, 32767, 7, 8, 9],
+                      array);
+  }
+
+  static testInt16List() {
+    Expect.throws(() { new Int16List(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Int16List(10);
+    testInt16ListImpl(array);
+  }
+
+  static testUint16ListImpl(Uint16List array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(10, array.length);
+    Expect.equals(2, array.bytesPerElement());
+    Expect.equals(20, array.lengthInBytes());
+    Expect.listEquals([0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0],
+                      array);
+    Expect.throws(() { array[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x10000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xFFFF - i;
+    }
+    Expect.listEquals([0xFFFF, 0xFFFE, 0xFFFD, 0xFFFC, 0xFFFB,
+                       0xFFFA, 0xFFF9, 0xFFF8, 0xFFF7, 0xFFF6],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Uint16List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Uint16List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    array.setRange(3, 4, [0x10001, 0, 1, 0xFFFF]);
+    Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFF, 7, 8, 9],
+                      array);
+  }
+
+  static testUint16List() {
+    Expect.throws(() { new Uint16List(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Uint16List(10);
+    testUint16ListImpl(array);
+  }
+
+  static testInt32ListImpl(Int32List array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(10, array.length);
+    Expect.equals(4, array.bytesPerElement());
+    Expect.equals(40, array.lengthInBytes());
+    Expect.listEquals([0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0],
+                      array);
+    Expect.throws(() { array[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x100000000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -10 + i;
+    }
+    Expect.listEquals([-10, -9, -8, -7, -6,
+                        -5, -4, -3, -2, -1],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x7FFFFFFF - i;
+    }
+    Expect.listEquals([0x7FFFFFFF, 0x7FFFFFFE,
+                       0x7FFFFFFD, 0x7FFFFFFC,
+                       0x7FFFFFFB, 0x7FFFFFFA,
+                       0x7FFFFFF9, 0x7FFFFFF8,
+                       0x7FFFFFF7, 0x7FFFFFF6],
+        array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -0x80000000 + i;
+    }
+    Expect.listEquals([-0x80000000, -0x7FFFFFFF,
+                       -0x7FFFFFFE, -0x7FFFFFFD,
+                       -0x7FFFFFFC, -0x7FFFFFFB,
+                       -0x7FFFFFFA, -0x7FFFFFF9,
+                       -0x7FFFFFF8, -0x7FFFFFF7],
+        array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Int32List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Int32List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    array.setRange(3, 4, [-0x80000000, 0, 1, 0x7FFFFFFF]);
+    Expect.listEquals([0, 1, 2, -0x80000000, 0, 1, 0x7FFFFFFF, 7, 8, 9],
+                      array);
+  }
+
+  static testInt32List() {
+    Expect.throws(() { new Int32List(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Int32List(10);
+    testInt32ListImpl(array);
+  }
+
+  static testUint32ListImpl(Uint32List array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(10, array.length);
+    Expect.equals(4, array.bytesPerElement());
+    Expect.equals(40, array.lengthInBytes());
+    Expect.listEquals([0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0],
+                      array);
+    Expect.throws(() { array[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x100000000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xFFFFFFFF - i;
+    }
+    Expect.listEquals([0xFFFFFFFF, 0xFFFFFFFE,
+                       0xFFFFFFFD, 0xFFFFFFFC,
+                       0xFFFFFFFB, 0xFFFFFFFA,
+                       0xFFFFFFF9, 0xFFFFFFF8,
+                       0xFFFFFFF7, 0xFFFFFFF6],
+        array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Uint32List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Uint32List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    array.setRange(3, 4, [0x100000001, 0, 1, 0xFFFFFFFF]);
+    Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFFFFFF, 7, 8, 9],
+                      array);
+  }
+
+  static testUint32List() {
+    Expect.throws(() { new Uint32List(-1); },
+                  (e) { return e is ArgumentError; });
+    Expect.throws(() { new Uint32List(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Uint32List(10);
+    testUint32ListImpl(array);
+    
+  }
+
+  static testInt64ListImpl(Int64List array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(10, array.length);
+    Expect.equals(8, array.bytesPerElement());
+    Expect.equals(80, array.lengthInBytes());
+    Expect.listEquals([0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0],
+                      array);
+    Expect.throws(() { array[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x10000000000000000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -10 + i;
+    }
+    Expect.listEquals([-10, -9, -8, -7, -6,
+                        -5, -4, -3, -2, -1],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x7FFFFFFFFFFFFFFF - i;
+    }
+    Expect.listEquals([0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFE,
+                       0x7FFFFFFFFFFFFFFD, 0x7FFFFFFFFFFFFFFC,
+                       0x7FFFFFFFFFFFFFFB, 0x7FFFFFFFFFFFFFFA,
+                       0x7FFFFFFFFFFFFFF9, 0x7FFFFFFFFFFFFFF8,
+                       0x7FFFFFFFFFFFFFF7, 0x7FFFFFFFFFFFFFF6],
+        array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -0x8000000000000000 + i;
+    }
+    Expect.listEquals([-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
+                       -0x7FFFFFFFFFFFFFFE, -0x7FFFFFFFFFFFFFFD,
+                       -0x7FFFFFFFFFFFFFFC, -0x7FFFFFFFFFFFFFFB,
+                       -0x7FFFFFFFFFFFFFFA, -0x7FFFFFFFFFFFFFF9,
+                       -0x7FFFFFFFFFFFFFF8, -0x7FFFFFFFFFFFFFF7],
+        array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Int64List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Int64List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    array.setRange(3, 4, [-0x8000000000000000, 0, 1, 0x7FFFFFFFFFFFFFFF]);
+    Expect.listEquals([0, 1, 2, -0x8000000000000000, 0,
+                       1, 0x7FFFFFFFFFFFFFFF, 7, 8, 9],
+                      array);
+  }
+
+  static testInt64List() {
+    Expect.throws(() { new Int64List(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Int64List(10);
+    testInt64ListImpl(array);
+  }
+
+  static testUint64ListImpl(Uint64List array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(10, array.length);
+    Expect.equals(8, array.bytesPerElement());
+    Expect.equals(80, array.lengthInBytes());
+    Expect.listEquals([0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0],
+                      array);
+    Expect.throws(() { array[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0x10000000000000000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xFFFFFFFFFFFFFFFF - i;
+    }
+    Expect.listEquals([0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE,
+                       0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFC,
+                       0xFFFFFFFFFFFFFFFB, 0xFFFFFFFFFFFFFFFA,
+                       0xFFFFFFFFFFFFFFF9, 0xFFFFFFFFFFFFFFF8,
+                       0xFFFFFFFFFFFFFFF7, 0xFFFFFFFFFFFFFFF6],
+        array);
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Uint64List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Uint64List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    array.setRange(3, 4, [0x10000000000000001, 0, 1, 0xFFFFFFFFFFFFFFFF]);
+    Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFFFFFFFFFFFFFF, 7, 8, 9],
+                      array);
+  }
+
+  static testUint64List() {
+    Expect.throws(() { new Uint64List(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Uint64List(10);
+    testUint64ListImpl(array);
+  }
+
+  static testFloat32ListImpl(Float32List array) {
+    Expect.isTrue(array is List<double>);
+    Expect.equals(10, array.length);
+    Expect.equals(4, array.bytesPerElement());
+    Expect.equals(40, array.lengthInBytes());
+    Expect.listEquals([0.0, 0.0, 0.0, 0.0, 0.0,
+                       0.0, 0.0, 0.0, 0.0, 0.0],
+                      array);
+    Expect.throws(() { array[-1] = 0.0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0.0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 1.0 + i;
+    }
+    Expect.listEquals([1.0, 2.0, 3.0, 4.0, 5.0,
+                       6.0, 7.0, 8.0, 9.0, 10.0],
+                      array);
+    // TODO: min, max, and round
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i * 1.0;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Float32List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Float32List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3.0, 4.0, 5.0, 6.0], region);
+    array.setRange(3, 4, [double.NEGATIVE_INFINITY, 0.0, 1.0, double.INFINITY]);
+    Expect.listEquals([0.0, 1.0, 2.0, double.NEGATIVE_INFINITY, 0.0,
+                       1.0, double.INFINITY, 7.0, 8.0, 9.0],
+                      array);
+  }
+
+  static testFloat32List() {
+    Expect.throws(() { new Float32List(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Float32List(10);
+    testFloat32ListImpl(array);
+  }
+
+  static testFloat64ListImpl(Float64List array) {
+    Expect.isTrue(array is List<double>);
+    Expect.equals(10, array.length);
+    Expect.equals(8, array.bytesPerElement());
+    Expect.equals(80, array.lengthInBytes());
+    Expect.listEquals([0.0, 0.0, 0.0, 0.0, 0.0,
+                       0.0, 0.0, 0.0, 0.0, 0.0],
+                      array);
+    Expect.throws(() { array[-1] = 0.0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return array[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array[10] = 0.0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 1.0 + i;
+    }
+    Expect.listEquals([1.0, 2.0, 3.0, 4.0, 5.0,
+                       6.0, 7.0, 8.0, 9.0, 10.0],
+                      array);
+    // TODO: min, max
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = i * 1.0;
+    }
+    var copy = array.getRange(0, array.length);
+    Expect.isFalse(copy === array);
+    Expect.isTrue(copy is Float64List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(array, copy);
+    var empty = array.getRange(array.length, 0);
+    Expect.equals(0, empty.length);
+    var region = array.getRange(3, array.length - 6);
+    Expect.isTrue(copy is Float64List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3.0, 4.0, 5.0, 6.0], region);
+    array.setRange(3, 4, [double.NEGATIVE_INFINITY, 0.0, 1.0, double.INFINITY]);
+    Expect.listEquals([0.0, 1.0, 2.0, double.NEGATIVE_INFINITY, 0.0,
+                       1.0, double.INFINITY, 7.0, 8.0, 9.0],
+                      array);
+  }
+
+  static testFloat64List() {
+    Expect.throws(() { new Float64List(-1); },
+                  (e) { return e is ArgumentError; });
+    var array = new Float64List(10);
+    testFloat64ListImpl(array);
+  }
+
+  static testInt8ListViewImpl(var array) {
+    Expect.equals(12, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(12, array.lengthInBytes());
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xFF;
+    }
+    Expect.throws(() { new Int8List.view(array.asByteArray(), -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int8List.view(array.asByteArray(), 0, -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int8List.view(array.asByteArray(),
+                                         array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int8List.view(array.asByteArray(),
+                                         0, array.length + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int8List.view(array.asByteArray(),
+                                         array.length - 1, 2); },
+                  (e) { return e is RangeError; });
+    var empty = new Int8List.view(array.asByteArray(),
+                                  array.lengthInBytes());
+    Expect.isTrue(empty is List<int>);
+    Expect.isTrue(empty is Int8List);
+    Expect.equals(0, empty.length);
+    var whole = new Int8List.view(array.asByteArray());
+    Expect.isTrue(whole is List<int>);
+    Expect.isTrue(whole is Int8List);
+    Expect.equals(12, whole.length);
+    var view = new Int8List.view(array.asByteArray(), 1, array.length - 2);
+    Expect.isTrue(view is List<int>);
+    Expect.isTrue(view is Int8List);
+    Expect.equals(10, view.length);
+    Expect.equals(1, view.bytesPerElement());
+    Expect.equals(10, view.lengthInBytes());
+    Expect.listEquals([-1, -1, -1, -1, -1,
+                       -1, -1, -1, -1, -1],
+                      view);
+    Expect.throws(() { view[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return view[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.insertRange(0, view.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeRange(0, view.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      view);
+    Expect.listEquals([0xFF, 1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x100 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      view);
+    Expect.listEquals([0xFF, 0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = -10 + i;
+    }
+    Expect.listEquals([-10, -9, -8, -7, -6,
+                        -5, -4, -3, -2, -1],
+                      view);
+    Expect.listEquals([0xFF, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA,
+                       0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x7F - i;
+    }
+    Expect.listEquals([127, 126, 125, 124, 123,
+                       122, 121, 120, 119, 118],
+                      view);
+    Expect.listEquals([0xFF, 127, 126, 125, 124, 123,
+                       122, 121, 120, 119, 118, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = -0x80 + i;
+    }
+    Expect.listEquals([-128, -127, -126, -125, -124,
+                       -123, -122, -121, -120, -119],
+                      view);
+    Expect.listEquals([0xFF, 0x80, 0x81, 0x82, 0x83, 0x84,
+                       0x85, 0x86, 0x87, 0x88, 0x89, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = i;
+    }
+    var copy = view.getRange(0, view.length);
+    Expect.isFalse(copy === view);
+    Expect.isTrue(copy is Int8List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(view, copy);
+    var region = view.getRange(3, view.length - 6);
+    Expect.isTrue(copy is Int8List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    view.setRange(3, 4, [-128, 0, 1, 127]);
+    Expect.listEquals([0, 1, 2, -128, 0, 1, 127, 7, 8, 9],
+                      view);
+    Expect.listEquals([0xFF, 0, 1, 2, 128, 0, 1, 127, 7, 8, 9, 0xFF],
+                      array);
+  }
+  static testInt8ListView() {
+    var array = new Uint8List(12);
+    testInt8ListViewImpl(array);
+  }
+
+  static testUint8ListViewImpl(var array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(12, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(12, array.lengthInBytes());
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -1;
+    }
+    Expect.throws(() { new Uint8List.view(array.asByteArray(), -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint8List.view(array.asByteArray(), 0, -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint8List.view(array.asByteArray(),
+                                          array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint8List.view(array.asByteArray(),
+                                          0, array.length + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint8List.view(array.asByteArray(),
+                                          array.length - 1, 2); },
+                  (e) { return e is RangeError; });
+    var empty = new Uint8List.view(array.asByteArray(),
+                                   array.lengthInBytes());
+    Expect.isTrue(empty is List<int>);
+    Expect.isTrue(empty is Uint8List);
+    Expect.equals(0, empty.length);
+    var whole = new Uint8List.view(array.asByteArray());
+    Expect.isTrue(whole is List<int>);
+    Expect.isTrue(whole is Uint8List);
+    Expect.equals(12, whole.length);
+    var view = new Uint8List.view(array.asByteArray(), 1, array.length - 2);
+    Expect.isTrue(view is List<int>);
+    Expect.isTrue(view is Uint8List);
+    Expect.equals(10, view.length);
+    Expect.equals(1, view.bytesPerElement());
+    Expect.equals(10, view.lengthInBytes());
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+                      view);
+    Expect.throws(() { view[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return view[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.insertRange(0, view.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeRange(0, view.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      view);
+    Expect.listEquals([-1, 1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x100 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      view);
+    Expect.listEquals([-1, 0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0xFF - i;
+    }
+    Expect.listEquals([0xFF, 0xFE, 0xFD, 0xFC, 0xFB,
+                       0xFA, 0xF9, 0xF8, 0xF7, 0xF6],
+                      view);
+    Expect.listEquals([-1, -1, -2, -3, -4, -5,
+                       -6, -7, -8, -9, -10, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = i;
+    }
+    var copy = view.getRange(0, view.length);
+    Expect.isFalse(copy === view);
+    Expect.isTrue(copy is Uint8List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(view, copy);
+    var region = view.getRange(3, view.length - 6);
+    Expect.isTrue(copy is Uint8List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    view.setRange(3, 4, [257, 0, 1, 255]);
+    Expect.listEquals([0, 1, 2, 1, 0, 1, 255, 7, 8, 9],
+                      view);
+  }
+
+  static testUint8ListView() {
+    var array = new Int8List(12);
+    testUint8ListViewImpl(array);
+  }
+
+  static testInt16ListViewImpl(var array) {
+    Expect.equals(24, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(24, array.lengthInBytes());
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xFF;
+    }
+    Expect.throws(() { new Int16List.view(array.asByteArray(), -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int16List.view(array.asByteArray(), 0, -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int16List.view(array.asByteArray(),
+                                          array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int16List.view(array.asByteArray(),
+                                           0, array.length + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int16List.view(array.asByteArray(),
+                                           array.length - 1, 2); },
+                  (e) { return e is RangeError; });
+    var empty = new Int16List.view(array.asByteArray(),
+                                   array.lengthInBytes());
+    Expect.isTrue(empty is List<int>);
+    Expect.isTrue(empty is Int16List);
+    Expect.equals(0, empty.length);
+    var whole = new Int16List.view(array.asByteArray());
+    Expect.isTrue(whole is List<int>);
+    Expect.isTrue(whole is Int16List);
+    Expect.equals(12, whole.length);
+    var view = new Int16List.view(array.asByteArray(), 2, 10);
+    Expect.isTrue(view is List<int>);
+    Expect.isTrue(view is Int16List);
+    Expect.equals(10, view.length);
+    Expect.equals(2, view.bytesPerElement());
+    Expect.equals(20, view.lengthInBytes());
+    Expect.listEquals([-1, -1, -1, -1, -1,
+                       -1, -1, -1, -1, -1],
+                      view);
+    Expect.throws(() { view[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return view[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.insertRange(0, view.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeRange(0, view.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00,
+                       0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00,
+                       0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x10000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+                       0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00,
+                       0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = -10 + i;
+    }
+    Expect.listEquals([-10, -9, -8, -7, -6,
+                        -5, -4, -3, -2, -1],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF,
+                       0xF9, 0xFF, 0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF,
+                       0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x7FFF - i;
+    }
+    Expect.listEquals([0x7FFF, 0x7FFE, 0x7FFD, 0x7FFC, 0x7FFB,
+                       0x7FFA, 0x7FF9, 0x7FF8, 0x7FF7, 0x7FF6],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0x7F, 0xFD, 0x7F,
+                       0xFC, 0x7F, 0xFB, 0x7F, 0xFA, 0x7F, 0xF9, 0x7F,
+                       0xF8, 0x7F, 0xF7, 0x7F, 0xF6, 0x7F, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = -0x8000 + i;
+    }
+    Expect.listEquals([-0x8000, -0x7FFF, -0x7FFE, -0x7FFD, -0x7FFC,
+                       -0x7FFB, -0x7FFA, -0x7FF9, -0x7FF8, -0x7FF7],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0x00, 0x80, 0x01, 0x80, 0x02, 0x80,
+                       0x03, 0x80, 0x04, 0x80, 0x05, 0x80, 0x06, 0x80,
+                       0x07, 0x80, 0x08, 0x80, 0x09, 0x80, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = i;
+    }
+    var copy = view.getRange(0, view.length);
+    Expect.isFalse(copy === view);
+    Expect.isTrue(copy is Int16List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(view, copy);
+    var region = view.getRange(3, view.length - 6);
+    Expect.isTrue(copy is Int16List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    view.setRange(3, 4, [-32768, 0, 1, 32767]);
+    Expect.listEquals([0, 1, 2, -32768, 0, 1, 32767, 7, 8, 9],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+                       0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0xFF, 0x7F,
+                       0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0xFF, 0xFF],
+                      array);
+  }
+
+  static testInt16ListView() {
+    var array = new Uint8List(24);
+    testInt16ListViewImpl(array);
+  }
+
+  static testUint16ListViewImpl(var array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(24, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(24, array.lengthInBytes());
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -1;
+    }
+    Expect.throws(() { new Uint16List.view(array.asByteArray(), -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint16List.view(array.asByteArray(), 0, -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint16List.view(array.asByteArray(),
+                                           array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint16List.view(array.asByteArray(),
+                                           0, array.length + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint16List.view(array.asByteArray(),
+                                           array.length - 1, 2); },
+                  (e) { return e is RangeError; });
+    var empty = new Uint16List.view(array.asByteArray(),
+                                    array.lengthInBytes());
+    Expect.isTrue(empty is List<int>);
+    Expect.isTrue(empty is Uint16List);
+    Expect.equals(0, empty.length);
+    var whole = new Uint16List.view(array.asByteArray());
+    Expect.isTrue(whole is List<int>);
+    Expect.isTrue(whole is Uint16List);
+    Expect.equals(12, whole.length);
+    var view = new Uint16List.view(array.asByteArray(), 2, 10);
+    Expect.isTrue(view is List<int>);
+    Expect.isTrue(view is Uint16List);
+    Expect.equals(10, view.length);
+    Expect.equals(2, view.bytesPerElement());
+    Expect.equals(20, view.lengthInBytes());
+    Expect.listEquals([0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+                       0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF],
+                      view);
+    Expect.throws(() { view[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return view[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.insertRange(0, view.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeRange(0, view.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      view);
+    Expect.listEquals([-1, -1, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0,
+                       6, 0, 7, 0, 8, 0, 9, 0, 10, 0, -1, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x10000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      view);
+    Expect.listEquals([-1, -1, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0,
+                        5, 0, 6, 0, 7, 0, 8, 0, 9, 0, -1, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0xFFFF - i;
+    }
+    Expect.listEquals([0xFFFF, 0xFFFE, 0xFFFD, 0xFFFC, 0xFFFB,
+                       0xFFFA, 0xFFF9, 0xFFF8, 0xFFF7, 0xFFF6],
+                      view);
+    Expect.listEquals([-1, -1, -1, -1, -2, -1, -3, -1,
+                       -4, -1, -5, -1, -6, -1, -7, -1,
+                       -8, -1, -9, -1, -10, -1, -1, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = i;
+    }
+    var copy = view.getRange(0, view.length);
+    Expect.isFalse(copy === view);
+    Expect.isTrue(copy is Uint16List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(view, copy);
+    var region = view.getRange(3, view.length - 6);
+    Expect.isTrue(copy is Uint16List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    view.setRange(3, 4, [0x10001, 0, 1, 0xFFFF]);
+    Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFF, 7, 8, 9],
+                      view);
+    Expect.listEquals([-1, -1, 0, 0, 1, 0, 2, 0,
+                       1, 0, 0, 0, 1, 0, -1, -1,
+                       7, 0, 8, 0, 9, 0, -1, -1],
+                      array);
+  }
+
+  static testUint16ListView() {
+    var array = new Int8List(24);
+    testUint16ListViewImpl(array);
+  }
+
+  static testInt32ListView() {
+    var array = new Uint8List(48);
+    Expect.equals(48, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(48, array.lengthInBytes());
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xFF;
+    }
+    Expect.throws(() { new Int32List.view(array.asByteArray(), -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int32List.view(array.asByteArray(), 0, -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int32List.view(array.asByteArray(),
+                                          array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int32List.view(array.asByteArray(),
+                                          0, array.length + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int32List.view(array.asByteArray(),
+                                          array.length - 1, 2); },
+                  (e) { return e is RangeError; });
+    var empty = new Int32List.view(array.asByteArray(),
+                                   array.lengthInBytes());
+    Expect.isTrue(empty is List<int>);
+    Expect.isTrue(empty is Int32List);
+    Expect.equals(0, empty.length);
+    var whole = new Int32List.view(array.asByteArray());
+    Expect.isTrue(whole is List<int>);
+    Expect.isTrue(whole is Int32List);
+    Expect.equals(12, whole.length);
+    var view = new Int32List.view(array.asByteArray(), 4, 10);
+    Expect.isTrue(view is List<int>);
+    Expect.isTrue(view is Int32List);
+    Expect.equals(10, view.length);
+    Expect.equals(4, view.bytesPerElement());
+    Expect.equals(40, view.lengthInBytes());
+    Expect.listEquals([-1, -1, -1, -1, -1,
+                       -1, -1, -1, -1, -1],
+                      view);
+    Expect.throws(() { view[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return view[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.insertRange(0, view.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeRange(0, view.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
+                       0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+                       0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+                       0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+                       0x0A, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x100000000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+                       0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+                       0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+                       0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+                       0x09, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = -10 + i;
+    }
+    Expect.listEquals([-10, -9, -8, -7, -6,
+                        -5, -4, -3, -2, -1],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0xFF, 0xFF, 0xFF,
+                       0xF7, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF,
+                       0xF9, 0xFF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF,
+                       0xFB, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF,
+                       0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x7FFFFFFF - i;
+    }
+    Expect.listEquals([0x7FFFFFFF, 0x7FFFFFFE,
+                       0x7FFFFFFD, 0x7FFFFFFC,
+                       0x7FFFFFFB, 0x7FFFFFFA,
+                       0x7FFFFFF9, 0x7FFFFFF8,
+                       0x7FFFFFF7, 0x7FFFFFF6],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xFE, 0xFF, 0xFF, 0x7F, 0xFD, 0xFF, 0xFF, 0x7F,
+                       0xFC, 0xFF, 0xFF, 0x7F, 0xFB, 0xFF, 0xFF, 0x7F,
+                       0xFA, 0xFF, 0xFF, 0x7F, 0xF9, 0xFF, 0xFF, 0x7F,
+                       0xF8, 0xFF, 0xFF, 0x7F, 0xF7, 0xFF, 0xFF, 0x7F,
+                       0xF6, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = -0x80000000 + i;
+    }
+    Expect.listEquals([-0x80000000, -0x7FFFFFFF,
+                       -0x7FFFFFFE, -0x7FFFFFFD,
+                       -0x7FFFFFFC, -0x7FFFFFFB,
+                       -0x7FFFFFFA, -0x7FFFFFF9,
+                       -0x7FFFFFF8, -0x7FFFFFF7],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80,
+                       0x01, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x80,
+                       0x03, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80,
+                       0x05, 0x00, 0x00, 0x80, 0x06, 0x00, 0x00, 0x80,
+                       0x07, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x80,
+                       0x09, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = i;
+    }
+    var copy = view.getRange(0, view.length);
+    Expect.isFalse(copy === view);
+    Expect.isTrue(copy is Int32List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(view, copy);
+    var region = view.getRange(3, view.length - 6);
+    Expect.isTrue(copy is Int32List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    view.setRange(3, 4, [-0x80000000, 0, 1, 0x7FFFFFFF]);
+    Expect.listEquals([0, 1, 2, -0x80000000, 0, 1, 0x7FFFFFFF, 7, 8, 9],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+                       0x09, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+  }
+
+  static testUint32ListViewImpl(var array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(48, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(48, array.lengthInBytes());
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -1;
+    }
+    Expect.throws(() { new Uint32List.view(array.asByteArray(), -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint32List.view(array.asByteArray(), 0, -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint32List.view(array.asByteArray(),
+                                           array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint32List.view(array.asByteArray(),
+                                           0, array.length + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint32List.view(array.asByteArray(),
+                                           array.length - 1, 2); },
+                  (e) { return e is RangeError; });
+    var empty = new Uint32List.view(array.asByteArray(),
+                                    array.lengthInBytes());
+    Expect.isTrue(empty is List<int>);
+    Expect.isTrue(empty is Uint32List);
+    Expect.equals(0, empty.length);
+    var whole = new Uint32List.view(array.asByteArray());
+    Expect.isTrue(whole is List<int>);
+    Expect.isTrue(whole is Uint32List);
+    Expect.equals(12, whole.length);
+    var view = new Uint32List.view(array.asByteArray(), 4, 10);
+    Expect.isTrue(view is List<int>);
+    Expect.isTrue(view is Uint32List);
+    Expect.equals(10, view.length);
+    Expect.equals(4, view.bytesPerElement());
+    Expect.equals(40, view.lengthInBytes());
+    Expect.listEquals([0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+                       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF],
+                      view);
+    Expect.throws(() { view[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return view[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.insertRange(0, view.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeRange(0, view.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      view);
+    Expect.listEquals([-1, -1, -1, -1, 1, 0, 0, 0,
+                       2, 0, 0, 0, 3, 0, 0, 0,
+                       4, 0, 0, 0, 5, 0, 0, 0,
+                       6, 0, 0, 0, 7, 0, 0, 0,
+                       8, 0, 0, 0, 9, 0, 0, 0,
+                       10, 0, 0, 0, -1, -1, -1, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x100000000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      view);
+    Expect.listEquals([-1, -1, -1, -1, 0, 0, 0, 0,
+                       1, 0, 0, 0, 2, 0, 0, 0,
+                       3, 0, 0, 0, 4, 0, 0, 0,
+                       5, 0, 0, 0, 6, 0, 0, 0,
+                       7, 0, 0, 0, 8, 0, 0, 0,
+                       9, 0, 0, 0, -1, -1, -1, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0xFFFFFFFF - i;
+    }
+    Expect.listEquals([0xFFFFFFFF, 0xFFFFFFFE,
+                       0xFFFFFFFD, 0xFFFFFFFC,
+                       0xFFFFFFFB, 0xFFFFFFFA,
+                       0xFFFFFFF9, 0xFFFFFFF8,
+                       0xFFFFFFF7, 0xFFFFFFF6],
+                      view);
+    Expect.listEquals([-1, -1, -1, -1, -1, -1, -1, -1,
+                       -2, -1, -1, -1, -3, -1, -1, -1,
+                       -4, -1, -1, -1, -5, -1, -1, -1,
+                       -6, -1, -1, -1, -7, -1, -1, -1,
+                       -8, -1, -1, -1, -9, -1, -1, -1,
+                       -10, -1, -1, -1, -1, -1, -1, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = i;
+    }
+    var copy = view.getRange(0, view.length);
+    Expect.isFalse(copy === view);
+    Expect.isTrue(copy is Uint32List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(view, copy);
+    var region = view.getRange(3, view.length - 6);
+    Expect.isTrue(copy is Uint32List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    view.setRange(3, 4, [0x100000001, 0, 1, 0xFFFFFFFF]);
+    Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFFFFFF, 7, 8, 9],
+                      view);
+    Expect.listEquals([-1, -1, -1, -1, 0, 0, 0, 0,
+                       1, 0, 0, 0, 2, 0, 0, 0,
+                       1, 0, 0, 0, 0, 0, 0, 0,
+                       1, 0, 0, 0, -1, -1, -1, -1,
+                       7, 0, 0, 0, 8, 0, 0, 0,
+                       9, 0, 0, 0, -1, -1, -1, -1],
+                      array);
+  }
+
+  static testUint32ListView() {
+    var array = new Int8List(48);
+    testUint32ListViewImpl(array);
+  }
+
+  static testInt64ListViewImpl(var array) {
+    Expect.equals(96, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(96, array.lengthInBytes());
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xFF;
+    }
+    Expect.throws(() { new Int64List.view(array.asByteArray(), -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int64List.view(array.asByteArray(), 0, -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int64List.view(array.asByteArray(),
+                                          array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int64List.view(array.asByteArray(),
+                                          0, array.length + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Int64List.view(array.asByteArray(),
+                                          array.length - 1, 2); },
+                  (e) { return e is RangeError; });
+    var empty = new Int64List.view(array.asByteArray(),
+                                   array.lengthInBytes());
+    Expect.isTrue(empty is List<int>);
+    Expect.isTrue(empty is Int64List);
+    Expect.equals(0, empty.length);
+    var whole = new Int64List.view(array.asByteArray());
+    Expect.isTrue(whole is List<int>);
+    Expect.isTrue(whole is Int64List);
+    Expect.equals(12, whole.length);
+    var view = new Int64List.view(array.asByteArray(), 8, 10);
+    Expect.isTrue(view is List<int>);
+    Expect.isTrue(view is Int64List);
+    Expect.equals(10, view.length);
+    Expect.equals(8, view.bytesPerElement());
+    Expect.equals(80, view.lengthInBytes());
+    Expect.listEquals([-1, -1, -1, -1, -1,
+                       -1, -1, -1, -1, -1],
+                      view);
+    Expect.throws(() { view[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return view[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[10] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.insertRange(0, view.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeRange(0, view.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x10000000000000000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = -10 + i;
+    }
+    Expect.listEquals([-10, -9, -8, -7, -6,
+                        -5, -4, -3, -2, -1],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x7FFFFFFFFFFFFFFF - i;
+    }
+    Expect.listEquals([0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFE,
+                       0x7FFFFFFFFFFFFFFD, 0x7FFFFFFFFFFFFFFC,
+                       0x7FFFFFFFFFFFFFFB, 0x7FFFFFFFFFFFFFFA,
+                       0x7FFFFFFFFFFFFFF9, 0x7FFFFFFFFFFFFFF8,
+                       0x7FFFFFFFFFFFFFF7, 0x7FFFFFFFFFFFFFF6],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = -0x8000000000000000 + i;
+    }
+    Expect.listEquals([-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
+                       -0x7FFFFFFFFFFFFFFE, -0x7FFFFFFFFFFFFFFD,
+                       -0x7FFFFFFFFFFFFFFC, -0x7FFFFFFFFFFFFFFB,
+                       -0x7FFFFFFFFFFFFFFA, -0x7FFFFFFFFFFFFFF9,
+                       -0x7FFFFFFFFFFFFFF8, -0x7FFFFFFFFFFFFFF7],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = i;
+    }
+    var copy = view.getRange(0, view.length);
+    Expect.isFalse(copy === view);
+    Expect.isTrue(copy is Int64List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(view, copy);
+    var region = view.getRange(3, view.length - 6);
+    Expect.isTrue(copy is Int64List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    view.setRange(3, 4, [-0x8000000000000000, 0, 1, 0x7FFFFFFFFFFFFFFF]);
+    Expect.listEquals([0, 1, 2, -0x8000000000000000, 0,
+                       1, 0x7FFFFFFFFFFFFFFF, 7, 8, 9],
+                      view);
+    Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+                       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+                      array);
+  }
+
+  static testInt64ListView() {
+    var array = new Uint8List(96);
+    testInt64ListViewImpl(array);
+  }
+
+  static testUint64ListViewImpl(var array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(96, array.length);
+    Expect.equals(1, array.bytesPerElement());
+    Expect.equals(96, array.lengthInBytes());
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = -1;
+    }
+    Expect.throws(() { new Uint64List.view(array.asByteArray(), -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint64List.view(array.asByteArray(), 0, -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint64List.view(array.asByteArray(),
+                                           array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint64List.view(array.asByteArray(),
+                                           0, array.length + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Uint64List.view(array.asByteArray(),
+                                           array.length - 1, 2); },
+                  (e) { return e is RangeError; });
+    var empty = new Uint64List.view(array.asByteArray(),
+                                    array.lengthInBytes());
+    Expect.isTrue(empty is List<int>);
+    Expect.isTrue(empty is Uint64List);
+    Expect.equals(0, empty.length);
+    var whole = new Uint64List.view(array.asByteArray());
+    Expect.isTrue(whole is List<int>);
+    Expect.isTrue(whole is Uint64List);
+    Expect.equals(12, whole.length);
+    var view = new Uint64List.view(array.asByteArray(), 8, 10);
+    Expect.isTrue(view is List<int>);
+    Expect.isTrue(view is Uint64List);
+    Expect.equals(10, view.length);
+    Expect.equals(8, view.bytesPerElement());
+    Expect.equals(80, view.lengthInBytes());
+    Expect.listEquals([0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
+                       0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
+                       0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
+                       0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
+                       0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF],
+                      view);
+    Expect.throws(() { view[-1] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return view[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[view.length] = 0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view.add(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.addLast(0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.insertRange(0, view.length, 0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { view.removeRange(0, view.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 1 + i;
+    }
+    Expect.listEquals([1, 2, 3, 4, 5,
+                       6, 7, 8, 9, 10],
+                      view);
+    Expect.listEquals([-1, -1, -1, -1, -1, -1, -1, -1,
+                       1, 0, 0, 0, 0, 0, 0, 0,
+                       2, 0, 0, 0, 0, 0, 0, 0,
+                       3, 0, 0, 0, 0, 0, 0, 0,
+                       4, 0, 0, 0, 0, 0, 0, 0,
+                       5, 0, 0, 0, 0, 0, 0, 0,
+                       6, 0, 0, 0, 0, 0, 0, 0,
+                       7, 0, 0, 0, 0, 0, 0, 0,
+                       8, 0, 0, 0, 0, 0, 0, 0,
+                       9, 0, 0, 0, 0, 0, 0, 0,
+                       10, 0, 0, 0, 0, 0, 0, 0,
+                       -1, -1, -1, -1, -1, -1, -1, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0x10000000000000000 + i;
+    }
+    Expect.listEquals([0, 1, 2, 3, 4,
+                       5, 6, 7, 8, 9],
+                      view);
+    Expect.listEquals([-1, -1, -1, -1, -1, -1, -1, -1,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       1, 0, 0, 0, 0, 0, 0, 0,
+                       2, 0, 0, 0, 0, 0, 0, 0,
+                       3, 0, 0, 0, 0, 0, 0, 0,
+                       4, 0, 0, 0, 0, 0, 0, 0,
+                       5, 0, 0, 0, 0, 0, 0, 0,
+                       6, 0, 0, 0, 0, 0, 0, 0,
+                       7, 0, 0, 0, 0, 0, 0, 0,
+                       8, 0, 0, 0, 0, 0, 0, 0,
+                       9, 0, 0, 0, 0, 0, 0, 0,
+                       -1, -1, -1, -1, -1, -1, -1, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 0xFFFFFFFFFFFFFFFF - i;
+    }
+    Expect.listEquals([0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE,
+                       0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFC,
+                       0xFFFFFFFFFFFFFFFB, 0xFFFFFFFFFFFFFFFA,
+                       0xFFFFFFFFFFFFFFF9, 0xFFFFFFFFFFFFFFF8,
+                       0xFFFFFFFFFFFFFFF7, 0xFFFFFFFFFFFFFFF6],
+                      view);
+    Expect.listEquals([-1, -1, -1, -1, -1, -1, -1, -1,
+                       -1, -1, -1, -1, -1, -1, -1, -1,
+                       -2, -1, -1, -1, -1, -1, -1, -1,
+                       -3, -1, -1, -1, -1, -1, -1, -1,
+                       -4, -1, -1, -1, -1, -1, -1, -1,
+                       -5, -1, -1, -1, -1, -1, -1, -1,
+                       -6, -1, -1, -1, -1, -1, -1, -1,
+                       -7, -1, -1, -1, -1, -1, -1, -1,
+                       -8, -1, -1, -1, -1, -1, -1, -1,
+                       -9, -1, -1, -1, -1, -1, -1, -1,
+                       -10, -1, -1, -1, -1, -1, -1, -1,
+                       -1, -1, -1, -1, -1, -1, -1, -1],
+                      array);
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = i;
+    }
+    var copy = view.getRange(0, view.length);
+    Expect.isFalse(copy === view);
+    Expect.isTrue(copy is Uint64List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(view, copy);
+    var region = view.getRange(3, view.length - 6);
+    Expect.isTrue(copy is Uint64List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3, 4, 5, 6], region);
+    view.setRange(3, 4, [0x10000000000000001, 0, 1, 0xFFFFFFFFFFFFFFFF]);
+    Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFFFFFFFFFFFFFF, 7, 8, 9],
+                      view);
+    Expect.listEquals([-1, -1, -1, -1, -1, -1, -1, -1,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       1, 0, 0, 0, 0, 0, 0, 0,
+                       2, 0, 0, 0, 0, 0, 0, 0,
+                       1, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       1, 0, 0, 0, 0, 0, 0, 0,
+                       -1, -1, -1, -1, -1, -1, -1, -1,
+                       7, 0, 0, 0, 0, 0, 0, 0,
+                       8, 0, 0, 0, 0, 0, 0, 0,
+                       9, 0, 0, 0, 0, 0, 0, 0,
+                       -1, -1, -1, -1, -1, -1, -1, -1],
+                      array);
+  }
+
+  static testUint64ListView() {
+    var array = new Int8List(96);
+    testUint64ListViewImpl(array);
+  }
+
+  static testFloat32ListViewImpl(var array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(12, array.length);
+    Expect.equals(4, array.bytesPerElement());
+    Expect.equals(48, array.lengthInBytes());
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xBF800000;
+    }
+    Expect.throws(() { new Float32List.view(array.asByteArray(), -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Float32List.view(array.asByteArray(), 0, -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Float32List.view(array.asByteArray(),
+                                            array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Float32List.view(array.asByteArray(),
+                                            0, array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Float32List.view(array.asByteArray(),
+                                            array.lengthInBytes() - 1, 2); },
+                  (e) { return e is RangeError; });
+    var empty = new Float32List.view(array.asByteArray(),
+                                     array.lengthInBytes());
+    Expect.isTrue(empty is List<double>);
+    Expect.isTrue(empty is Float32List);
+    Expect.equals(0, empty.length);
+    var whole = new Float32List.view(array.asByteArray());
+    Expect.isTrue(whole is List<double>);
+    Expect.isTrue(whole is Float32List);
+    Expect.equals(12, whole.length);
+    var view = new Float32List.view(array.asByteArray(), 4, 10);
+    Expect.isTrue(view is List<double>);
+    Expect.isTrue(view is Float32List);
+    Expect.equals(10, view.length);
+    Expect.equals(4, view.bytesPerElement());
+    Expect.equals(40, view.lengthInBytes());
+    Expect.listEquals([-1.0, -1.0, -1.0, -1.0, -1.0,
+                       -1.0, -1.0, -1.0, -1.0, -1.0],
+                      view);
+    Expect.throws(() { view[-1] = 0.0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return view[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[10] = 0.0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 1.0 + i;
+    }
+    Expect.listEquals([1.0, 2.0, 3.0, 4.0, 5.0,
+                       6.0, 7.0, 8.0, 9.0, 10.0],
+                      view);
+    Expect.listEquals([0xBF800000, 0x3F800000,
+                       0x40000000, 0x40400000,
+                       0x40800000, 0x40A00000,
+                       0x40C00000, 0x40E00000,
+                       0x41000000, 0x41100000,
+                       0x41200000, 0xBF800000],
+                      array);
+    // TODO: min, max, and round
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = i * 1.0;
+    }
+    var copy = view.getRange(0, view.length);
+    Expect.isFalse(copy === view);
+    Expect.isTrue(copy is Float32List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(view, copy);
+    var region = view.getRange(3, view.length - 6);
+    Expect.isTrue(copy is Float32List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3.0, 4.0, 5.0, 6.0], region);
+    view.setRange(3, 4, [double.NEGATIVE_INFINITY, 0.0, 1.0, double.INFINITY]);
+    Expect.listEquals([0.0, 1.0, 2.0, double.NEGATIVE_INFINITY, 0.0,
+                       1.0, double.INFINITY, 7.0, 8.0, 9.0],
+                      view);
+    Expect.listEquals([0xBF800000, 0x00000000,
+                       0x3F800000, 0x40000000,
+                       0xFF800000, 0x00000000,
+                       0x3F800000, 0x7F800000,
+                       0x40E00000, 0x41000000,
+                       0x41100000, 0xBF800000],
+                      array);
+  }
+
+  static testFloat32ListView() {
+    var array = new Uint32List(12);
+    testFloat32ListViewImpl(array);
+  }
+
+  static testFloat64ListViewImpl(var array) {
+    Expect.isTrue(array is List<int>);
+    Expect.equals(12, array.length);
+    Expect.equals(8, array.bytesPerElement());
+    Expect.equals(96, array.lengthInBytes());
+    for (int i = 0; i < array.length; ++i) {
+      array[i] = 0xBFF0000000000000;
+    }
+    Expect.throws(() { new Float64List.view(array.asByteArray(), -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Float64List.view(array.asByteArray(), 0, -1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Float64List.view(array.asByteArray(),
+                                            array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Float64List.view(array.asByteArray(),
+                                            0, array.lengthInBytes() + 1); },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { new Float64List.view(array.asByteArray(),
+                                            array.lengthInBytes() - 1, 2); },
+                  (e) { return e is RangeError; });
+    var empty = new Float64List.view(array.asByteArray(),
+                                     array.lengthInBytes());
+    Expect.isTrue(empty is List<double>);
+    Expect.isTrue(empty is Float64List);
+    Expect.equals(0, empty.length);
+    var whole = new Float64List.view(array.asByteArray());
+    Expect.isTrue(whole is List<double>);
+    Expect.isTrue(whole is Float64List);
+    Expect.equals(12, whole.length);
+    var view = new Float64List.view(array.asByteArray(), 8, 10);
+    Expect.isTrue(view is List<double>);
+    Expect.isTrue(view is Float64List);
+    Expect.equals(10, view.length);
+    Expect.equals(8, view.bytesPerElement());
+    Expect.equals(80, view.lengthInBytes());
+    Expect.listEquals([-1.0, -1.0, -1.0, -1.0, -1.0,
+                       -1.0, -1.0, -1.0, -1.0, -1.0],
+                      view);
+    Expect.throws(() { view[-1] = 0.0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { return view[-1]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[10]; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { view[10] = 0.0; },
+                  (e) { return e is RangeError; });
+    Expect.throws(() { array.add(0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addAll([0]); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.addLast(0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.clear(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.insertRange(0, array.length, 0.0); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.length = 0; },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeLast(); },
+                  (e) { return e is UnsupportedError; });
+    Expect.throws(() { array.removeRange(0, array.length - 1); },
+                  (e) { return e is UnsupportedError; });
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = 1.0 + i;
+    }
+    Expect.listEquals([1.0, 2.0, 3.0, 4.0, 5.0,
+                       6.0, 7.0, 8.0, 9.0, 10.0],
+                      view);
+    Expect.listEquals([0xBFF0000000000000, 0x3FF0000000000000,
+                       0x4000000000000000, 0x4008000000000000,
+                       0x4010000000000000, 0x4014000000000000,
+                       0x4018000000000000, 0x401C000000000000,
+                       0x4020000000000000, 0x4022000000000000,
+                       0x4024000000000000, 0xBFF0000000000000],
+                      array);
+    // TODO: min, max
+    for (int i = 0; i < view.length; ++i) {
+      view[i] = i * 1.0;
+    }
+    var copy = view.getRange(0, view.length);
+    Expect.isFalse(copy === view);
+    Expect.isTrue(copy is Float64List);
+    Expect.equals(10, copy.length);
+    Expect.listEquals(view, copy);
+    var region = view.getRange(3, view.length - 6);
+    Expect.isTrue(copy is Float64List);
+    Expect.equals(4, region.length);
+    Expect.listEquals([3.0, 4.0, 5.0, 6.0], region);
+    view.setRange(3, 4, [double.NEGATIVE_INFINITY, 0.0, 1.0, double.INFINITY]);
+    Expect.listEquals([0.0, 1.0, 2.0, double.NEGATIVE_INFINITY, 0.0,
+                       1.0, double.INFINITY, 7.0, 8.0, 9.0],
+                      view);
+    Expect.listEquals([0xBFF0000000000000, 0x0000000000000000,
+                       0x3FF0000000000000, 0x4000000000000000,
+                       0xFFF0000000000000, 0x0000000000000000,
+                       0x3FF0000000000000, 0x7FF0000000000000,
+                       0x401C000000000000, 0x4020000000000000,
+                       0x4022000000000000, 0xBFF0000000000000],
+                      array);
+  }
+
+  static testFloat64ListView() {
+    var array = new Uint64List(12);
+    testFloat64ListViewImpl(array);
+  }
+
+  static testMain() {
+    testInt8List();
+    testUint8List();
+    testInt16List();
+    testUint16List();
+    testInt32List();
+    testUint32List();
+    testInt64List();
+    testUint64List();
+    testFloat32List();
+    testFloat64List();
+    //testByteList();
+    testInt8ListView();
+    testUint8ListView();
+    testInt16ListView();
+    testUint16ListView();
+    testInt32ListView();
+    testUint32ListView();
+    testInt64ListView();
+    testUint64ListView();
+    testFloat32ListView();
+    testFloat64ListView();
+  }
+}
+
+main() {
+  for (var i=0; i<1000; i++) {
+    OptimizedByteArrayTest.testMain();
+  }
+}
diff --git a/runtime/tests/vm/dart/byte_array_test.dart b/runtime/tests/vm/dart/byte_array_test.dart
index d984365..8ebe03c 100644
--- a/runtime/tests/vm/dart/byte_array_test.dart
+++ b/runtime/tests/vm/dart/byte_array_test.dart
@@ -2405,5 +2405,7 @@
 }
 
 main() {
-  ByteArrayTest.testMain();
+  for (var i=0; i<1000; i++) {
+    ByteArrayTest.testMain();
+  }
 }
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index c944645..5d7f315 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -32,6 +32,7 @@
 [ $compiler == dart2js || $compiler == dartc ]
 dart/isolate_mirror*: Skip # compilers not aware of dart:mirrors
 dart/byte_array_test: Skip # compilers not aware of byte arrays
+dart/byte_array_optimized_test: Skip # compilers not aware of byte arrays
 dart/isolate_unhandled*: Skip
 
 [ $compiler == dart2js ]
@@ -65,7 +66,6 @@
 cc/IcDataAccess: Skip
 cc/Jump: Skip
 cc/PatchStaticCall: Skip
-cc/Simple: Skip
 cc/UseDartApi: Skip
 # Tests needing Dart execution.
 dart/*: Skip
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 817a58f..183e164 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -72,7 +72,7 @@
   const uint32_t offset_mask = (1 << 12) - 1;
   uint32_t offset = encoding_ & offset_mask;
   ASSERT(offset < (1 << 10));  // In the range 0 to +1020.
-  ASSERT(Utils::Utils::IsAligned(offset, 2));  // Multiple of 4.
+  ASSERT(Utils::IsAligned(offset, 4));  // Multiple of 4.
   int mode = encoding_ & ((8|4|1) << 21);
   ASSERT((mode == Offset) || (mode == NegOffset));
   uint32_t vencoding = (encoding_ & (0xf << kRnShift)) | (offset >> 2);
@@ -83,6 +83,17 @@
 }
 
 
+void Assembler::InitializeMemoryWithBreakpoints(uword data, int length) {
+  ASSERT(Utils::IsAligned(data, 4));
+  ASSERT(Utils::IsAligned(length, 4));
+  const uword end = data + length;
+  while (data < end) {
+    *reinterpret_cast<int32_t*>(data) = Instr::kBreakPointInstruction;
+    data += 4;
+  }
+}
+
+
 void Assembler::Emit(int32_t value) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   buffer_.Emit<int32_t>(value);
@@ -1020,7 +1031,18 @@
 
 
 void Assembler::LoadObject(Register rd, const Object& object) {
-  UNIMPLEMENTED();
+  // TODO(regis): If the object is never relocated (null, true, false, ...),
+  // load as immediate.
+  const int32_t offset =
+      Array::data_offset() + 4*AddObject(object) - kHeapObjectTag;
+  if (Address::CanHoldLoadOffset(kLoadWord, offset)) {
+    ldr(rd, Address(CP, offset));
+  } else {
+    int32_t offset12_hi = offset & ~kOffset12Mask;  // signed
+    uint32_t offset12_lo = offset & kOffset12Mask;  // unsigned
+    AddConstant(rd, CP, offset12_hi);
+    ldr(rd, Address(rd, offset12_lo));
+  }
 }
 
 
@@ -1139,22 +1161,37 @@
 
 
 void Assembler::Branch(const ExternalLabel* label) {
-  // TODO(regis): Revisit this code sequence.
   LoadImmediate(IP, label->address());  // Target address is never patched.
   mov(PC, ShifterOperand(IP));
 }
 
 
 void Assembler::BranchLink(const ExternalLabel* label) {
-  // TODO(regis): Revisit this code sequence.
-  // Make sure that CodePatcher is able to patch this code sequence.
+  // TODO(regis): Make sure that CodePatcher is able to patch the label referred
+  // to by this code sequence.
   // For added code robustness, use 'blx lr' in a patchable sequence and
   // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors).
-  ldr(LR, Address(PC));
-  Label skip;
-  b(&skip);
-  Emit(label->address());  // May get patched.
-  Bind(&skip);
+  const int32_t offset =
+      Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag;
+  if (Address::CanHoldLoadOffset(kLoadWord, offset)) {
+    ldr(LR, Address(CP, offset));
+  } else {
+    int32_t offset12_hi = offset & ~kOffset12Mask;  // signed
+    uint32_t offset12_lo = offset & kOffset12Mask;  // unsigned
+    // Inline a simplified version of AddConstant(LR, CP, offset12_hi).
+    ShifterOperand shifter_op;
+    if (ShifterOperand::CanHold(offset12_hi, &shifter_op)) {
+      add(LR, CP, shifter_op);
+    } else {
+      movw(LR, Utils::Low16Bits(offset12_hi));
+      const uint16_t value_high = Utils::High16Bits(offset12_hi);
+      if (value_high != 0) {
+        movt(LR, value_high);
+      }
+      add(LR, CP, ShifterOperand(LR));
+    }
+    ldr(LR, Address(LR, offset12_lo));
+  }
   blx(LR);  // Use blx instruction so that the return branch prediction works.
 }
 
@@ -1494,6 +1531,29 @@
   return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8);
 }
 
+
+int32_t Assembler::AddObject(const Object& obj) {
+  for (int i = 0; i < object_pool_.Length(); i++) {
+    if (object_pool_.At(i) == obj.raw()) {
+      return i;
+    }
+  }
+  object_pool_.Add(obj);
+  return object_pool_.Length();
+}
+
+
+int32_t Assembler::AddExternalLabel(const ExternalLabel* label) {
+  const uword address = label->address();
+  ASSERT(Utils::IsAligned(address, 4));
+  // The address is stored in the object array as a RawSmi.
+  const Smi& smi = Smi::Handle(Smi::New(address >> kSmiTagShift));
+  // Do not reuse an existing entry, since each reference may be patched
+  // independently.
+  object_pool_.Add(smi);
+  return object_pool_.Length();
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index b998894e..1b45703 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -262,7 +262,11 @@
 
 class Assembler : public ValueObject {
  public:
-  Assembler() : buffer_(), prologue_offset_(-1), comments_() { }
+  Assembler()
+      : buffer_(),
+        object_pool_(GrowableObjectArray::Handle(GrowableObjectArray::New())),
+        prologue_offset_(-1),
+        comments_() { }
   ~Assembler() { }
 
   void PopRegister(Register r) { Pop(r); }
@@ -273,11 +277,16 @@
   int CodeSize() const { return buffer_.Size(); }
   int prologue_offset() const { return prologue_offset_; }
   const ZoneGrowableArray<int>& GetPointerOffsets() const {
+    ASSERT(buffer_.pointer_offsets().length() == 0);  // No pointers in code.
     return buffer_.pointer_offsets();
   }
+  const GrowableObjectArray& object_pool() const {
+    return object_pool_;
+  }
 
   void FinalizeInstructions(const MemoryRegion& region) {
     buffer_.FinalizeInstructions(region);
+    ASSERT(object_pool_.Length() == 0);  // TODO(regis): Otherwise, more work.
   }
 
   // Debugging and bringup support.
@@ -286,9 +295,7 @@
   void Untested(const char* message);
   void Unreachable(const char* message);
 
-  static void InitializeMemoryWithBreakpoints(uword data, int length) {
-    UNIMPLEMENTED();
-  }
+  static void InitializeMemoryWithBreakpoints(uword data, int length);
 
   void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
 
@@ -525,9 +532,12 @@
   void Emit(int32_t value);
 
  private:
-  AssemblerBuffer buffer_;
-  ZoneGrowableArray<int>* pointer_offsets_;
-  int prologue_offset_;
+  AssemblerBuffer buffer_;  // Contains position independent code.
+  const GrowableObjectArray& object_pool_;  // Objects and jump targets.
+  int32_t prologue_offset_;
+
+  int32_t AddObject(const Object& obj);
+  int32_t AddExternalLabel(const ExternalLabel* label);
 
   class CodeComment : public ZoneAllocated {
    public:
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 856f212..9d92c48 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -16,13 +16,14 @@
 
 
 ASSEMBLER_TEST_GENERATE(Simple, assembler) {
-  UNIMPLEMENTED();
+  __ mov(R0, ShifterOperand(42));
+  __ mov(PC, ShifterOperand(LR));
 }
 
 
 ASSEMBLER_TEST_RUN(Simple, entry) {
   typedef int (*SimpleCode)();
-  EXPECT_EQ(42, reinterpret_cast<SimpleCode>(entry)());
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, entry));
 }
 
 }  // namespace dart
diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc
index 7321a8b..8e263f5 100644
--- a/runtime/vm/assembler_mips_test.cc
+++ b/runtime/vm/assembler_mips_test.cc
@@ -22,7 +22,7 @@
 
 ASSEMBLER_TEST_RUN(Simple, entry) {
   typedef int (*SimpleCode)();
-  EXPECT_EQ(42, reinterpret_cast<SimpleCode>(entry)());
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, entry));
 }
 
 }  // namespace dart
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 5720b0a..27f949b 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -49,7 +49,8 @@
 
 
 RawScript* Bootstrap::LoadCollectionDevScript(bool patch) {
-  const char* url = patch ? "dart:collection-dev-patch" : "dart:collection-dev";
+  const char* url =
+      patch ? "dart:_collection-dev-patch" : "dart:_collection-dev";
   const char* source = patch ? collection_dev_source_ : collection_dev_source_;
   return LoadScript(url, source, patch);
 }
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index e0324f0..babed80 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -196,10 +196,8 @@
         propagator.PropagateTypes();
       }
 
-      // Verify that the use lists are still valid.
-      DEBUG_ASSERT(flow_graph->ValidateUseLists());
-
       // Propagate sminess from CheckSmi to phis.
+      flow_graph->ComputeUseLists();
       optimizer.PropagateSminess();
 
       // Use propagated class-ids to optimize further.
@@ -244,7 +242,6 @@
         // We have to perform range analysis after LICM because it
         // optimistically moves CheckSmi through phis into loop preheaders
         // making some phis smi.
-        flow_graph->ComputeUseLists();
         optimizer.InferSmiRanges();
       }
 
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 4d477db..747b9a8 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -295,6 +295,8 @@
     kPCReadOffset = 8
   };
 
+  static const int32_t kBreakPointInstruction =  // svc #kBreakpointSvcCode
+      ((AL << kConditionShift) | (0xf << 24) | kBreakpointSvcCode);
   static const int kBreakPointInstructionSize = kInstrSize;
   bool IsBreakPoint() {
     return IsBkpt();
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index a10d329..7a68fc2 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -134,12 +134,11 @@
 }
 
 
-ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp,
-                                 const Context& ctx)
+ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp, const Code& code)
     : pc_(pc), fp_(fp), sp_(sp),
-      ctx_(Context::ZoneHandle(ctx.raw())),
-      function_(Function::ZoneHandle()),
-      code_(Code::ZoneHandle()),
+      ctx_(Context::ZoneHandle()),
+      code_(Code::ZoneHandle(code.raw())),
+      function_(Function::ZoneHandle(code.function())),
       token_pos_(-1),
       pc_desc_index_(-1),
       line_number_(-1),
@@ -151,24 +150,6 @@
 }
 
 
-const Code& ActivationFrame::DartCode() {
-  if (code_.IsNull()) {
-    Isolate* isolate = Isolate::Current();
-    ASSERT(isolate != NULL);
-    code_ = Code::LookupCode(pc_);
-  }
-  return code_;
-}
-
-
-const Function& ActivationFrame::DartFunction() {
-  if (function_.IsNull()) {
-    function_ = DartCode().function();
-  }
-  return function_;
-}
-
-
 void Debugger::SignalIsolateEvent(EventType type) {
   if (event_handler_ != NULL) {
     Debugger* debugger = Isolate::Current()->debugger();
@@ -241,8 +222,7 @@
 
 
 RawString* ActivationFrame::QualifiedFunctionName() {
-  const Function& func = DartFunction();
-  return String::New(Debugger::QualifiedFunctionName(func));
+  return String::New(Debugger::QualifiedFunctionName(function()));
 }
 
 
@@ -253,23 +233,19 @@
 
 
 RawScript* ActivationFrame::SourceScript() {
-  const Function& func = DartFunction();
-  return func.script();
+  return function().script();
 }
 
 
 RawLibrary* ActivationFrame::Library() {
-  const Function& func = DartFunction();
-  const Class& cls = Class::Handle(func.Owner());
+  const Class& cls = Class::Handle(function().Owner());
   return cls.library();
 }
 
 
 void ActivationFrame::GetPcDescriptors() {
   if (pc_desc_.IsNull()) {
-    const Code& code = DartCode();
-    ASSERT(!code.IsNull());
-    pc_desc_ = code.pc_descriptors();
+    pc_desc_ = code().pc_descriptors();
     ASSERT(!pc_desc_.IsNull());
   }
 }
@@ -320,8 +296,7 @@
 
 void ActivationFrame::GetVarDescriptors() {
   if (var_descriptors_.IsNull()) {
-    const Code& code = DartCode();
-    var_descriptors_ = code.var_descriptors();
+    var_descriptors_ = code().var_descriptors();
     ASSERT(!var_descriptors_.IsNull());
   }
 }
@@ -363,7 +338,7 @@
 }
 
 
-RawContext* ActivationFrame::CallerContext() {
+RawContext* ActivationFrame::GetSavedContext() {
   GetVarDescriptors();
   intptr_t var_desc_len = var_descriptors_.Length();
   for (int i = 0; i < var_desc_len; i++) {
@@ -373,8 +348,8 @@
       return reinterpret_cast<RawContext*>(GetLocalVarValue(var_info.index));
     }
   }
-  // Caller uses same context chain.
-  return ctx_.raw();
+  UNREACHABLE();
+  return Context::null();
 }
 
 
@@ -388,8 +363,7 @@
     ActivationFrame* frame = trace_[frame_index];
     intptr_t try_index = frame->TryIndex();
     if (try_index < 0) continue;
-    const Code& code = frame->DartCode();
-    handlers = code.exception_handlers();
+    handlers = frame->code().exception_handlers();
     ASSERT(!handlers.IsNull());
     intptr_t num_handlers_checked = 0;
     while (try_index >= 0) {
@@ -426,7 +400,7 @@
   // Rather than potentially displaying incorrect values, we
   // pretend that there are no variables in the frame.
   // We should be more clever about this in the future.
-  if (DartCode().is_optimized()) {
+  if (code().is_optimized()) {
     vars_initialized_ = true;
     return;
   }
@@ -563,10 +537,9 @@
 const char* ActivationFrame::ToCString() {
   const char* kFormat = "Function: '%s' url: '%s' line: %d";
 
-  const Function& func = DartFunction();
   const String& url = String::Handle(SourceUrl());
   intptr_t line = LineNumber();
-  const char* func_name = Debugger::QualifiedFunctionName(func);
+  const char* func_name = Debugger::QualifiedFunctionName(function());
 
   intptr_t len =
       OS::SNPrint(NULL, 0, kFormat, func_name, url.ToCString(), line);
@@ -880,17 +853,31 @@
 
 
 DebuggerStackTrace* Debugger::CollectStackTrace() {
+  Isolate* isolate = Isolate::Current();
   DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8);
-  Context& ctx = Context::Handle(Isolate::Current()->top_context());
-  DartFrameIterator iterator;
+  Context& ctx = Context::Handle(isolate->top_context());
+  Code& code = Code::Handle(isolate);
+  StackFrameIterator iterator(false);
   StackFrame* frame = iterator.NextFrame();
+  bool get_saved_context = false;
   while (frame != NULL) {
     ASSERT(frame->IsValid());
-    ASSERT(frame->IsDartFrame());
-    ActivationFrame* activation =
-        new ActivationFrame(frame->pc(), frame->fp(), frame->sp(), ctx);
-    ctx = activation->CallerContext();
-    stack_trace->AddActivation(activation);
+    if (frame->IsDartFrame()) {
+      code = frame->LookupDartCode();
+      ActivationFrame* activation = new ActivationFrame(frame->pc(),
+                                                        frame->fp(),
+                                                        frame->sp(),
+                                                        code);
+      if (get_saved_context) {
+        ctx = activation->GetSavedContext();
+      }
+      activation->SetContext(ctx);
+      stack_trace->AddActivation(activation);
+      get_saved_context = activation->function().IsClosureFunction();
+    } else if (frame->IsEntryFrame()) {
+      ctx = reinterpret_cast<EntryFrame*>(frame)->SavedContext();
+      get_saved_context = false;
+    }
     frame = iterator.NextFrame();
   }
   return stack_trace;
@@ -1486,7 +1473,7 @@
       // If we are at the function return, do a StepOut action.
       if (stack_trace->Length() > 1) {
         ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1);
-        func_to_instrument = caller_frame->DartFunction().raw();
+        func_to_instrument = caller_frame->function().raw();
       }
     }
   } else if (resume_action_ == kStepInto) {
@@ -1526,7 +1513,7 @@
       // Treat like stepping out to caller.
       if (stack_trace->Length() > 1) {
         ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1);
-        func_to_instrument = caller_frame->DartFunction().raw();
+        func_to_instrument = caller_frame->function().raw();
       }
     }
   } else {
@@ -1534,7 +1521,7 @@
     // Set stepping breakpoints in the caller.
     if (stack_trace->Length() > 1) {
       ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1);
-      func_to_instrument = caller_frame->DartFunction().raw();
+      func_to_instrument = caller_frame->function().raw();
     }
   }
 
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index b85cfc7..2d7cbe8 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -119,20 +119,27 @@
 // on the call stack.
 class ActivationFrame : public ZoneAllocated {
  public:
-  explicit ActivationFrame(uword pc, uword fp, uword sp, const Context& ctx);
+  ActivationFrame(uword pc, uword fp, uword sp, const Code& code);
 
   uword pc() const { return pc_; }
   uword fp() const { return fp_; }
   uword sp() const { return sp_; }
+  const Function& function() const {
+    ASSERT(!function_.IsNull());
+    return function_;
+  }
+  const Code& code() const {
+    ASSERT(!code_.IsNull());
+    return code_;
+  }
 
-  const Function& DartFunction();
-  const Code& DartCode();
   RawString* QualifiedFunctionName();
   RawString* SourceUrl();
   RawScript* SourceScript();
   RawLibrary* Library();
   intptr_t TokenPos();
   intptr_t LineNumber();
+  void SetContext(const Context& ctx) { ctx_ = ctx.raw(); }
 
   // The context level of a frame is the context level at the
   // PC/token index of the frame. It determines the depth of the context
@@ -150,7 +157,7 @@
                   Instance* value);
 
   RawArray* GetLocalVariables();
-  RawContext* CallerContext();
+  RawContext* GetSavedContext();
 
  private:
   intptr_t PcDescIndex();
@@ -166,10 +173,9 @@
   uword sp_;
 
   // The anchor of the context chain for this function.
-  const Context& ctx_;
-
-  Function& function_;
-  Code& code_;
+  Context& ctx_;
+  const Code& code_;
+  const Function& function_;
   intptr_t token_pos_;
   intptr_t pc_desc_index_;
   intptr_t line_number_;
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 20f0e3f..bcde541 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -169,7 +169,9 @@
 }
 
 
-static void VerifyListEquals(Dart_Handle expected, Dart_Handle got) {
+static void VerifyListEquals(Dart_Handle expected,
+                             Dart_Handle got,
+                             bool skip_null_expects) {
   EXPECT(Dart_IsList(expected));
   EXPECT(Dart_IsList(got));
   Dart_Handle res;
@@ -188,14 +190,15 @@
     bool equals;
     res = Dart_ObjectEquals(expected_elem, got_elem, &equals);
     EXPECT_VALID(res);
-    EXPECT(equals);
+    EXPECT(equals || (Dart_IsNull(expected_elem) && skip_null_expects));
   }
 }
 
 
 static void VerifyStackFrame(Dart_ActivationFrame frame,
                              const char* expected_name,
-                             Dart_Handle expected_locals) {
+                             Dart_Handle expected_locals,
+                             bool skip_null_expects) {
   Dart_Handle func_name;
   Dart_Handle res;
   res = Dart_ActivationFrameInfo(frame, &func_name, NULL, NULL, NULL);
@@ -204,13 +207,13 @@
   const char* func_name_chars;
   Dart_StringToCString(func_name, &func_name_chars);
   if (expected_name != NULL) {
-    EXPECT_STREQ(func_name_chars, expected_name);
+    EXPECT_SUBSTRING(expected_name, func_name_chars);
   }
 
   if (!Dart_IsNull(expected_locals)) {
     Dart_Handle locals = Dart_GetLocalVariables(frame);
     EXPECT_VALID(locals);
-    VerifyListEquals(expected_locals, locals);
+    VerifyListEquals(expected_locals, locals, skip_null_expects);
   }
 }
 
@@ -218,7 +221,8 @@
 static void VerifyStackTrace(Dart_StackTrace trace,
                              const char* func_names[],
                              Dart_Handle local_vars[],
-                             int expected_frames) {
+                             int expected_frames,
+                             bool skip_null_expects) {
   intptr_t trace_len;
   Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
   EXPECT_VALID(res);
@@ -227,9 +231,9 @@
     res = Dart_GetActivationFrame(trace, i, &frame);
     EXPECT_VALID(res);
     if (i < expected_frames) {
-      VerifyStackFrame(frame, func_names[i], local_vars[i]);
+      VerifyStackFrame(frame, func_names[i], local_vars[i], skip_null_expects);
     } else {
-      VerifyStackFrame(frame, NULL, Dart_Null());
+      VerifyStackFrame(frame, NULL, Dart_Null(), skip_null_expects);
     }
   }
 }
@@ -639,7 +643,7 @@
   Dart_Handle expected_locals[] = {add_locals, Dart_Null()};
   breakpoint_hit_counter++;
   PrintStackTrace(trace);
-  VerifyStackTrace(trace, expected_trace, expected_locals, 2);
+  VerifyStackTrace(trace, expected_trace, expected_locals, 2, false);
 }
 
 
@@ -1228,6 +1232,321 @@
   EXPECT(interrupt_isolate_id == ILLEGAL_ISOLATE_ID);
 }
 
+
+static void StackTraceDump1BreakpointHandler(Dart_IsolateId isolate_id,
+                                             Dart_Breakpoint bpt,
+                                             Dart_StackTrace trace) {
+  const int kStackTraceLen = 4;
+  static const char* expected_trace[kStackTraceLen] = {
+    "local_to_main",
+    "Test.local1_to_func1",
+    "Test.func1",
+    "main"
+  };
+
+  intptr_t trace_len;
+  Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
+  EXPECT_VALID(res);
+  EXPECT_EQ(kStackTraceLen, trace_len);
+
+  // Frame 0 corresponding to "local_to_main".
+  Dart_Handle frame0_locals = Dart_NewList(8);
+  Dart_ListSetAt(frame0_locals, 0, NewString("i"));
+  Dart_ListSetAt(frame0_locals, 1, Dart_NewInteger(76));
+  Dart_ListSetAt(frame0_locals, 2, NewString("j"));
+  Dart_ListSetAt(frame0_locals, 3, Dart_NewInteger(119));
+  Dart_ListSetAt(frame0_locals, 4, NewString("k"));
+  Dart_ListSetAt(frame0_locals, 5, Dart_NewInteger(66));
+  Dart_ListSetAt(frame0_locals, 6, NewString("l"));
+  Dart_ListSetAt(frame0_locals, 7, Dart_NewInteger(99));
+
+  // Frame 1 corresponding to "Test.local1_to_func1".
+  Dart_Handle frame1_locals = Dart_NewList(14);
+  Dart_ListSetAt(frame1_locals, 0, NewString("i"));
+  Dart_ListSetAt(frame1_locals, 1, Dart_NewInteger(11));
+  Dart_ListSetAt(frame1_locals, 2, NewString("j"));
+  Dart_ListSetAt(frame1_locals, 3, Dart_NewInteger(22));
+  Dart_ListSetAt(frame1_locals, 4, NewString("k"));
+  Dart_ListSetAt(frame1_locals, 5, Dart_NewInteger(33));
+  Dart_ListSetAt(frame1_locals, 6, NewString("l"));
+  Dart_ListSetAt(frame1_locals, 7, Dart_NewInteger(44));
+  Dart_ListSetAt(frame1_locals, 8, NewString("m"));
+  Dart_ListSetAt(frame1_locals, 9, Dart_NewInteger(55));
+  Dart_ListSetAt(frame1_locals, 10, NewString("func"));
+  Dart_ListSetAt(frame1_locals, 11, Dart_Null());
+  Dart_ListSetAt(frame1_locals, 12, NewString("n"));
+  Dart_ListSetAt(frame1_locals, 13, Dart_Null());
+
+  // Frame 2 corresponding to "Test.func1".
+  Dart_Handle frame2_locals = Dart_NewList(18);
+  Dart_ListSetAt(frame2_locals, 0, NewString("this"));
+  Dart_ListSetAt(frame2_locals, 1, Dart_Null());
+  Dart_ListSetAt(frame2_locals, 2, NewString("func"));
+  Dart_ListSetAt(frame2_locals, 3, Dart_Null());
+  Dart_ListSetAt(frame2_locals, 4, NewString("i"));
+  Dart_ListSetAt(frame2_locals, 5, Dart_NewInteger(11));
+  Dart_ListSetAt(frame2_locals, 6, NewString("j"));
+  Dart_ListSetAt(frame2_locals, 7, Dart_NewInteger(22));
+  Dart_ListSetAt(frame2_locals, 8, NewString("k"));
+  Dart_ListSetAt(frame2_locals, 9, Dart_NewInteger(33));
+  Dart_ListSetAt(frame2_locals, 10, NewString("l"));
+  Dart_ListSetAt(frame2_locals, 11, Dart_NewInteger(44));
+  Dart_ListSetAt(frame2_locals, 12, NewString("m"));
+  Dart_ListSetAt(frame2_locals, 13, Dart_NewInteger(55));
+  Dart_ListSetAt(frame2_locals, 14, NewString("local1_to_func1"));
+  Dart_ListSetAt(frame2_locals, 15, Dart_Null());
+  Dart_ListSetAt(frame2_locals, 16, NewString("sum"));
+  Dart_ListSetAt(frame2_locals, 17, Dart_NewInteger(0));
+
+  // Frame 3 corresponding to "main".
+  Dart_Handle frame3_locals = Dart_NewList(14);
+  Dart_ListSetAt(frame3_locals, 0, NewString("i"));
+  Dart_ListSetAt(frame3_locals, 1, Dart_NewInteger(76));
+  Dart_ListSetAt(frame3_locals, 2, NewString("j"));
+  Dart_ListSetAt(frame3_locals, 3, Dart_NewInteger(119));
+  Dart_ListSetAt(frame3_locals, 4, NewString("local_to_main"));
+  Dart_ListSetAt(frame3_locals, 5, Dart_Null());
+  Dart_ListSetAt(frame3_locals, 6, NewString("sum"));
+  Dart_ListSetAt(frame3_locals, 7, Dart_NewInteger(0));
+  Dart_ListSetAt(frame3_locals, 8, NewString("value"));
+  Dart_ListSetAt(frame3_locals, 9, Dart_Null());
+  Dart_ListSetAt(frame3_locals, 10, NewString("func1"));
+  Dart_ListSetAt(frame3_locals, 11, Dart_Null());
+  Dart_ListSetAt(frame3_locals, 12, NewString("main_local"));
+  Dart_ListSetAt(frame3_locals, 13, Dart_Null());
+
+  Dart_Handle expected_locals[] = {
+    frame0_locals,
+    frame1_locals,
+    frame2_locals,
+    frame3_locals
+  };
+  breakpoint_hit_counter++;
+  VerifyStackTrace(trace, expected_trace, expected_locals,
+                   kStackTraceLen, true);
+}
+
+
+TEST_CASE(Debug_StackTraceDump1) {
+  const char* kScriptChars =
+      "class Test {\n"
+      "  Test(int local);\n"
+      "\n"
+      "  int func1(int func(int i, int j)) {\n"
+      "    var i = 0;\n"
+      "    var j = 0;\n"
+      "    var k = 0;\n"
+      "    var l = 0;\n"
+      "    var m = 0;\n"
+      "    int local1_to_func1(int func(int i, int j)) {\n"
+      "      // Capture i and j here.\n"
+      "      i = 11;\n"
+      "      j = 22;\n"
+      "      k = 33;\n"
+      "      l = 44;\n"
+      "      m = 55;\n"
+      "      var n = func(i + j + k, l + m);\n"
+      "      return n;\n"
+      "    }\n"
+      "    var sum = 0;\n"
+      "    return local1_to_func1(func);\n"
+      "  }\n"
+      "\n"
+      "  int local;\n"
+      "}\n"
+      "\n"
+      "int main() {\n"
+      "  var i = 10;\n"
+      "  var j = 20;\n"
+      "  int local_to_main(int k, int l) {\n"
+      "    // Capture i and j here.\n"
+      "    i = i + k;\n"
+      "    j = j + l;\n"
+      "    return i + j;\n"
+      "  }\n"
+      "  var sum = 0;\n"
+      "  Test value = new Test(10);\n"
+      "  var func1 = value.func1;\n"
+      "  var main_local = local_to_main;\n"
+      "  return func1(main_local);\n"
+      "}\n";
+
+  LoadScript(kScriptChars);
+  Dart_SetBreakpointHandler(&StackTraceDump1BreakpointHandler);
+
+  Dart_Handle script_url = NewString(TestCase::url());
+  intptr_t line_no = 34;  // In closure 'local_to_main'.
+  Dart_Handle res = Dart_SetBreakpoint(script_url, line_no);
+  EXPECT_VALID(res);
+  EXPECT(Dart_IsInteger(res));
+
+  breakpoint_hit_counter = 0;
+  Dart_Handle retval = Invoke("main");
+  EXPECT_VALID(retval);
+  int64_t int_value = 0;
+  Dart_IntegerToInt64(retval, &int_value);
+  EXPECT_EQ(195, int_value);
+  EXPECT_EQ(1, breakpoint_hit_counter);
+}
+
+
+static void StackTraceDump2ExceptionHandler(Dart_IsolateId isolate_id,
+                                            Dart_Handle exception_object,
+                                            Dart_StackTrace trace) {
+  const int kStackTraceLen = 5;
+  static const char* expected_trace[kStackTraceLen] = {
+    "Object._noSuchMethod",
+    "Object.noSuchMethod",
+    "Test.local1_to_func1",
+    "Test.func1",
+    "main"
+  };
+
+  intptr_t trace_len;
+  Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
+  EXPECT_VALID(res);
+  EXPECT_EQ(kStackTraceLen, trace_len);
+
+  // Frame 0 corresponding to "Object._noSuchMethod".
+  Dart_Handle frame0_locals = Dart_NewList(10);
+  Dart_ListSetAt(frame0_locals, 0, NewString("this"));
+  Dart_ListSetAt(frame0_locals, 1, Dart_Null());
+  Dart_ListSetAt(frame0_locals, 2, NewString("isMethod"));
+  Dart_ListSetAt(frame0_locals, 3, Dart_Null());
+  Dart_ListSetAt(frame0_locals, 4, NewString("memberName"));
+  Dart_ListSetAt(frame0_locals, 5, Dart_Null());
+  Dart_ListSetAt(frame0_locals, 6, NewString("arguments"));
+  Dart_ListSetAt(frame0_locals, 7, Dart_Null());
+  Dart_ListSetAt(frame0_locals, 8, NewString("namedArguments"));
+  Dart_ListSetAt(frame0_locals, 9, Dart_Null());
+
+  // Frame 1 corresponding to "Object.noSuchMethod".
+  Dart_Handle frame1_locals = Dart_NewList(4);
+  Dart_ListSetAt(frame1_locals, 0, NewString("this"));
+  Dart_ListSetAt(frame1_locals, 1, Dart_Null());
+  Dart_ListSetAt(frame1_locals, 2, NewString("invocation"));
+  Dart_ListSetAt(frame1_locals, 3, Dart_Null());
+
+  // Frame 2 corresponding to "Test.local1_to_func1".
+  Dart_Handle frame2_locals = Dart_NewList(16);
+  Dart_ListSetAt(frame2_locals, 0, NewString("i"));
+  Dart_ListSetAt(frame2_locals, 1, Dart_NewInteger(11));
+  Dart_ListSetAt(frame2_locals, 2, NewString("j"));
+  Dart_ListSetAt(frame2_locals, 3, Dart_NewInteger(22));
+  Dart_ListSetAt(frame2_locals, 4, NewString("k"));
+  Dart_ListSetAt(frame2_locals, 5, Dart_NewInteger(33));
+  Dart_ListSetAt(frame2_locals, 6, NewString("l"));
+  Dart_ListSetAt(frame2_locals, 7, Dart_NewInteger(44));
+  Dart_ListSetAt(frame2_locals, 8, NewString("m"));
+  Dart_ListSetAt(frame2_locals, 9, Dart_NewInteger(55));
+  Dart_ListSetAt(frame2_locals, 10, NewString("this"));
+  Dart_ListSetAt(frame2_locals, 11, Dart_Null());
+  Dart_ListSetAt(frame2_locals, 12, NewString("func"));
+  Dart_ListSetAt(frame2_locals, 13, Dart_Null());
+  Dart_ListSetAt(frame2_locals, 14, NewString("n"));
+  Dart_ListSetAt(frame2_locals, 15, Dart_Null());
+
+  // Frame 3 corresponding to "Test.func1".
+  Dart_Handle frame3_locals = Dart_NewList(18);
+  Dart_ListSetAt(frame3_locals, 0, NewString("this"));
+  Dart_ListSetAt(frame3_locals, 1, Dart_Null());
+  Dart_ListSetAt(frame3_locals, 2, NewString("func"));
+  Dart_ListSetAt(frame3_locals, 3, Dart_Null());
+  Dart_ListSetAt(frame3_locals, 4, NewString("i"));
+  Dart_ListSetAt(frame3_locals, 5, Dart_NewInteger(11));
+  Dart_ListSetAt(frame3_locals, 6, NewString("j"));
+  Dart_ListSetAt(frame3_locals, 7, Dart_NewInteger(22));
+  Dart_ListSetAt(frame3_locals, 8, NewString("k"));
+  Dart_ListSetAt(frame3_locals, 9, Dart_NewInteger(33));
+  Dart_ListSetAt(frame3_locals, 10, NewString("l"));
+  Dart_ListSetAt(frame3_locals, 11, Dart_NewInteger(44));
+  Dart_ListSetAt(frame3_locals, 12, NewString("m"));
+  Dart_ListSetAt(frame3_locals, 13, Dart_NewInteger(55));
+  Dart_ListSetAt(frame3_locals, 14, NewString("local1_to_func1"));
+  Dart_ListSetAt(frame3_locals, 15, Dart_Null());
+  Dart_ListSetAt(frame3_locals, 16, NewString("sum"));
+  Dart_ListSetAt(frame3_locals, 17, Dart_NewInteger(0));
+
+  // Frame 4 corresponding to "main".
+  Dart_Handle frame4_locals = Dart_NewList(12);
+  Dart_ListSetAt(frame4_locals, 0, NewString("i"));
+  Dart_ListSetAt(frame4_locals, 1, Dart_NewInteger(10));
+  Dart_ListSetAt(frame4_locals, 2, NewString("j"));
+  Dart_ListSetAt(frame4_locals, 3, Dart_NewInteger(20));
+  Dart_ListSetAt(frame4_locals, 4, NewString("local_to_main"));
+  Dart_ListSetAt(frame4_locals, 5, Dart_Null());
+  Dart_ListSetAt(frame4_locals, 6, NewString("sum"));
+  Dart_ListSetAt(frame4_locals, 7, Dart_NewInteger(0));
+  Dart_ListSetAt(frame4_locals, 8, NewString("value"));
+  Dart_ListSetAt(frame4_locals, 9, Dart_Null());
+  Dart_ListSetAt(frame4_locals, 10, NewString("func1"));
+  Dart_ListSetAt(frame4_locals, 11, Dart_Null());
+
+  Dart_Handle expected_locals[] = {
+    frame0_locals,
+    frame1_locals,
+    frame2_locals,
+    frame3_locals,
+    frame4_locals
+  };
+  breakpoint_hit_counter++;
+  VerifyStackTrace(trace, expected_trace, expected_locals,
+                   kStackTraceLen, true);
+}
+
+
+TEST_CASE(Debug_StackTraceDump2) {
+  const char* kScriptChars =
+      "class Test {\n"
+      "  Test(int local);\n"
+      "\n"
+      "  int func1(int func(int i, int j)) {\n"
+      "    var i = 0;\n"
+      "    var j = 0;\n"
+      "    var k = 0;\n"
+      "    var l = 0;\n"
+      "    var m = 0;\n"
+      "    int local1_to_func1(int func(int i, int j)) {\n"
+      "      // Capture i and j here.\n"
+      "      i = 11;\n"
+      "      j = 22;\n"
+      "      k = 33;\n"
+      "      l = 44;\n"
+      "      m = 55;\n"
+      "      var n = junk(i + j + k, l + m);\n"
+      "      return n;\n"
+      "    }\n"
+      "    var sum = 0;\n"
+      "    return local1_to_func1(func);\n"
+      "  }\n"
+      "\n"
+      "  int local;\n"
+      "}\n"
+      "\n"
+      "int main() {\n"
+      "  var i = 10;\n"
+      "  var j = 20;\n"
+      "  int local_to_main(int k, int l) {\n"
+      "    // Capture i and j here.\n"
+      "    return i + j;\n"
+      "  }\n"
+      "  var sum = 0;\n"
+      "  Test value = new Test(10);\n"
+      "  var func1 = value.func1;\n"
+      "  return func1(local_to_main);\n"
+      "}\n";
+
+  LoadScript(kScriptChars);
+  Dart_SetExceptionThrownHandler(&StackTraceDump2ExceptionHandler);
+  breakpoint_hit_counter = 0;
+  Dart_SetExceptionPauseInfo(kPauseOnAllExceptions);
+
+  Dart_Handle retval = Invoke("main");
+  EXPECT(Dart_IsError(retval));
+  EXPECT(Dart_IsUnhandledExceptionError(retval));
+  EXPECT_EQ(1, breakpoint_hit_counter);
+}
+
 #endif  // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64).
 
 }  // namespace dart
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index 58ae9ac..ea66a5a 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -169,7 +169,11 @@
     while (curr != NULL) {
       ASSERT(prev == curr->previous_use());
       ASSERT(defn == curr->definition());
-      ASSERT(curr == curr->instruction()->InputAt(curr->use_index()));
+      Instruction* instr = curr->instruction();
+      // The instruction should not be removed from the graph (phis are not
+      // removed until register allocation.)
+      ASSERT(instr->IsPhi() || (instr->previous() != NULL));
+      ASSERT(curr == instr->InputAt(curr->use_index()));
       prev = curr;
       curr = curr->next_use();
     }
@@ -179,8 +183,11 @@
     while (curr != NULL) {
       ASSERT(prev == curr->previous_use());
       ASSERT(defn == curr->definition());
-      ASSERT(curr ==
-             curr->instruction()->env()->ValueAtUseIndex(curr->use_index()));
+      Instruction* instr = curr->instruction();
+      ASSERT(curr == instr->env()->ValueAtUseIndex(curr->use_index()));
+      // The instruction should not be removed from the graph (phis are not
+      // removed until register allocation.)
+      ASSERT(instr->IsPhi() || (instr->previous() != NULL));
       prev = curr;
       curr = curr->next_use();
     }
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 88c7c9e..236c4d9 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -692,9 +692,9 @@
 
   intptr_t current_context_level = owner()->context_level();
   ASSERT(current_context_level >= 0);
-  if (owner()->parsed_function().saved_context_var() != NULL) {
+  if (owner()->parsed_function().saved_entry_context_var() != NULL) {
     // CTX on entry was saved, but not linked as context parent.
-    BuildLoadContext(*owner()->parsed_function().saved_context_var());
+    BuildLoadContext(*owner()->parsed_function().saved_entry_context_var());
   } else {
     while (current_context_level-- > 0) {
       UnchainContext();
@@ -1870,7 +1870,8 @@
   BuildPushArguments(*node->arguments(), arguments);
 
   // Save context around the call.
-  BuildStoreContext(*owner()->parsed_function().expression_temp_var());
+  ASSERT(owner()->parsed_function().saved_current_context_var() != NULL);
+  BuildStoreContext(*owner()->parsed_function().saved_current_context_var());
   return new ClosureCallInstr(node, arguments);
 }
 
@@ -1878,14 +1879,16 @@
 void EffectGraphVisitor::VisitClosureCallNode(ClosureCallNode* node) {
   Do(BuildClosureCall(node));
   // Restore context from saved location.
-  BuildLoadContext(*owner()->parsed_function().expression_temp_var());
+  ASSERT(owner()->parsed_function().saved_current_context_var() != NULL);
+  BuildLoadContext(*owner()->parsed_function().saved_current_context_var());
 }
 
 
 void ValueGraphVisitor::VisitClosureCallNode(ClosureCallNode* node) {
   Value* result = Bind(BuildClosureCall(node));
   // Restore context from temp.
-  BuildLoadContext(*owner()->parsed_function().expression_temp_var());
+  ASSERT(owner()->parsed_function().saved_current_context_var() != NULL);
+  BuildLoadContext(*owner()->parsed_function().saved_current_context_var());
   ReturnValue(result);
 }
 
@@ -2763,7 +2766,7 @@
 
 bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const {
   return (node == owner()->parsed_function().node_sequence()) &&
-         (owner()->parsed_function().saved_context_var() != NULL);
+         (owner()->parsed_function().saved_entry_context_var() != NULL);
 }
 
 
@@ -2803,7 +2806,7 @@
     // In this case, the parser pre-allocates a variable to save the context.
     if (MustSaveRestoreContext(node)) {
       Value* current_context = Bind(new CurrentContextInstr());
-      Do(BuildStoreTemp(*owner()->parsed_function().saved_context_var(),
+      Do(BuildStoreTemp(*owner()->parsed_function().saved_entry_context_var(),
                         current_context));
       Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle()));
       AddInstruction(new StoreContextInstr(null_context));
@@ -2902,7 +2905,7 @@
   if (is_open()) {
     if (MustSaveRestoreContext(node)) {
       ASSERT(num_context_variables > 0);
-      BuildLoadContext(*owner()->parsed_function().saved_context_var());
+      BuildLoadContext(*owner()->parsed_function().saved_entry_context_var());
     } else if (num_context_variables > 0) {
       UnchainContext();
     }
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 11349ad..880b3eb 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -903,6 +903,8 @@
       return TwoByteString::kBytesPerElement;
     case kExternalUint8ArrayCid:
       return ExternalUint8Array::kBytesPerElement;
+    case kExternalUint8ClampedArrayCid:
+      return ExternalUint8ClampedArray::kBytesPerElement;
     default:
       UNIMPLEMENTED();
       return 0;
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index eb7181f..f7d3f34 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -384,15 +384,19 @@
   static intptr_t DataOffsetFor(intptr_t cid);
   static intptr_t ElementSizeFor(intptr_t cid);
   static FieldAddress ElementAddressForIntIndex(intptr_t cid,
+                                                intptr_t index_scale,
                                                 Register array,
                                                 intptr_t offset);
   static FieldAddress ElementAddressForRegIndex(intptr_t cid,
+                                                intptr_t index_scale,
                                                 Register array,
                                                 Register index);
   static Address ExternalElementAddressForIntIndex(intptr_t cid,
+                                                   intptr_t index_scale,
                                                    Register array,
                                                    intptr_t offset);
   static Address ExternalElementAddressForRegIndex(intptr_t cid,
+                                                   intptr_t index_scale,
                                                    Register array,
                                                    Register index);
 
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 38b9901..d8b220c 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -304,6 +304,7 @@
 
 
 FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
+                                                          intptr_t index_scale,
                                                           Register array,
                                                           intptr_t index) {
   UNIMPLEMENTED();
@@ -312,6 +313,7 @@
 
 
 FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
+                                                          intptr_t index_scale,
                                                           Register array,
                                                           Register index) {
   UNIMPLEMENTED();
@@ -319,17 +321,21 @@
 }
 
 
-Address FlowGraphCompiler::ExternalElementAddressForIntIndex(intptr_t cid,
-                                                             Register array,
-                                                             intptr_t index) {
+Address FlowGraphCompiler::ExternalElementAddressForIntIndex(
+    intptr_t cid,
+    intptr_t index_scale,
+    Register array,
+    intptr_t index) {
   UNIMPLEMENTED();
   return FieldAddress(array, index);
 }
 
 
-Address FlowGraphCompiler::ExternalElementAddressForRegIndex(intptr_t cid,
-                                                             Register array,
-                                                             Register index) {
+Address FlowGraphCompiler::ExternalElementAddressForRegIndex(
+    intptr_t cid,
+    intptr_t index_scale,
+    Register array,
+    Register index) {
   UNIMPLEMENTED();
   return FieldAddress(array, index);
 }
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 102f205..efb9b7b 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -1504,70 +1504,62 @@
 
 
 FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
+                                                          intptr_t index_scale,
                                                           Register array,
                                                           intptr_t index) {
   const int64_t disp =
-      static_cast<int64_t>(index) * ElementSizeFor(cid) + DataOffsetFor(cid);
+      static_cast<int64_t>(index) * index_scale + DataOffsetFor(cid);
   ASSERT(Utils::IsInt(32, disp));
   return FieldAddress(array, static_cast<int32_t>(disp));
 }
 
 
-FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
-                                                          Register array,
-                                                          Register index) {
-  // Note that index is smi-tagged, (i.e, times 2) for all arrays with element
-  // size > 1. For Uint8Array and OneByteString the index is expected to be
-  // untagged before accessing.
+static ScaleFactor ToScaleFactor(intptr_t index_scale) {
+  // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
+  // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
+  // expected to be untagged before accessing.
   ASSERT(kSmiTagShift == 1);
-  switch (cid) {
-    case kArrayCid:
-    case kImmutableArrayCid:
-      return FieldAddress(
-          array, index, TIMES_HALF_WORD_SIZE, Array::data_offset());
-    case kFloat32ArrayCid:
-      return FieldAddress(array, index, TIMES_2, Float32Array::data_offset());
-    case kFloat64ArrayCid:
-      return FieldAddress(array, index, TIMES_4, Float64Array::data_offset());
-    case kInt8ArrayCid:
-      return FieldAddress(array, index, TIMES_1, Int8Array::data_offset());
-    case kUint8ArrayCid:
-      return FieldAddress(array, index, TIMES_1, Uint8Array::data_offset());
-    case kUint8ClampedArrayCid:
-      return
-          FieldAddress(array, index, TIMES_1, Uint8ClampedArray::data_offset());
-    case kInt16ArrayCid:
-      return FieldAddress(array, index, TIMES_1, Int16Array::data_offset());
-    case kUint16ArrayCid:
-      return FieldAddress(array, index, TIMES_1, Uint16Array::data_offset());
-    case kInt32ArrayCid:
-      return FieldAddress(array, index, TIMES_2, Int32Array::data_offset());
-    case kUint32ArrayCid:
-      return FieldAddress(array, index, TIMES_2, Uint32Array::data_offset());
-    case kOneByteStringCid:
-      return FieldAddress(array, index, TIMES_1, OneByteString::data_offset());
-    case kTwoByteStringCid:
-      return FieldAddress(array, index, TIMES_1, TwoByteString::data_offset());
+  switch (index_scale) {
+    case 1: return TIMES_1;
+    case 2: return TIMES_1;
+    case 4: return TIMES_2;
+    case 8: return TIMES_4;
     default:
-      UNIMPLEMENTED();
-      return FieldAddress(SPREG, 0);
+      UNREACHABLE();
+      return TIMES_1;
   }
 }
 
 
-Address FlowGraphCompiler::ExternalElementAddressForIntIndex(intptr_t cid,
-                                                             Register array,
-                                                             intptr_t index) {
-  return Address(array, index * ElementSizeFor(cid));
+FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
+                                                          intptr_t index_scale,
+                                                          Register array,
+                                                          Register index) {
+  return FieldAddress(array,
+                      index,
+                      ToScaleFactor(index_scale),
+                      DataOffsetFor(cid));
 }
 
 
-Address FlowGraphCompiler::ExternalElementAddressForRegIndex(intptr_t cid,
-                                                             Register array,
-                                                             Register index) {
+Address FlowGraphCompiler::ExternalElementAddressForIntIndex(
+    intptr_t cid,
+    intptr_t index_scale,
+    Register array,
+    intptr_t index) {
+  return Address(array, index * index_scale);
+}
+
+
+Address FlowGraphCompiler::ExternalElementAddressForRegIndex(
+    intptr_t cid,
+    intptr_t index_scale,
+    Register array,
+    Register index) {
   switch (cid) {
     case kExternalUint8ArrayCid:
-      return Address(array, index, TIMES_1, 0);
+    case kExternalUint8ClampedArrayCid:
+      return Address(array, index, ToScaleFactor(index_scale), 0);
     default:
       UNIMPLEMENTED();
       return Address(SPREG, 0);
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 6ff3a8c..e3c0cd6 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -304,6 +304,7 @@
 
 
 FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
+                                                          intptr_t index_scale,
                                                           Register array,
                                                           intptr_t index) {
   UNIMPLEMENTED();
@@ -312,6 +313,7 @@
 
 
 FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
+                                                          intptr_t index_scale,
                                                           Register array,
                                                           Register index) {
   UNIMPLEMENTED();
@@ -319,17 +321,21 @@
 }
 
 
-Address FlowGraphCompiler::ExternalElementAddressForIntIndex(intptr_t cid,
-                                                             Register array,
-                                                             intptr_t index) {
+Address FlowGraphCompiler::ExternalElementAddressForIntIndex(
+    intptr_t cid,
+    intptr_t index_scale,
+    Register array,
+    intptr_t index) {
   UNIMPLEMENTED();
   return FieldAddress(array, index);
 }
 
 
-Address FlowGraphCompiler::ExternalElementAddressForRegIndex(intptr_t cid,
-                                                             Register array,
-                                                             Register index) {
+Address FlowGraphCompiler::ExternalElementAddressForRegIndex(
+    intptr_t cid,
+    intptr_t index_scale,
+    Register array,
+    Register index) {
   UNIMPLEMENTED();
   return FieldAddress(array, index);
 }
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 4e1b9aa..76e976e 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -1508,70 +1508,62 @@
 
 
 FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
+                                                          intptr_t index_scale,
                                                           Register array,
                                                           intptr_t index) {
   const int64_t disp =
-      static_cast<int64_t>(index) * ElementSizeFor(cid) + DataOffsetFor(cid);
+      static_cast<int64_t>(index) * index_scale + DataOffsetFor(cid);
   ASSERT(Utils::IsInt(32, disp));
   return FieldAddress(array, static_cast<int32_t>(disp));
 }
 
 
-FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
-                                                          Register array,
-                                                          Register index) {
-  // Note that index is smi-tagged, (i.e, times 2) for all arrays with element
-  // size > 1. For Uint8Array and OneByteString the index is expected to be
-  // untagged before accessing.
+static ScaleFactor ToScaleFactor(intptr_t index_scale) {
+  // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
+  // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
+  // expected to be untagged before accessing.
   ASSERT(kSmiTagShift == 1);
-  switch (cid) {
-    case kArrayCid:
-    case kImmutableArrayCid:
-      return FieldAddress(
-          array, index, TIMES_HALF_WORD_SIZE, Array::data_offset());
-    case kFloat32ArrayCid:
-      return FieldAddress(array, index, TIMES_2, Float32Array::data_offset());
-    case kFloat64ArrayCid:
-      return FieldAddress(array, index, TIMES_4, Float64Array::data_offset());
-    case kInt8ArrayCid:
-      return FieldAddress(array, index, TIMES_1, Int8Array::data_offset());
-    case kUint8ArrayCid:
-      return FieldAddress(array, index, TIMES_1, Uint8Array::data_offset());
-    case kUint8ClampedArrayCid:
-      return
-          FieldAddress(array, index, TIMES_1, Uint8ClampedArray::data_offset());
-    case kInt16ArrayCid:
-      return FieldAddress(array, index, TIMES_1, Int16Array::data_offset());
-    case kUint16ArrayCid:
-      return FieldAddress(array, index, TIMES_1, Uint16Array::data_offset());
-    case kInt32ArrayCid:
-      return FieldAddress(array, index, TIMES_2, Int32Array::data_offset());
-    case kUint32ArrayCid:
-      return FieldAddress(array, index, TIMES_2, Uint32Array::data_offset());
-    case kOneByteStringCid:
-      return FieldAddress(array, index, TIMES_1, OneByteString::data_offset());
-    case kTwoByteStringCid:
-      return FieldAddress(array, index, TIMES_1, TwoByteString::data_offset());
+  switch (index_scale) {
+    case 1: return TIMES_1;
+    case 2: return TIMES_1;
+    case 4: return TIMES_2;
+    case 8: return TIMES_4;
     default:
-      UNIMPLEMENTED();
-      return FieldAddress(SPREG, 0);
+      UNREACHABLE();
+      return TIMES_1;
   }
 }
 
 
-Address FlowGraphCompiler::ExternalElementAddressForIntIndex(intptr_t cid,
-                                                             Register array,
-                                                             intptr_t index) {
-  return Address(array, index * ElementSizeFor(cid));
+FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
+                                                          intptr_t index_scale,
+                                                          Register array,
+                                                          Register index) {
+  return FieldAddress(array,
+                      index,
+                      ToScaleFactor(index_scale),
+                      DataOffsetFor(cid));
 }
 
 
-Address FlowGraphCompiler::ExternalElementAddressForRegIndex(intptr_t cid,
-                                                             Register array,
-                                                             Register index) {
+Address FlowGraphCompiler::ExternalElementAddressForIntIndex(
+    intptr_t cid,
+    intptr_t index_scale,
+    Register array,
+    intptr_t index) {
+  return Address(array, index * index_scale);
+}
+
+
+Address FlowGraphCompiler::ExternalElementAddressForRegIndex(
+    intptr_t cid,
+    intptr_t index_scale,
+    Register array,
+    Register index) {
   switch (cid) {
     case kExternalUint8ArrayCid:
-      return Address(array, index, TIMES_1, 0);
+    case kExternalUint8ClampedArrayCid:
+      return Address(array, index, ToScaleFactor(index_scale), 0);
     default:
       UNIMPLEMENTED();
       return Address(SPREG, 0);
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 3ce5318..b1a10b8 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -176,7 +176,7 @@
 }
 
 
-static void ReplaceCurrentInstruction(ForwardInstructionIterator* it,
+static void ReplaceCurrentInstruction(ForwardInstructionIterator* iterator,
                                       Instruction* current,
                                       Instruction* replacement,
                                       FlowGraph* graph) {
@@ -200,7 +200,8 @@
       OS::Print("Removing v%"Pd".\n", current_defn->ssa_temp_index());
     }
   }
-  it->RemoveCurrentFromGraph();
+  current->UnuseAllInputs();
+  iterator->RemoveCurrentFromGraph();
 }
 
 
@@ -555,7 +556,8 @@
   }
   if (!skip_check) {
     // Insert array length load and bounds check.
-    const bool is_immutable = (class_id != kGrowableObjectArrayCid);
+    const bool is_immutable =
+        CheckArrayBoundInstr::IsFixedLengthArrayType(class_id);
     LoadFieldInstr* length = new LoadFieldInstr(
         (*array)->Copy(),
         CheckArrayBoundInstr::LengthOffsetFor(class_id),
@@ -758,6 +760,7 @@
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
     case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
       break;
@@ -784,7 +787,11 @@
   Value* index = NULL;
   intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index);
   Definition* array_op =
-      new LoadIndexedInstr(array, index, array_cid, deopt_id);
+      new LoadIndexedInstr(array,
+                           index,
+                           FlowGraphCompiler::ElementSizeFor(array_cid),
+                           array_cid,
+                           deopt_id);
   call->ReplaceWith(array_op, current_iterator());
   RemovePushArguments(call);
   return true;
@@ -1256,7 +1263,9 @@
         return false;
       }
       const bool is_immutable =
-          (recognized_kind != MethodRecognizer::kGrowableArrayLength);
+          (recognized_kind == MethodRecognizer::kObjectArrayLength) ||
+          (recognized_kind == MethodRecognizer::kImmutableArrayLength) ||
+          (recognized_kind == MethodRecognizer::kByteArrayBaseLength);
       InlineArrayLengthGetter(call,
                               OffsetForLengthGetter(recognized_kind),
                               is_immutable,
@@ -1329,7 +1338,11 @@
                  call->env(),
                  Definition::kEffect);
   }
-  return new LoadIndexedInstr(str, index, cid, Isolate::kNoDeoptId);
+  return new LoadIndexedInstr(str,
+                              index,
+                              FlowGraphCompiler::ElementSizeFor(cid),
+                              cid,
+                              Isolate::kNoDeoptId);  // Can't deoptimize.
 }
 
 
@@ -1349,6 +1362,24 @@
 }
 
 
+static bool IsSupportedByteArrayCid(intptr_t cid) {
+  switch (cid) {
+    case kInt8ArrayCid:
+    case kUint8ArrayCid:
+    case kUint8ClampedArrayCid:
+    case kInt16ArrayCid:
+    case kUint16ArrayCid:
+    case kInt32ArrayCid:
+    case kUint32ArrayCid:
+    case kFloat32ArrayCid:
+    case kFloat64ArrayCid:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
 // Inline only simple, frequently called core library methods.
 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
   ASSERT(call->HasICData());
@@ -1440,10 +1471,98 @@
     }
   }
 
+  if (IsSupportedByteArrayCid(class_ids[0]) &&
+      (ic_data.NumberOfChecks() == 1)) {
+    Definition* array_op = NULL;
+    switch (recognized_kind) {
+      case MethodRecognizer::kByteArrayBaseGetInt8:
+        array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt8ArrayCid);
+        break;
+      case MethodRecognizer::kByteArrayBaseGetUint8:
+        array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint8ArrayCid);
+        break;
+      case MethodRecognizer::kByteArrayBaseGetInt16:
+        array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt16ArrayCid);
+        break;
+      case MethodRecognizer::kByteArrayBaseGetUint16:
+        array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint16ArrayCid);
+        break;
+      case MethodRecognizer::kByteArrayBaseGetInt32:
+        array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt32ArrayCid);
+        break;
+      case MethodRecognizer::kByteArrayBaseGetUint32:
+        array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint32ArrayCid);
+        break;
+      case MethodRecognizer::kByteArrayBaseGetFloat32:
+        array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid);
+        break;
+      case MethodRecognizer::kByteArrayBaseGetFloat64:
+        array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid);
+        break;
+      default:
+        // Unsupported method.
+        return false;
+    }
+    ASSERT(array_op != NULL);
+    call->ReplaceWith(array_op, current_iterator());
+    RemovePushArguments(call);
+    return true;
+  }
   return false;
 }
 
 
+LoadIndexedInstr* FlowGraphOptimizer::BuildByteArrayViewLoad(
+    InstanceCallInstr* call,
+    intptr_t receiver_cid,
+    intptr_t view_cid) {
+    Value* array = call->ArgumentAt(0)->value();
+    Value* byte_index = call->ArgumentAt(1)->value();
+
+    AddCheckClass(call, array->Copy());
+    const bool is_immutable = true;
+    LoadFieldInstr* length = new LoadFieldInstr(
+        array->Copy(),
+        CheckArrayBoundInstr::LengthOffsetFor(receiver_cid),
+        Type::ZoneHandle(Type::SmiType()),
+        is_immutable);
+    length->set_result_cid(kSmiCid);
+    length->set_recognized_kind(
+        LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid));
+    InsertBefore(call, length, NULL, Definition::kValue);
+
+    // len_in_bytes = length * kBytesPerElement(receiver)
+    intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid);
+    ConstantInstr* bytes_per_element =
+        new ConstantInstr(Smi::Handle(Smi::New(element_size)));
+    InsertBefore(call, bytes_per_element, NULL, Definition::kValue);
+    BinarySmiOpInstr* len_in_bytes =
+        new BinarySmiOpInstr(Token::kMUL,
+                             call,
+                             new Value(length),
+                             new Value(bytes_per_element));
+    InsertBefore(call, len_in_bytes, call->env(), Definition::kValue);
+
+    // Check byte_index < len_in_bytes.
+    InsertBefore(call,
+                 new CheckArrayBoundInstr(new Value(len_in_bytes),
+                                          byte_index->Copy(),
+                                          receiver_cid,
+                                          call),
+                 call->env(),
+                 Definition::kEffect);
+
+    // TODO(fschneider): Optimistically build smi load for Int32 and Uint32
+    // loads on ia32 like we do for normal array loads, and only revert to
+    // mint case after deoptimizing here.
+    return new LoadIndexedInstr(array,
+                                byte_index,
+                                1,  // Index scale.
+                                view_cid,
+                                Isolate::kNoDeoptId);  // Can't deoptimize.
+}
+
+
 // Returns a Boolean constant if all classes in ic_data yield the same type-test
 // result and the type tests do not depend on type arguments. Otherwise return
 // Bool::null().
@@ -2562,7 +2681,10 @@
       CheckArrayBoundInstr* check = current->AsCheckArrayBound();
       RangeBoundary array_length =
           RangeBoundary::FromDefinition(check->length()->definition());
-      if (check->IsRedundant(array_length)) it.RemoveCurrentFromGraph();
+      if (check->IsRedundant(array_length)) {
+        current->UnuseAllInputs();
+        it.RemoveCurrentFromGraph();
+      }
     }
   }
 
@@ -2602,7 +2724,7 @@
       def = def->AsConstraint()->value()->definition();
     }
     constraints_[i]->ReplaceUsesWith(def);
-    constraints_[i]->RemoveDependency();
+    constraints_[i]->UnuseAllInputs();
     constraints_[i]->RemoveFromGraph();
   }
 }
@@ -2914,6 +3036,7 @@
   }
 
   if (phi->GetPropagatedCid() == kSmiCid) {
+    current->UnuseAllInputs();
     it->RemoveCurrentFromGraph();
     return;
   }
@@ -3322,6 +3445,7 @@
           }
 
           defn->ReplaceUsesWith(replacement);
+          defn->UnuseAllInputs();
           instr_it.RemoveCurrentFromGraph();
           continue;
         } else if (!kill->Contains(expr_id)) {
@@ -3533,6 +3657,7 @@
           }
 
           load->ReplaceUsesWith(replacement);
+          load->UnuseAllInputs();
           load->RemoveFromGraph();
           load->SetReplacement(replacement);
         }
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 53159fc..b53054e 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -75,6 +75,10 @@
   LoadIndexedInstr* BuildStringCharCodeAt(InstanceCallInstr* call,
                                           intptr_t cid);
 
+  LoadIndexedInstr* BuildByteArrayViewLoad(InstanceCallInstr* call,
+                                           intptr_t receiver_cid,
+                                           intptr_t view_cid);
+
   void AddCheckClass(InstanceCallInstr* call, Value* value);
 
   void InsertAfter(Instruction* prev,
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 11b2713..7b8e997 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -696,6 +696,16 @@
 }
 
 
+void Instruction::UnuseAllInputs() {
+  for (intptr_t i = InputCount() - 1; i >= 0; --i) {
+    InputAt(i)->RemoveFromUseList();
+  }
+  for (Environment::DeepIterator it(env()); !it.Done(); it.Advance()) {
+    it.CurrentValue()->RemoveFromUseList();
+  }
+}
+
+
 void Definition::ReplaceWith(Definition* other,
                              ForwardInstructionIterator* iterator) {
   if ((iterator != NULL) && (this == iterator->Current())) {
@@ -1219,6 +1229,7 @@
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
     case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
     case kInt32ArrayCid:
@@ -1715,6 +1726,7 @@
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
     case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
     case kInt32ArrayCid:
@@ -2129,13 +2141,20 @@
 
 
 Environment* Environment::DeepCopy() const {
+  return (this == NULL) ? NULL : DeepCopy(Length());
+}
+
+
+Environment* Environment::DeepCopy(intptr_t length) const {
+  ASSERT(length <= values_.length());
+  if (this == NULL) return NULL;
   Environment* copy =
-      new Environment(values_.length(),
+      new Environment(length,
                       fixed_parameter_count_,
                       deopt_id_,
                       function_,
-                      (outer_ == NULL) ? NULL : outer_->DeepCopy());
-  for (intptr_t i = 0; i < values_.length(); ++i) {
+                      outer_->DeepCopy());
+  for (intptr_t i = 0; i < length; ++i) {
     copy->values_.Add(values_[i]->Copy());
   }
   return copy;
@@ -2144,6 +2163,10 @@
 
 // Copies the environment and updates the environment use lists.
 void Environment::DeepCopyTo(Instruction* instr) const {
+  for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) {
+    it.CurrentValue()->RemoveFromUseList();
+  }
+
   Environment* copy = DeepCopy();
   intptr_t use_index = 0;
   for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) {
@@ -2159,18 +2182,11 @@
 // Copies the environment as outer on an inlined instruction and updates the
 // environment use lists.
 void Environment::DeepCopyToOuter(Instruction* instr) const {
-  ASSERT(instr->env()->outer() == NULL);
   // Create a deep copy removing caller arguments from the environment.
+  ASSERT(this != NULL);
+  ASSERT(instr->env()->outer() == NULL);
   intptr_t argument_count = instr->env()->fixed_parameter_count();
-  Environment* copy =
-      new Environment(values_.length() - argument_count,
-                      fixed_parameter_count_,
-                      deopt_id_,
-                      function_,
-                      (outer_ == NULL) ? NULL : outer_->DeepCopy());
-  for (intptr_t i = 0; i < values_.length() - argument_count; ++i) {
-    copy->values_.Add(values_[i]->Copy());
-  }
+  Environment* copy = DeepCopy(values_.length() - argument_count);
   intptr_t use_index = instr->env()->Length();  // Start index after inner.
   for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) {
     Value* value = it.CurrentValue();
@@ -2498,6 +2514,7 @@
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
     case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
       range_ = new Range(RangeBoundary::FromConstant(0),
                          RangeBoundary::FromConstant(255));
       break;
@@ -2777,6 +2794,7 @@
     case kFloat64ArrayCid:
     case kFloat32ArrayCid:
     case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
       return ByteArray::length_offset();
     default:
       UNREACHABLE();
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 8c3b695..1d70a29 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -36,6 +36,14 @@
   V(_ObjectArray, get:length, ObjectArrayLength, 405297088)                    \
   V(_ImmutableArray, get:length, ImmutableArrayLength, 433698233)              \
   V(_ByteArrayBase, get:length, ByteArrayBaseLength, 1098081765)               \
+  V(_ByteArrayBase, _getInt8, ByteArrayBaseGetInt8, 261365835)                 \
+  V(_ByteArrayBase, _getUint8, ByteArrayBaseGetUint8, 261365835)               \
+  V(_ByteArrayBase, _getInt16, ByteArrayBaseGetInt16, 261365835)               \
+  V(_ByteArrayBase, _getUint16, ByteArrayBaseGetUint16, 261365835)             \
+  V(_ByteArrayBase, _getInt32, ByteArrayBaseGetInt32, 261365835)               \
+  V(_ByteArrayBase, _getUint32, ByteArrayBaseGetUint32, 261365835)             \
+  V(_ByteArrayBase, _getFloat32, ByteArrayBaseGetFloat32, 434247298)           \
+  V(_ByteArrayBase, _getFloat64, ByteArrayBaseGetFloat64, 434247298)           \
   V(_GrowableObjectArray, get:length, GrowableArrayLength, 725548050)          \
   V(_GrowableObjectArray, get:_capacity, GrowableArrayCapacity, 725548050)     \
   V(_StringBase, get:length, StringBaseLength, 320803993)                      \
@@ -351,6 +359,10 @@
   virtual Value* InputAt(intptr_t i) const = 0;
   virtual void SetInputAt(intptr_t i, Value* value) = 0;
 
+  // Remove all inputs (including in the environment) from their
+  // definition's use lists.
+  void UnuseAllInputs();
+
   // Call instructions override this function and return the number of
   // pushed arguments.
   virtual intptr_t ArgumentCount() const = 0;
@@ -1802,6 +1814,10 @@
 
   DECLARE_INSTRUCTION(Constraint)
 
+  virtual intptr_t InputCount() const {
+    return (inputs_[1] == NULL) ? 1 : 2;
+  }
+
   virtual RawAbstractType* CompileType() const {
     return Type::SmiType();
   }
@@ -1832,13 +1848,6 @@
     set_dependency(val);
   }
 
-  void RemoveDependency() {
-    if (dependency() != NULL) {
-      dependency()->RemoveFromUseList();
-      set_dependency(NULL);
-    }
-  }
-
  private:
   Value* dependency() {
     return inputs_[1];
@@ -2721,9 +2730,10 @@
  public:
   LoadIndexedInstr(Value* array,
                    Value* index,
+                   intptr_t index_scale,
                    intptr_t class_id,
                    intptr_t deopt_id)
-      : class_id_(class_id) {
+      : index_scale_(index_scale), class_id_(class_id) {
     ASSERT(array != NULL);
     ASSERT(index != NULL);
     inputs_[0] = array;
@@ -2736,6 +2746,7 @@
 
   Value* array() const { return inputs_[0]; }
   Value* index() const { return inputs_[1]; }
+  intptr_t index_scale() const { return index_scale_; }
   intptr_t class_id() const { return class_id_; }
 
   virtual bool CanDeoptimize() const {
@@ -2755,6 +2766,7 @@
   virtual void InferRange();
 
  private:
+  const intptr_t index_scale_;
   const intptr_t class_id_;
 
   DISALLOW_COPY_AND_ASSIGN(LoadIndexedInstr);
@@ -4455,7 +4467,11 @@
         function_(function),
         outer_(outer) { }
 
+  // Deep copy the environment.  A 'length' parameter can be given, which
+  // may be less than the environment's length in order to drop values
+  // (e.g., passed arguments) from the copy.
   Environment* DeepCopy() const;
+  Environment* DeepCopy(intptr_t length) const;
 
   GrowableArray<Value*> values_;
   Location* locations_;
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index a698a59..0787527 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -462,7 +462,11 @@
     ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
     Label next_test;
     __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
-    __ j(NOT_EQUAL, &next_test);
+    if (i < len - 1) {
+      __ j(NOT_EQUAL, &next_test);
+    } else {
+      __ j(NOT_EQUAL, deopt);
+    }
     const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
     if (target.Owner() == object_store->object_class()) {
       // Object.== is same as ===.
@@ -497,7 +501,6 @@
           __ jmp(&done);
           __ Bind(&false_label);
           __ LoadObject(EAX, Bool::False());
-          __ jmp(&done);
         }
       } else {
         if (branch->is_checked()) {
@@ -507,11 +510,11 @@
         branch->EmitBranchOnCondition(compiler, cond);
       }
     }
-    __ jmp(&done);
-    __ Bind(&next_test);
+    if (i < len - 1) {
+      __ jmp(&done);
+      __ Bind(&next_test);
+    }
   }
-  // Fall through leads to deoptimization
-  __ jmp(deopt);
   __ Bind(&done);
 }
 
@@ -1106,6 +1109,7 @@
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
     case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
     case kOneByteStringCid:
@@ -1132,6 +1136,7 @@
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
     case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
     case kOneByteStringCid:
@@ -1177,13 +1182,16 @@
   Register array = locs()->in(0).reg();
   Location index = locs()->in(1);
 
-  if (class_id() == kExternalUint8ArrayCid) {
+  if ((class_id() == kExternalUint8ArrayCid) ||
+      (class_id() == kExternalUint8ClampedArrayCid)) {
     Register result = locs()->out().reg();
     const Address& element_address = index.IsRegister()
         ? FlowGraphCompiler::ExternalElementAddressForRegIndex(
-            class_id(), result, index.reg())
+            class_id(), index_scale(), result, index.reg())
         : FlowGraphCompiler::ExternalElementAddressForIntIndex(
-            class_id(), result, Smi::Cast(index.constant()).Value());
+            class_id(), index_scale(), result,
+            Smi::Cast(index.constant()).Value());
+    ASSERT(index_scale() == 1);
     if (index.IsRegister()) {
       __ SmiUntag(index.reg());
     }
@@ -1199,13 +1207,17 @@
 
   FieldAddress element_address = index.IsRegister()
       ? FlowGraphCompiler::ElementAddressForRegIndex(
-          class_id(), array, index.reg())
+          class_id(), index_scale(), array, index.reg())
       : FlowGraphCompiler::ElementAddressForIntIndex(
-          class_id(), array, Smi::Cast(index.constant()).Value());
+          class_id(), index_scale(), array,
+          Smi::Cast(index.constant()).Value());
 
   if ((representation() == kUnboxedDouble) ||
       (representation() == kUnboxedMint)) {
     XmmRegister result = locs()->out().fpu_reg();
+    if ((index_scale() == 1) && index.IsRegister()) {
+      __ SmiUntag(index.reg());
+    }
     switch (class_id()) {
       case kInt32ArrayCid:
         __ movss(result, element_address);
@@ -1224,27 +1236,28 @@
         __ movsd(result, element_address);
         break;
     }
+    if ((index_scale() == 1) && index.IsRegister()) {
+        __ SmiTag(index.reg());  // Re-tag.
+    }
     return;
   }
 
   Register result = locs()->out().reg();
+  if ((index_scale() == 1) && index.IsRegister()) {
+    __ SmiUntag(index.reg());
+  }
   switch (class_id()) {
     case kInt8ArrayCid:
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
     case kOneByteStringCid:
-      if (index.IsRegister()) {
-        __ SmiUntag(index.reg());
-      }
+      ASSERT(index_scale() == 1);
       if (class_id() == kInt8ArrayCid) {
         __ movsxb(result, element_address);
       } else {
         __ movzxb(result, element_address);
       }
       __ SmiTag(result);
-      if (index.IsRegister()) {
-        __ SmiTag(index.reg());  // Re-tag.
-      }
       break;
     case kInt16ArrayCid:
       __ movsxw(result, element_address);
@@ -1278,6 +1291,9 @@
       __ movl(result, element_address);
       break;
   }
+  if ((index_scale() == 1) && index.IsRegister()) {
+      __ SmiTag(index.reg());  // Re-tag.
+  }
 }
 
 
@@ -1358,11 +1374,13 @@
   Register array = locs()->in(0).reg();
   Location index = locs()->in(1);
 
+  intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id());
+
   FieldAddress element_address = index.IsRegister() ?
       FlowGraphCompiler::ElementAddressForRegIndex(
-          class_id(), array, index.reg()) :
+          class_id(), index_scale, array, index.reg()) :
       FlowGraphCompiler::ElementAddressForIntIndex(
-          class_id(), array, Smi::Cast(index.constant()).Value());
+          class_id(), index_scale, array, Smi::Cast(index.constant()).Value());
 
   switch (class_id()) {
     case kArrayCid:
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index b0d714a..c0e93f9 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -459,7 +459,11 @@
     ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
     Label next_test;
     __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
-    __ j(NOT_EQUAL, &next_test);
+    if (i < len - 1) {
+      __ j(NOT_EQUAL, &next_test);
+    } else {
+      __ j(NOT_EQUAL, deopt);
+    }
     const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
     if (target.Owner() == object_store->object_class()) {
       // Object.== is same as ===.
@@ -495,7 +499,6 @@
           __ jmp(&done);
           __ Bind(&false_label);
           __ LoadObject(RAX, Bool::False());
-          __ jmp(&done);
         }
       } else {
         if (branch->is_checked()) {
@@ -505,11 +508,11 @@
         branch->EmitBranchOnCondition(compiler, cond);
       }
     }
-    __ jmp(&done);
-    __ Bind(&next_test);
+    if (i < len - 1) {
+      __ jmp(&done);
+      __ Bind(&next_test);
+    }
   }
-  // Fall through leads to deoptimization
-  __ jmp(deopt);
   __ Bind(&done);
 }
 
@@ -970,6 +973,7 @@
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
     case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
     case kOneByteStringCid:
@@ -992,6 +996,7 @@
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
     case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
     case kOneByteStringCid:
@@ -1034,13 +1039,16 @@
   Register array = locs()->in(0).reg();
   Location index = locs()->in(1);
 
-  if (class_id() == kExternalUint8ArrayCid) {
+  if ((class_id() == kExternalUint8ArrayCid) ||
+      (class_id() == kExternalUint8ClampedArrayCid)) {
     Register result = locs()->out().reg();
     Address element_address = index.IsRegister()
         ? FlowGraphCompiler::ExternalElementAddressForRegIndex(
-            class_id(), result, index.reg())
+            class_id(), index_scale(), result, index.reg())
         : FlowGraphCompiler::ExternalElementAddressForIntIndex(
-            class_id(), result, Smi::Cast(index.constant()).Value());
+            class_id(), index_scale(), result,
+            Smi::Cast(index.constant()).Value());
+    ASSERT(index_scale() == 1);
     if (index.IsRegister()) {
       __ SmiUntag(index.reg());
     }
@@ -1054,13 +1062,18 @@
     return;
   }
 
-  FieldAddress element_address = index.IsRegister() ?
-      FlowGraphCompiler::ElementAddressForRegIndex(
-          class_id(), array, index.reg()) :
-      FlowGraphCompiler::ElementAddressForIntIndex(
-          class_id(), array, Smi::Cast(index.constant()).Value());
+  FieldAddress element_address = index.IsRegister()
+      ? FlowGraphCompiler::ElementAddressForRegIndex(
+          class_id(), index_scale(), array, index.reg())
+      : FlowGraphCompiler::ElementAddressForIntIndex(
+          class_id(), index_scale(), array,
+          Smi::Cast(index.constant()).Value());
 
   if (representation() == kUnboxedDouble) {
+    if ((index_scale() == 1) && index.IsRegister()) {
+      __ SmiUntag(index.reg());
+    }
+
     XmmRegister result = locs()->out().fpu_reg();
     if (class_id() == kFloat32ArrayCid) {
       // Load single precision float.
@@ -1071,27 +1084,28 @@
       ASSERT(class_id() == kFloat64ArrayCid);
       __ movsd(result, element_address);
     }
+
+    if ((index_scale() == 1) && index.IsRegister()) {
+        __ SmiTag(index.reg());  // Re-tag.
+    }
     return;
   }
 
+  if ((index_scale() == 1) && index.IsRegister()) {
+    __ SmiUntag(index.reg());
+  }
   Register result = locs()->out().reg();
   switch (class_id()) {
     case kInt8ArrayCid:
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
     case kOneByteStringCid:
-      if (index.IsRegister()) {
-        __ SmiUntag(index.reg());
-      }
       if (class_id() == kInt8ArrayCid) {
         __ movsxb(result, element_address);
       } else {
         __ movzxb(result, element_address);
       }
       __ SmiTag(result);
-      if (index.IsRegister()) {
-        __ SmiTag(index.reg());  // Re-tag.
-      }
       break;
     case kInt16ArrayCid:
       __ movsxw(result, element_address);
@@ -1115,6 +1129,9 @@
       __ movq(result, element_address);
       break;
   }
+  if ((index_scale() == 1) && index.IsRegister()) {
+      __ SmiTag(index.reg());  // Re-tag.
+  }
 }
 
 
@@ -1194,11 +1211,14 @@
   Register array = locs()->in(0).reg();
   Location index = locs()->in(1);
 
-  FieldAddress element_address = index.IsRegister() ?
-      FlowGraphCompiler::ElementAddressForRegIndex(
-          class_id(), array, index.reg()) :
-      FlowGraphCompiler::ElementAddressForIntIndex(
-          class_id(), array, Smi::Cast(index.constant()).Value());
+  intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id());
+
+  FieldAddress element_address = index.IsRegister()
+      ? FlowGraphCompiler::ElementAddressForRegIndex(
+          class_id(), index_scale, array, index.reg())
+      : FlowGraphCompiler::ElementAddressForIntIndex(
+          class_id(), index_scale, array,
+          Smi::Cast(index.constant()).Value());
 
   switch (class_id()) {
     case kArrayCid:
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index fc20192..a3b4559 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1787,9 +1787,8 @@
   // Shared handles used during the iteration.
   String& member_name = String::Handle();
 
-  const Script& patch_script = Script::Handle(patch.script());
-  const PatchClass& patch_class = PatchClass::Handle(
-      PatchClass::New(*this, patch_script));
+  const PatchClass& patch_class =
+      PatchClass::Handle(PatchClass::New(*this, patch));
 
   Array& orig_list = Array::Handle(functions());
   intptr_t orig_len = orig_list.Length();
@@ -1853,6 +1852,10 @@
     new_list.SetAt(patch_len + i, field);
   }
   SetFields(new_list);
+
+  // The functions and fields in the patch class are no longer needed.
+  patch.SetFunctions(Object::empty_array());
+  patch.SetFields(Object::empty_array());
   return NULL;
 }
 
@@ -3246,10 +3249,10 @@
 
 
 RawPatchClass* PatchClass::New(const Class& patched_class,
-                               const Script& script) {
+                               const Class& source_class) {
   const PatchClass& result = PatchClass::Handle(PatchClass::New());
   result.set_patched_class(patched_class);
-  result.set_script(script);
+  result.set_source_class(source_class);
   return result.raw();
 }
 
@@ -3263,13 +3266,19 @@
 }
 
 
+RawScript* PatchClass::Script() const {
+  const Class& source_class = Class::Handle(this->source_class());
+  return source_class.script();
+}
+
+
 void PatchClass::set_patched_class(const Class& value) const {
   StorePointer(&raw_ptr()->patched_class_, value.raw());
 }
 
 
-void PatchClass::set_script(const Script& value) const {
-  StorePointer(&raw_ptr()->script_, value.raw());
+void PatchClass::set_source_class(const Class& value) const {
+  StorePointer(&raw_ptr()->source_class_, value.raw());
 }
 
 
@@ -4375,7 +4384,7 @@
     return Class::Cast(obj).script();
   }
   ASSERT(obj.IsPatchClass());
-  return PatchClass::Cast(obj).script();
+  return PatchClass::Cast(obj).Script();
 }
 
 
@@ -6207,7 +6216,7 @@
 
 
 void Library::InitASyncLibrary(Isolate* isolate) {
-  const String& url = String::Handle(Symbols::New("dart:async"));
+  const String& url = Symbols::DartAsync();
   const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
   lib.Register();
   isolate->object_store()->set_async_library(lib);
@@ -6215,7 +6224,7 @@
 
 
 void Library::InitCoreLibrary(Isolate* isolate) {
-  const String& core_lib_url = String::Handle(Symbols::New("dart:core"));
+  const String& core_lib_url = Symbols::DartCore();
   const Library& core_lib =
       Library::Handle(Library::NewLibraryHelper(core_lib_url, false));
   core_lib.Register();
@@ -6248,7 +6257,7 @@
 
 
 void Library::InitCollectionLibrary(Isolate* isolate) {
-  const String& url = String::Handle(Symbols::New("dart:collection"));
+  const String& url = Symbols::DartCollection();
   const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
   lib.Register();
   const Library& math_lib = Library::Handle(Library::MathLibrary());
@@ -6265,7 +6274,7 @@
 
 
 void Library::InitCollectionDevLibrary(Isolate* isolate) {
-  const String& url = String::Handle(Symbols::New("dart:collection-dev"));
+  const String& url = Symbols::DartCollectionDev();
   const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
   lib.Register();
   isolate->object_store()->set_collection_dev_library(lib);
@@ -6273,7 +6282,7 @@
 
 
 void Library::InitMathLibrary(Isolate* isolate) {
-  const String& url = String::Handle(Symbols::New("dart:math"));
+  const String& url = Symbols::DartMath();
   const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
   lib.Register();
   isolate->object_store()->set_math_library(lib);
@@ -6281,7 +6290,7 @@
 
 
 void Library::InitIsolateLibrary(Isolate* isolate) {
-  const String& url = String::Handle(Symbols::New("dart:isolate"));
+  const String& url = Symbols::DartIsolate();
   const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
   lib.Register();
   const Library& async_lib = Library::Handle(Library::ASyncLibrary());
@@ -6293,7 +6302,7 @@
 
 
 void Library::InitMirrorsLibrary(Isolate* isolate) {
-  const String& url = String::Handle(Symbols::New("dart:mirrors"));
+  const String& url = Symbols::DartMirrors();
   const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
   lib.Register();
   const Library& isolate_lib = Library::Handle(Library::IsolateLibrary());
@@ -6314,7 +6323,7 @@
 
 
 void Library::InitScalarlistLibrary(Isolate* isolate) {
-  const String& url = String::Handle(Symbols::New("dart:scalarlist"));
+  const String& url = Symbols::DartScalarlist();
   const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
   lib.Register();
   const Library& collection_lib =
@@ -6329,8 +6338,7 @@
 void Library::InitNativeWrappersLibrary(Isolate* isolate) {
   static const int kNumNativeWrappersClasses = 4;
   ASSERT(kNumNativeWrappersClasses > 0 && kNumNativeWrappersClasses < 10);
-  const String& native_flds_lib_url = String::Handle(
-      Symbols::New("dart:nativewrappers"));
+  const String& native_flds_lib_url = Symbols::DartNativeWrappers();
   const Library& native_flds_lib = Library::Handle(
       Library::NewLibraryHelper(native_flds_lib_url, false));
   native_flds_lib.Register();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 0a64f79..b10e24c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1146,17 +1146,19 @@
 class PatchClass : public Object {
  public:
   RawClass* patched_class() const { return raw_ptr()->patched_class_; }
-  RawScript* script() const { return raw_ptr()->script_; }
+  RawClass* source_class() const { return raw_ptr()->source_class_; }
+  RawScript* Script() const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawPatchClass));
   }
 
-  static RawPatchClass* New(const Class& patched_class, const Script& script);
+  static RawPatchClass* New(const Class& patched_class,
+                            const Class& source_class);
 
  private:
   void set_patched_class(const Class& value) const;
-  void set_script(const Script& value) const;
+  void set_source_class(const Class& value) const;
   static RawPatchClass* New();
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(PatchClass, Object);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 3513e79..34dee42 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -194,7 +194,7 @@
                             Type::ZoneHandle(Type::DynamicType()));
       context_var->set_index(next_free_frame_index--);
       scope->AddVariable(context_var);
-      set_saved_context_var(context_var);
+      set_saved_entry_context_var(context_var);
     }
   }
 
@@ -265,7 +265,8 @@
       current_class_(Class::Handle()),
       library_(library),
       try_blocks_list_(NULL),
-      expression_temp_(NULL) {
+      expression_temp_(NULL),
+      saved_current_context_(NULL) {
   ASSERT(tokens_iterator_.IsValid());
   ASSERT(!library.IsNull());
 }
@@ -287,7 +288,8 @@
       current_class_(Class::Handle(current_function_.Owner())),
       library_(Library::Handle(current_class_.library())),
       try_blocks_list_(NULL),
-      expression_temp_(NULL) {
+      expression_temp_(NULL),
+      saved_current_context_(NULL) {
   ASSERT(tokens_iterator_.IsValid());
   ASSERT(!function.IsNull());
   if (FLAG_enable_type_checks) {
@@ -769,6 +771,12 @@
   if (parsed_function->has_expression_temp_var()) {
     node_sequence->scope()->AddVariable(parsed_function->expression_temp_var());
   }
+  if (parser.saved_current_context_ != NULL) {
+    parsed_function->set_saved_current_context_var(
+        parser.saved_current_context_);
+    node_sequence->scope()->AddVariable(
+        parsed_function->saved_current_context_var());
+  }
   parsed_function->SetNodeSequence(node_sequence);
 
   // The instantiator may be required at run time for generic type checks or
@@ -1452,7 +1460,7 @@
                                             /* is_super_getter */ true,
                                             super_class,
                                             function_name);
-    EnsureExpressionTemp();
+    EnsureSavedCurrentContext();
     // 'this' is not passed as parameter to the closure.
     ArgumentListNode* closure_arguments = new ArgumentListNode(supercall_pos);
     for (int i = 1; i < arguments->length(); i++) {
@@ -4255,6 +4263,13 @@
   const Namespace& ns =
     Namespace::Handle(Namespace::New(library, show_names, hide_names));
   if (is_import) {
+    // Ensure that private dart:_ libraries are only imported into dart:
+    // libraries.
+    const String& lib_url = String::Handle(library_.url());
+    if (canon_url.StartsWith(Symbols::DartSchemePrivate()) &&
+        !lib_url.StartsWith(Symbols::DartScheme())) {
+      ErrorMsg(import_pos, "private library is not accessible");
+    }
     if (prefix.IsNull() || (prefix.Length() == 0)) {
       library_.AddImport(ns);
     } else {
@@ -5792,7 +5807,7 @@
   if (condition->IsClosureNode() ||
       (condition->IsStoreLocalNode() &&
        condition->AsStoreLocalNode()->value()->IsClosureNode())) {
-    EnsureExpressionTemp();
+    EnsureSavedCurrentContext();
     // Function literal in assert implies a call.
     const intptr_t pos = condition->token_pos();
     condition = new ClosureCallNode(pos, condition, new ArgumentListNode(pos));
@@ -5931,9 +5946,10 @@
   TRACE_PARSER("ParseTryStatement");
 
   // We create three stack slots for exceptions here:
-  // ':saved_context_var' - Used to save the context before start of the try
-  //                        block. The context register is restored from this
-  //                        slot before processing the catch block handler.
+  // ':saved_try_context_var' - Used to save the context before start of the try
+  //                            block. The context register is restored from
+  //                            this slot before processing the catch block
+  //                            handler.
   // ':exception_var' - Used to save the current exception object that was
   //                    thrown.
   // ':stacktrace_var' - Used to save the current stack trace object into which
@@ -5943,10 +5959,10 @@
   // and the stacktrace object when an exception is thrown.
   // These three implicit variables can never be captured variables.
   LocalVariable* context_var =
-      current_block_->scope->LocalLookupVariable(Symbols::SavedContextVar());
+      current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar());
   if (context_var == NULL) {
     context_var = new LocalVariable(TokenPos(),
-                                    Symbols::SavedContextVar(),
+                                    Symbols::SavedTryContextVar(),
                                     Type::ZoneHandle(Type::DynamicType()));
     current_block_->scope->AddVariable(context_var);
   }
@@ -6782,6 +6798,19 @@
 }
 
 
+void Parser::EnsureSavedCurrentContext() {
+  // Used later by the flow_graph_builder to save current context.
+  if (saved_current_context_ == NULL) {
+    // Allocate a local variable to save the current context when we call into
+    // any closure function as the call will destroy the current context.
+    saved_current_context_ =
+        new LocalVariable(current_function().token_pos(),
+                          Symbols::SavedCurrentContextVar(),
+                          Type::ZoneHandle(Type::DynamicType()));
+  }
+}
+
+
 LocalVariable* Parser::CreateTempConstVariable(intptr_t token_pos,
                                                const char* s) {
   char name[64];
@@ -7222,7 +7251,7 @@
                                      Resolver::kIsQualified);
       if (!func.IsNull()) {
         ASSERT(func.kind() != RawFunction::kConstImplicitGetter);
-        EnsureExpressionTemp();
+        EnsureSavedCurrentContext();
         closure = new StaticGetterNode(call_pos,
                                        NULL,
                                        false,
@@ -7231,7 +7260,7 @@
         return new ClosureCallNode(call_pos, closure, arguments);
       }
     } else {
-      EnsureExpressionTemp();
+      EnsureSavedCurrentContext();
       closure = GenerateStaticFieldLookup(field, call_pos);
       return new ClosureCallNode(call_pos, closure, arguments);
     }
@@ -7257,7 +7286,7 @@
   TRACE_PARSER("ParseClosureCall");
   const intptr_t call_pos = TokenPos();
   ASSERT(CurrentToken() == Token::kLPAREN);
-  EnsureExpressionTemp();
+  EnsureSavedCurrentContext();
   ArgumentListNode* arguments = ParseActualParameters(NULL, kAllowConst);
   return new ClosureCallNode(call_pos, closure, arguments);
 }
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 5fa2eca..53b3bfc 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -37,7 +37,8 @@
         node_sequence_(NULL),
         instantiator_(NULL),
         default_parameter_values_(Array::ZoneHandle()),
-        saved_context_var_(NULL),
+        saved_current_context_var_(NULL),
+        saved_entry_context_var_(NULL),
         expression_temp_var_(NULL),
         first_parameter_index_(0),
         first_stack_local_index_(0),
@@ -65,10 +66,20 @@
     default_parameter_values_ = default_parameter_values.raw();
   }
 
-  LocalVariable* saved_context_var() const { return saved_context_var_; }
-  void set_saved_context_var(LocalVariable* saved_context_var) {
-    ASSERT(saved_context_var != NULL);
-    saved_context_var_ = saved_context_var;
+  LocalVariable* saved_current_context_var() const {
+    return saved_current_context_var_;
+  }
+  void set_saved_current_context_var(LocalVariable* saved_current_context_var) {
+    ASSERT(saved_current_context_var != NULL);
+    saved_current_context_var_ = saved_current_context_var;
+  }
+
+  LocalVariable* saved_entry_context_var() const {
+    return saved_entry_context_var_;
+  }
+  void set_saved_entry_context_var(LocalVariable* saved_entry_context_var) {
+    ASSERT(saved_entry_context_var != NULL);
+    saved_entry_context_var_ = saved_entry_context_var;
   }
 
   // Returns NULL if this function does not save the arguments descriptor on
@@ -100,7 +111,8 @@
   SequenceNode* node_sequence_;
   AstNode* instantiator_;
   Array& default_parameter_values_;
-  LocalVariable* saved_context_var_;
+  LocalVariable* saved_current_context_var_;
+  LocalVariable* saved_entry_context_var_;
   LocalVariable* expression_temp_var_;
 
   int first_parameter_index_;
@@ -582,6 +594,7 @@
 
   const LocalVariable* GetIncrementTempLocal();
   void EnsureExpressionTemp();
+  void EnsureSavedCurrentContext();
   AstNode* CreateAssignmentNode(AstNode* original, AstNode* rhs);
   AstNode* InsertClosureCallNodes(AstNode* condition);
 
@@ -631,6 +644,9 @@
   // Allocate temporary only once per function.
   LocalVariable* expression_temp_;
 
+  // Allocate saved current context only if needed.
+  LocalVariable* saved_current_context_;
+
   DISALLOW_COPY_AND_ASSIGN(Parser);
 };
 
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index b997520..ac66f62 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -527,9 +527,9 @@
     return reinterpret_cast<RawObject**>(&ptr()->patched_class_);
   }
   RawClass* patched_class_;
-  RawScript* script_;
+  RawClass* source_class_;
   RawObject** to() {
-    return reinterpret_cast<RawObject**>(&ptr()->script_);
+    return reinterpret_cast<RawObject**>(&ptr()->source_class_);
   }
 };
 
diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc
index d5bf92a..86dceae 100644
--- a/runtime/vm/scopes.cc
+++ b/runtime/vm/scopes.cc
@@ -259,7 +259,7 @@
         desc.info.index = var->index();
         vars->Add(desc);
       } else if (var->name().Equals(
-            Symbols::Name(Symbols::kSavedEntryContextVarId))) {
+            Symbols::Name(Symbols::kSavedCurrentContextVarId))) {
         // This is the local variable in which the function saves the
         // caller's chain of closure contexts (caller's CTX register).
         VarDesc desc;
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 0b4d1bc..952ab88 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -37,11 +37,11 @@
 class StatsCounter {
  public:
   explicit StatsCounter(const char* name) {
-    UNIMPLEMENTED();
+    // UNIMPLEMENTED();
   }
 
   void Increment() {
-    UNIMPLEMENTED();
+    // UNIMPLEMENTED();
   }
 };
 
@@ -651,7 +651,10 @@
 
 Simulator::~Simulator() {
   delete[] stack_;
-  Isolate::Current()->set_simulator(NULL);
+  Isolate* isolate = Isolate::Current();
+  if (isolate != NULL) {
+    isolate->set_simulator(NULL);
+  }
 }
 
 
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index fe3c275..56d73eb 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -22,13 +22,38 @@
 
 
 Simulator::~Simulator() {
-  UNIMPLEMENTED();
+  Isolate* isolate = Isolate::Current();
+  if (isolate != NULL) {
+    isolate->set_simulator(NULL);
+  }
+}
+
+
+// Get the active Simulator for the current isolate.
+Simulator* Simulator::Current() {
+  Simulator* simulator = Isolate::Current()->simulator();
+  if (simulator == NULL) {
+    simulator = new Simulator();
+    Isolate::Current()->set_simulator(simulator);
+  }
+  return simulator;
 }
 
 
 void Simulator::InitOnce() {
 }
 
+
+int64_t Simulator::Call(int32_t entry,
+                        int32_t parameter0,
+                        int32_t parameter1,
+                        int32_t parameter2,
+                        int32_t parameter3,
+                        int32_t parameter4) {
+  UNIMPLEMENTED();
+  return 0LL;
+}
+
 }  // namespace dart
 
 #endif  // !defined(HOST_ARCH_MIPS)
diff --git a/runtime/vm/simulator_mips.h b/runtime/vm/simulator_mips.h
index 8541815..b852ebb 100644
--- a/runtime/vm/simulator_mips.h
+++ b/runtime/vm/simulator_mips.h
@@ -23,8 +23,22 @@
   Simulator();
   ~Simulator();
 
+  // The currently executing Simulator instance, which is associated to the
+  // current isolate
+  static Simulator* Current();
+
   // Call on program start.
   static void InitOnce();
+
+  // Dart generally calls into generated code with 5 parameters. This is a
+  // convenience function, which sets up the simulator state and grabs the
+  // result on return.
+  int64_t Call(int32_t entry,
+               int32_t parameter0,
+               int32_t parameter1,
+               int32_t parameter2,
+               int32_t parameter3,
+               int32_t parameter4);
 };
 
 }  // namespace dart
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index d4306f5..ca20583 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -35,6 +35,11 @@
 }
 
 
+RawContext* EntryFrame::SavedContext() const {
+  return *(reinterpret_cast<RawContext**>(fp() + SavedContextOffset()));
+}
+
+
 void EntryFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
   // Visit objects between SP and (FP - callee_save_area).
   ASSERT(visitor != NULL);
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index c4dd50dd..483f212 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -13,6 +13,7 @@
 
 // Forward declarations.
 class ObjectPointerVisitor;
+class RawContext;
 
 
 // Generic stack frame.
@@ -118,6 +119,8 @@
   bool IsStubFrame() const { return false; }
   bool IsEntryFrame() const { return true; }
 
+  RawContext* SavedContext() const;
+
   // Visit objects in the frame.
   virtual void VisitObjectPointers(ObjectPointerVisitor* visitor);
 
@@ -126,7 +129,8 @@
 
  private:
   EntryFrame() { }
-  intptr_t ExitLinkOffset();
+  intptr_t ExitLinkOffset() const;
+  intptr_t SavedContextOffset() const;
 
   friend class StackFrameIterator;
   DISALLOW_COPY_AND_ASSIGN(EntryFrame);
diff --git a/runtime/vm/stack_frame_arm.cc b/runtime/vm/stack_frame_arm.cc
index 1273a01..2d90b32 100644
--- a/runtime/vm/stack_frame_arm.cc
+++ b/runtime/vm/stack_frame_arm.cc
@@ -27,7 +27,13 @@
 }
 
 
-intptr_t EntryFrame::ExitLinkOffset() {
+intptr_t EntryFrame::ExitLinkOffset() const {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+intptr_t EntryFrame::SavedContextOffset() const {
   UNIMPLEMENTED();
   return 0;
 }
diff --git a/runtime/vm/stack_frame_ia32.cc b/runtime/vm/stack_frame_ia32.cc
index 67051bb..b3f554e 100644
--- a/runtime/vm/stack_frame_ia32.cc
+++ b/runtime/vm/stack_frame_ia32.cc
@@ -13,6 +13,7 @@
 
 // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
 // code in the InvokeDartCode stub.
+static const int kSavedContextOffsetInEntryFrame = -5 * kWordSize;
 static const int kExitLinkOffsetInEntryFrame = -4 * kWordSize;
 static const int kPcAddressOffsetFromSp = -1 * kWordSize;
 static const int kSpOffsetFromPreviousFp = 2 * kWordSize;
@@ -33,11 +34,16 @@
 }
 
 
-intptr_t EntryFrame::ExitLinkOffset() {
+intptr_t EntryFrame::ExitLinkOffset() const {
   return kExitLinkOffsetInEntryFrame;
 }
 
 
+intptr_t EntryFrame::SavedContextOffset() const {
+  return kSavedContextOffsetInEntryFrame;
+}
+
+
 void StackFrameIterator::SetupLastExitFrameData() {
   Isolate* current = Isolate::Current();
   uword exit_marker = current->top_exit_frame_info();
diff --git a/runtime/vm/stack_frame_mips.cc b/runtime/vm/stack_frame_mips.cc
index 500a8e6..eb79f18 100644
--- a/runtime/vm/stack_frame_mips.cc
+++ b/runtime/vm/stack_frame_mips.cc
@@ -27,7 +27,13 @@
 }
 
 
-intptr_t EntryFrame::ExitLinkOffset() {
+intptr_t EntryFrame::ExitLinkOffset() const {
+  UNIMPLEMENTED();
+  return 0;
+}
+
+
+intptr_t EntryFrame::SavedContextOffset() const {
   UNIMPLEMENTED();
   return 0;
 }
diff --git a/runtime/vm/stack_frame_x64.cc b/runtime/vm/stack_frame_x64.cc
index 2650b30..d0ae422 100644
--- a/runtime/vm/stack_frame_x64.cc
+++ b/runtime/vm/stack_frame_x64.cc
@@ -13,6 +13,7 @@
 
 // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
 // code in the InvokeDartCode stub.
+static const int kSavedContextOffsetInEntryFrame = -9 * kWordSize;
 static const int kExitLinkOffsetInEntryFrame = -8 * kWordSize;
 static const int kPcAddressOffsetFromSp = -1 * kWordSize;
 static const int kSpOffsetFromPreviousFp = 2 * kWordSize;
@@ -33,11 +34,16 @@
 }
 
 
-intptr_t EntryFrame::ExitLinkOffset() {
+intptr_t EntryFrame::ExitLinkOffset() const {
   return kExitLinkOffsetInEntryFrame;
 }
 
 
+intptr_t EntryFrame::SavedContextOffset() const {
+  return kSavedContextOffsetInEntryFrame;
+}
+
+
 void StackFrameIterator::SetupLastExitFrameData() {
   Isolate* current = Isolate::Current();
   uword exit_marker = current->top_exit_frame_info();
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index bc47212..387a52d 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -745,18 +745,20 @@
   __ movl(EDI, FieldAddress(CTX, Context::isolate_offset()));
 
   // Save the top exit frame info. Use EDX as a temporary register.
+  // StackFrameIterator reads the top exit frame info saved in this frame.
+  // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
+  // code below: kExitLinkOffsetInEntryFrame = -4 * kWordSize.
   __ movl(EDX, Address(EDI, Isolate::top_exit_frame_info_offset()));
   __ pushl(EDX);
   __ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), Immediate(0));
 
-  // StackFrameIterator reads the top exit frame info saved in this frame.
-  // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
-  // code above.
-
   // Save the old Context pointer. Use ECX as a temporary register.
   // Note that VisitObjectPointers will find this saved Context pointer during
   // GC marking, since it traverses any information between SP and
   // FP - kExitLinkOffsetInEntryFrame.
+  // EntryFrame::SavedContext reads the context saved in this frame.
+  // The constant kSavedContextOffsetInEntryFrame must be kept in sync with
+  // the code below: kSavedContextOffsetInEntryFrame = -5 * kWordSize.
   __ movl(ECX, Address(EDI, Isolate::top_context_offset()));
   __ pushl(ECX);
 
@@ -1270,7 +1272,7 @@
       __ movl(EDX, FieldAddress(CTX, Context::isolate_offset()));
       __ movl(Address(ECX, Context::isolate_offset()), EDX);
 
-      // Set the parent field to null.
+      // Set the parent to null.
       __ movl(Address(ECX, Context::parent_offset()), raw_null);
 
       // Initialize the context variable to the receiver.
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 70d9c36..de2b1de 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -735,18 +735,20 @@
   __ movq(R8, FieldAddress(CTX, Context::isolate_offset()));
 
   // Save the top exit frame info. Use RAX as a temporary register.
+  // StackFrameIterator reads the top exit frame info saved in this frame.
+  // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
+  // code below: kExitLinkOffsetInEntryFrame = -8 * kWordSize.
   __ movq(RAX, Address(R8, Isolate::top_exit_frame_info_offset()));
   __ pushq(RAX);
   __ movq(Address(R8, Isolate::top_exit_frame_info_offset()), Immediate(0));
 
-  // StackFrameIterator reads the top exit frame info saved in this frame.
-  // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
-  // code above: kExitLinkOffsetInEntryFrame = -8 * kWordSize.
-
   // Save the old Context pointer. Use RAX as a temporary register.
   // Note that VisitObjectPointers will find this saved Context pointer during
   // GC marking, since it traverses any information between SP and
   // FP - kExitLinkOffsetInEntryFrame.
+  // EntryFrame::SavedContext reads the context saved in this frame.
+  // The constant kSavedContextOffsetInEntryFrame must be kept in sync with
+  // the code below: kSavedContextOffsetInEntryFrame = -9 * kWordSize.
   __ movq(RAX, Address(R8, Isolate::top_context_offset()));
   __ pushq(RAX);
 
@@ -1258,7 +1260,7 @@
       __ movq(R10, FieldAddress(CTX, Context::isolate_offset()));
       __ movq(Address(RBX, Context::isolate_offset()), R10);
 
-      // Set the parent field to null.
+      // Set the parent to null.
       __ movq(Address(RBX, Context::parent_offset()), raw_null);
 
       // Initialize the context variable to the receiver.
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 1ab5563..caec906 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -54,8 +54,9 @@
   V(GetIterator, "iterator")                                                   \
   V(NoSuchMethod, "noSuchMethod")                                              \
   V(SavedArgDescVarPrefix, ":saved_args_desc_var")                             \
+  V(SavedCurrentContextVar, ":saved_current_context_var")                      \
   V(SavedEntryContextVar, ":saved_entry_context_var")                          \
-  V(SavedContextVar, ":saved_context_var")                                     \
+  V(SavedTryContextVar, ":saved_try_context_var")                              \
   V(ExceptionVar, ":exception_var")                                            \
   V(StacktraceVar, ":stacktrace_var")                                          \
   V(ListLiteralElement, "list literal element")                                \
@@ -191,6 +192,17 @@
   V(PrivateGetterPrefix, "get:_")                                              \
   V(PrivateSetterPrefix, "set:_")                                              \
   V(_New, "_new")                                                              \
+  V(DartScheme, "dart:")                                                       \
+  V(DartSchemePrivate, "dart:_")                                               \
+  V(DartCore, "dart:core")                                                     \
+  V(DartCollection, "dart:collection")                                         \
+  V(DartCollectionDev, "dart:_collection-dev")                                 \
+  V(DartMath, "dart:math")                                                     \
+  V(DartIsolate, "dart:isolate")                                               \
+  V(DartMirrors, "dart:mirrors")                                               \
+  V(DartScalarlist, "dart:scalarlist")                                         \
+  V(DartNativeWrappers, "dart:nativewrappers")                                 \
+  V(DartAsync, "dart:async")                                                   \
 
 
 // Contains a list of frequently used strings in a canonicalized form. This
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 7859a5e..bd15b1e 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -15,6 +15,7 @@
 #include "vm/longjump.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
+#include "vm/simulator.h"
 #include "vm/zone.h"
 
 // The UNIT_TEST_CASE macro is used for tests that do not need any
@@ -128,6 +129,49 @@
   }
 
 
+#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+#if defined(HOST_ARCH_ARM) || defined(HOST_ARCH_MIPS)
+// Running on actual ARM or MIPS hardware, execute code natively.
+#define EXECUTE_TEST_CODE_INT32(name, entry) reinterpret_cast<name>(entry)()
+#define EXECUTE_TEST_CODE_INT64_LL(name, entry, long_arg0, long_arg1)          \
+    reinterpret_cast<name>(entry)(long_arg0, long_arg1)
+#define EXECUTE_TEST_CODE_FLOAT(name, entry) reinterpret_cast<name>(entry)()
+#define EXECUTE_TEST_CODE_DOUBLE(name, entry) reinterpret_cast<name>(entry)()
+#define EXECUTE_TEST_CODE_INT32_F(name, entry, float_arg)                      \
+    reinterpret_cast<name>(entry)(float_arg)
+#define EXECUTE_TEST_CODE_INT32_D(name, entry, double_arg)                     \
+    reinterpret_cast<name>(entry)(double_arg)
+#else
+// Not running on ARM or MIPS hardware, call simulator to execute code.
+#define EXECUTE_TEST_CODE_INT32(name, entry)                                   \
+  static_cast<int32_t>(Simulator::Current()->Call((int32_t)entry,              \
+      0, 0, 0, 0, 0))
+#define EXECUTE_TEST_CODE_INT64_LL(name, entry, long_arg0, long_arg1)          \
+  static_cast<int64_t>(Simulator::Current()->Call((int32_t)entry,              \
+      Utils::Low32Bits(long_arg0),                                             \
+      Utils::High32Bits(long_arg0),                                            \
+      Utils::Low32Bits(long_arg1),                                             \
+      Utils::High32Bits(long_arg1),                                            \
+      0))
+#define EXECUTE_TEST_CODE_FLOAT(name, entry)                                   \
+  bit_cast<float, int32_t>(Simulator::Current()->Call((int32_t)entry,          \
+      0, 0, 0, 0, 0))
+#define EXECUTE_TEST_CODE_DOUBLE(name, entry)                                  \
+  bit_cast<double, int64_t>(Simulator::Current()->Call((int32_t)entry,         \
+      0, 0, 0, 0, 0))
+#define EXECUTE_TEST_CODE_INT32_F(name, entry, float_arg)                      \
+  static_cast<int32_t>(Simulator::Current()->Call((int32_t)entry,              \
+      bit_cast<int32_t, float>(float_arg),                                     \
+      0, 0, 0, 0))
+#define EXECUTE_TEST_CODE_INT32_D(name, entry, double_arg)                     \
+  static_cast<int32_t>(Simulator::Current()->Call((int32_t)entry,              \
+      Utils::Low32Bits(bit_cast<int64_t, double>(double_arg)),                 \
+      Utils::High32Bits(bit_cast<int64_t, double>(double_arg)),                \
+      0, 0, 0))
+#endif  // defined(HOST_ARCH_ARM) || defined(HOST_ARCH_MIPS)
+#endif  // defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+
+
 inline Dart_Handle NewString(const char* str) {
   return Dart_NewStringFromCString(str);
 }
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index 6c887e7..9ed725d 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -363,7 +363,7 @@
       },
       'includes': [
         # Load the shared collection_dev library sources.
-        '../../sdk/lib/collection_dev/collection_dev_sources.gypi',
+        '../../sdk/lib/_collection_dev/collection_dev_sources.gypi',
       ],
       'sources/': [
         # Exclude all .[cc|h] files.
diff --git a/sdk/lib/collection_dev/collection_dev.dart b/sdk/lib/_collection_dev/collection_dev.dart
similarity index 69%
rename from sdk/lib/collection_dev/collection_dev.dart
rename to sdk/lib/_collection_dev/collection_dev.dart
index 12e8e62..839fd1c 100644
--- a/sdk/lib/collection_dev/collection_dev.dart
+++ b/sdk/lib/_collection_dev/collection_dev.dart
@@ -2,9 +2,12 @@
 // 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 dart.collection.dev;
+library dart._collection.dev;
 
 part 'iterable.dart';
 part 'list.dart';
 part 'sort.dart';
 part 'to_string.dart';
+
+// TODO(floitsch): move this into core, another hidden library or remove it.
+const deprecated = 0;
diff --git a/sdk/lib/collection_dev/collection_dev_sources.gypi b/sdk/lib/_collection_dev/collection_dev_sources.gypi
similarity index 100%
rename from sdk/lib/collection_dev/collection_dev_sources.gypi
rename to sdk/lib/_collection_dev/collection_dev_sources.gypi
diff --git a/sdk/lib/collection_dev/iterable.dart b/sdk/lib/_collection_dev/iterable.dart
similarity index 91%
rename from sdk/lib/collection_dev/iterable.dart
rename to sdk/lib/_collection_dev/iterable.dart
index 9729e1c..89b9e6d 100644
--- a/sdk/lib/collection_dev/iterable.dart
+++ b/sdk/lib/_collection_dev/iterable.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of dart.collection.dev;
+part of dart._collection.dev;
 
 typedef T _Transformation<S, T>(S value);
 
@@ -405,6 +405,55 @@
   E get current => _iterator.current;
 }
 
+typedef Iterable<T> _ExpandFunction<S, T>(S sourceElement);
+
+class ExpandIterable<S, T> extends Iterable<T> {
+  final Iterable<S> _iterable;
+  // TODO(ahe): Restore type when feature is implemented in dart2js
+  // checked mode. http://dartbug.com/7733
+  final /* _ExpandFunction */ _f;
+
+  ExpandIterable(this._iterable, Iterable<T> this._f(S element));
+
+  Iterator<T> get iterator => new ExpandIterator<S, T>(_iterable.iterator, _f);
+}
+
+class ExpandIterator<S, T> implements Iterator<T> {
+  final Iterator<S> _iterator;
+  // TODO(ahe): Restore type when feature is implemented in dart2js
+  // checked mode. http://dartbug.com/7733
+  final /* _ExpandFunction */ _f;
+  // Initialize _currentExpansion to an empty iterable. A null value
+  // marks the end of iteration, and we don't want to call _f before
+  // the first moveNext call.
+  Iterator<T> _currentExpansion = const EmptyIterator();
+  T _current;
+
+  ExpandIterator(this._iterator, Iterable<T> this._f(S element));
+
+  void _nextExpansion() {
+  }
+
+  T get current => _current;
+
+  bool moveNext() {
+    if (_currentExpansion == null) return false;
+    while (!_currentExpansion.moveNext()) {
+      _current = null;
+      if (_iterator.moveNext()) {
+        // If _f throws, this ends iteration. Otherwise _currentExpansion and
+        // _current will be set again below.
+        _currentExpansion = null;
+        _currentExpansion = _f(_iterator.current).iterator;
+      } else {
+        return false;
+      }
+    }
+    _current = _currentExpansion.current;
+    return true;
+  }
+}
+
 class TakeIterable<E> extends Iterable<E> {
   final Iterable<E> _iterable;
   final int _takeCount;
diff --git a/sdk/lib/collection_dev/list.dart b/sdk/lib/_collection_dev/list.dart
similarity index 99%
rename from sdk/lib/collection_dev/list.dart
rename to sdk/lib/_collection_dev/list.dart
index 09d6deb..7af0fbb 100644
--- a/sdk/lib/collection_dev/list.dart
+++ b/sdk/lib/_collection_dev/list.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of dart.collection.dev;
+part of dart._collection.dev;
 
 /**
  * Class implementing the read-operations on [List].
diff --git a/sdk/lib/collection_dev/sort.dart b/sdk/lib/_collection_dev/sort.dart
similarity index 99%
rename from sdk/lib/collection_dev/sort.dart
rename to sdk/lib/_collection_dev/sort.dart
index 9b89e63..73276b2 100644
--- a/sdk/lib/collection_dev/sort.dart
+++ b/sdk/lib/_collection_dev/sort.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of dart.collection.dev;
+part of dart._collection.dev;
 
 /**
  * Dual-Pivot Quicksort algorithm.
diff --git a/sdk/lib/collection_dev/to_string.dart b/sdk/lib/_collection_dev/to_string.dart
similarity index 99%
rename from sdk/lib/collection_dev/to_string.dart
rename to sdk/lib/_collection_dev/to_string.dart
index c55ccac..21cbf0c 100644
--- a/sdk/lib/collection_dev/to_string.dart
+++ b/sdk/lib/_collection_dev/to_string.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of dart.collection.dev;
+part of dart._collection.dev;
 
 /**
  * Temporary move `toString` methods into this class.
diff --git a/sdk/lib/_internal/compiler/compiler.dart b/sdk/lib/_internal/compiler/compiler.dart
index cf7eb2a..bbee705 100644
--- a/sdk/lib/_internal/compiler/compiler.dart
+++ b/sdk/lib/_internal/compiler/compiler.dart
@@ -22,7 +22,7 @@
 typedef Future<String> ReadStringFromUri(Uri uri);
 
 /**
- * Returns a [Sink] that will serve as compiler output for the given
+ * Returns a [StreamSink] that will serve as compiler output for the given
  * component.
  *
  * Components are identified by [name] and [extension]. By convention,
@@ -41,7 +41,8 @@
  * As more features are added to the compiler, new names and
  * extensions may be introduced.
  */
-typedef Sink<String> CompilerOutputProvider(String name, String extension);
+typedef StreamSink<String> CompilerOutputProvider(String name,
+                                                  String extension);
 
 /**
  * Invoked by the compiler to report diagnostics. If [uri] is
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 6bf404e..4b1fc3b 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -80,8 +80,7 @@
   }
 
   void run(Compiler compiler, CodegenEnqueuer world) {
-    js.Expression code = world.universe.generatedCode[element];
-    if (code != null) return;
+    if (world.isProcessed(element)) return;
     compiler.codegen(this, world);
   }
 }
@@ -376,8 +375,8 @@
         this, backend.constantSystem, isMetadata: true);
   }
 
-  ResolutionUniverse get resolverWorld => enqueuer.resolution.universe;
-  CodegenUniverse get codegenWorld => enqueuer.codegen.universe;
+  Universe get resolverWorld => enqueuer.resolution.universe;
+  Universe get codegenWorld => enqueuer.codegen.universe;
 
   int getNextFreeClassId() => nextFreeClassId++;
 
@@ -450,6 +449,8 @@
       return spanFromHInstruction(node);
     } else if (node is Element) {
       return spanFromElement(node);
+    } else if (node is MetadataAnnotation) {
+      return spanFromTokens(node.beginToken, node.endToken);
     } else {
       throw 'No error location.';
     }
@@ -720,7 +721,7 @@
     }
     if (!REPORT_EXCESS_RESOLUTION) return;
     var resolved = new Set.from(enqueuer.resolution.resolvedElements.keys);
-    for (Element e in codegenWorld.generatedCode.keys) {
+    for (Element e in enqueuer.codegen.generatedCode.keys) {
       resolved.remove(e);
     }
     for (Element e in new Set.from(resolved)) {
@@ -762,8 +763,11 @@
     Node tree = parser.parse(element);
     validator.validate(tree);
     elements = resolver.resolve(element);
-    checker.check(tree, elements);
-    typesTask.analyze(tree, elements);
+    if (elements != null) {
+      // Only analyze nodes with a corresponding [TreeElements].
+      checker.check(tree, elements);
+      typesTask.analyze(tree, elements);
+    }
     return elements;
   }
 
@@ -794,7 +798,7 @@
     if (progress.elapsedMilliseconds > 500) {
       // TODO(ahe): Add structured diagnostics to the compiler API and
       // use it to separate this from the --verbose option.
-      log('Compiled ${codegenWorld.generatedCode.length} methods.');
+      log('Compiled ${enqueuer.codegen.generatedCode.length} methods.');
       progress.reset();
     }
     backend.codegen(work);
@@ -839,7 +843,6 @@
       if (identical(message.message.kind, MessageKind.NOT_ASSIGNABLE)) return;
       if (identical(message.message.kind, MessageKind.MISSING_RETURN)) return;
       if (identical(message.message.kind, MessageKind.MAYBE_MISSING_RETURN)) return;
-      if (identical(message.message.kind, MessageKind.ADDITIONAL_ARGUMENT)) return;
       if (identical(message.message.kind, MessageKind.METHOD_NOT_FOUND)) return;
     }
     SourceSpan span = spanFromNode(node);
@@ -1107,13 +1110,15 @@
 }
 
 /// A sink that drains into /dev/null.
-class NullSink extends Sink<String> {
+class NullSink extends StreamSink<String> {
   final String name;
 
   NullSink(this.name);
 
   add(String value) {}
 
+  void signalError(AsyncError error) {}
+
   void close() {}
 
   toString() => name;
diff --git a/sdk/lib/_internal/compiler/implementation/dart2js.dart b/sdk/lib/_internal/compiler/implementation/dart2js.dart
index d66579f..ac7d422 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2js.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2js.dart
@@ -201,7 +201,6 @@
     new OptionHandler('--analyze-all', passThrough),
     new OptionHandler('--analyze-only', setAnalyzeOnly),
     new OptionHandler('--disable-native-live-type-analysis', passThrough),
-    new OptionHandler('--enable-native-live-type-analysis', passThrough),
     new OptionHandler('--reject-deprecated-language-features', passThrough),
     new OptionHandler('--report-sdk-use-of-deprecated-language-features',
                       passThrough),
@@ -263,7 +262,7 @@
     }
   }
 
-  Sink<String> outputProvider(String name, String extension) {
+  StreamSink<String> outputProvider(String name, String extension) {
     Uri uri;
     String sourceMapFileName;
     bool isPrimaryOutput = false;
@@ -314,8 +313,8 @@
 }
 
 // TODO(ahe): Get rid of this class if http://dartbug.com/8118 is fixed.
-class CountingSink implements Sink<String> {
-  final Sink<String> sink;
+class CountingSink implements StreamSink<String> {
+  final StreamSink<String> sink;
   int count = 0;
 
   CountingSink(this.sink);
@@ -325,6 +324,8 @@
     count += value.length;
   }
 
+  signalError(AsyncError error) => sink.signalError(error);
+
   close() => sink.close();
 }
 
@@ -430,12 +431,12 @@
   --enable-concrete-type-inference
     Enable experimental concrete type inference.
 
-  --enable-native-live-type-analysis
-    Remove unused native types from dart:html and related libraries. This is
-    expected to become the default behavior.
+  --disable-native-live-type-analysis
+    Disable the optimization that removes unused native types from dart:html
+    and related libraries.
 
   --disallow-unsafe-eval
-    Disables dynamic generation of code in the generated output. This is
+    Disable dynamic generation of code in the generated output. This is
     necessary to satisfy CSP restrictions (see http://www.w3.org/TR/CSP/).
     This flag is not continuously tested. Please report breakages and we
     will fix them as soon as possible.
diff --git a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
index 8a1e012..9b683f2 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
@@ -4,6 +4,7 @@
 
 library dart2js;
 
+import 'dart:async';
 import 'dart:uri';
 import 'dart:collection' show Queue, LinkedHashMap;
 
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
index 0d421b3..c30a2cf 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
@@ -213,8 +213,7 @@
       visit(node.name), visit(node.bound));
 
   visitVariableDefinitions(VariableDefinitions node) => new VariableDefinitions(
-      visit(node.type), visit(node.modifiers), visit(node.definitions),
-      node.endToken);
+      visit(node.type), visit(node.modifiers), visit(node.definitions));
 
   visitWhile(While node) => new While(
       visit(node.condition), visit(node.body), node.whileKeyword);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index b43de38..7c78bd5 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -293,22 +293,16 @@
   return false;
 }
 
-// TODO(johnniwinther): Add common supertype for InterfaceType and TypedefType.
-class InterfaceType extends DartType {
-  final ClassElement element;
+abstract class GenericType extends DartType {
   final Link<DartType> typeArguments;
   final bool isMalformed;
 
-  InterfaceType(this.element,
-                [Link<DartType> typeArguments = const Link<DartType>()])
-      : this.typeArguments = typeArguments,
-        this.isMalformed = hasMalformed(typeArguments) {
-    assert(invariant(element, element.isDeclaration));
-  }
+  GenericType(Link<DartType> this.typeArguments, bool this.isMalformed);
 
-  TypeKind get kind => TypeKind.INTERFACE;
+  TypeDeclarationElement get element;
 
-  SourceString get name => element.name;
+  /// Creates a new instance of this type using the provided type arguments.
+  GenericType _createType(Link<DartType> newTypeArguments);
 
   DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
     if (typeArguments.isEmpty) {
@@ -324,7 +318,7 @@
         Types.substTypes(typeArguments, arguments, parameters);
     if (!identical(typeArguments, newTypeArguments)) {
       // Create a new type only if necessary.
-      return new InterfaceType(element, newTypeArguments);
+      return _createType(newTypeArguments);
     }
     return this;
   }
@@ -338,26 +332,6 @@
     return true;
   }
 
-  /**
-   * Returns the type as an instance of class [other], if possible, null
-   * otherwise.
-   */
-  DartType asInstanceOf(ClassElement other) {
-    if (element == other) return this;
-    for (InterfaceType supertype in element.allSupertypes) {
-      ClassElement superclass = supertype.element;
-      if (superclass == other) {
-        Link<DartType> arguments = Types.substTypes(supertype.typeArguments,
-                                                    typeArguments,
-                                                    element.typeVariables);
-        return new InterfaceType(superclass, arguments);
-      }
-    }
-    return null;
-  }
-
-  DartType unalias(Compiler compiler) => this;
-
   String toString() {
     StringBuffer sb = new StringBuffer();
     sb.add(name.slowToString());
@@ -381,14 +355,59 @@
   }
 
   bool operator ==(other) {
-    if (other is !InterfaceType) return false;
     if (!identical(element, other.element)) return false;
     return typeArguments == other.typeArguments;
   }
 
   bool get isRaw => typeArguments.isEmpty || identical(this, element.rawType);
 
-  InterfaceType asRaw() => element.rawType;
+  GenericType asRaw() => element.rawType;
+}
+
+// TODO(johnniwinther): Add common supertype for InterfaceType and TypedefType.
+class InterfaceType extends GenericType {
+  final ClassElement element;
+
+  InterfaceType(this.element,
+                [Link<DartType> typeArguments = const Link<DartType>()])
+      : super(typeArguments, hasMalformed(typeArguments)) {
+    assert(invariant(element, element.isDeclaration));
+  }
+
+  TypeKind get kind => TypeKind.INTERFACE;
+
+  SourceString get name => element.name;
+
+  InterfaceType _createType(Link<DartType> newTypeArguments) {
+    return new InterfaceType(element, newTypeArguments);
+  }
+
+  /**
+   * Returns the type as an instance of class [other], if possible, null
+   * otherwise.
+   */
+  DartType asInstanceOf(ClassElement other) {
+    if (element == other) return this;
+    for (InterfaceType supertype in element.allSupertypes) {
+      ClassElement superclass = supertype.element;
+      if (superclass == other) {
+        Link<DartType> arguments = Types.substTypes(supertype.typeArguments,
+                                                    typeArguments,
+                                                    element.typeVariables);
+        return new InterfaceType(superclass, arguments);
+      }
+    }
+    return null;
+  }
+
+  DartType unalias(Compiler compiler) => this;
+
+  bool operator ==(other) {
+    if (other is !InterfaceType) return false;
+    return super == other;
+  }
+
+  InterfaceType asRaw() => super.asRaw();
 }
 
 class FunctionType extends DartType {
@@ -447,6 +466,19 @@
 
   TypeKind get kind => TypeKind.FUNCTION;
 
+  DartType getNamedParameterType(SourceString name) {
+    Link<SourceString> namedParameter = namedParameters;
+    Link<DartType> namedParameterType = namedParameterTypes;
+    while (!namedParameter.isEmpty && !namedParameterType.isEmpty) {
+      if (namedParameter.head == name) {
+        return namedParameterType.head;
+      }
+      namedParameter = namedParameter.tail;
+      namedParameterType = namedParameterType.tail;
+    }
+    return null;
+  }
+
   DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
     if (parameters.isEmpty) {
       assert(arguments.isEmpty);
@@ -577,48 +609,21 @@
   }
 }
 
-class TypedefType extends DartType {
+class TypedefType extends GenericType {
   final TypedefElement element;
-  final Link<DartType> typeArguments;
-  final bool isMalformed;
 
   TypedefType(this.element,
               [Link<DartType> typeArguments = const Link<DartType>()])
-      : this.typeArguments = typeArguments,
-        this.isMalformed = hasMalformed(typeArguments);
+      : super(typeArguments, hasMalformed(typeArguments));
+
+  TypedefType _createType(Link<DartType> newTypeArguments) {
+    return new TypedefType(element, newTypeArguments);
+  }
 
   TypeKind get kind => TypeKind.TYPEDEF;
 
   SourceString get name => element.name;
 
-  DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
-    if (typeArguments.isEmpty) {
-      // Return fast on non-generic typedefs.
-      return this;
-    }
-    if (parameters.isEmpty) {
-      assert(arguments.isEmpty);
-      // Return fast on empty substitutions.
-      return this;
-    }
-    Link<DartType> newTypeArguments = Types.substTypes(typeArguments, arguments,
-                                                       parameters);
-    if (!identical(typeArguments, newTypeArguments)) {
-      // Create a new type only if necessary.
-      return new TypedefType(element, newTypeArguments);
-    }
-    return this;
-  }
-
-  bool forEachMalformedType(bool f(MalformedType type)) {
-    for (DartType typeArgument in typeArguments) {
-      if (!typeArgument.forEachMalformedType(f)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
   DartType unalias(Compiler compiler) {
     // TODO(ahe): This should be [ensureResolved].
     compiler.resolveTypedef(element);
@@ -627,28 +632,12 @@
     return definition.subst(typeArguments, declaration.typeArguments);
   }
 
-  String toString() {
-    StringBuffer sb = new StringBuffer();
-    sb.add(name.slowToString());
-    if (!isRaw) {
-      sb.add('<');
-      typeArguments.printOn(sb, ', ');
-      sb.add('>');
-    }
-    return sb.toString();
-  }
-
-  int get hashCode => 17 * element.hashCode;
-
   bool operator ==(other) {
     if (other is !TypedefType) return false;
-    if (!identical(element, other.element)) return false;
-    return typeArguments == other.typeArguments;
+    return super == other;
   }
 
-  bool get isRaw => typeArguments.isEmpty || identical(this, element.rawType);
-
-  TypedefType asRaw() => element.rawType;
+  TypedefType asRaw() => super.asRaw();
 }
 
 /**
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 81e2fc0..2798f95 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -625,6 +625,8 @@
  * declarations and typedefs.
  */
 abstract class TypeDeclarationElement extends Element {
+  GenericType get rawType;
+
   /**
    * The type variables declared on this declaration. The type variables are not
    * available until the type of the element has been computed through
@@ -775,11 +777,12 @@
   void set bound(DartType value);
 }
 
-abstract class MetadataAnnotation {
+abstract class MetadataAnnotation implements Spannable {
   Constant get value;
   Element get annotatedElement;
   int get resolutionState;
   Token get beginToken;
+  Token get endToken;
 
   // TODO(kasperl): Try to get rid of these.
   void set annotatedElement(Element value);
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 8c43df5..f007946 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -1700,7 +1700,10 @@
    * account.
    */
   bool isSubclassOf(ClassElement cls) {
-    for (ClassElement s = this; s != null; s = s.superclass) {
+    // Use [declaration] for both [this] and [cls], because
+    // declaration classes hold the superclass hierarchy.
+    cls = cls.declaration;
+    for (ClassElement s = declaration; s != null; s = s.superclass) {
       if (identical(s, cls)) return true;
     }
     return false;
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index ea98278..4a4fea8 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -31,6 +31,7 @@
   final Function itemCompilationContextCreator;
   final Map<String, Link<Element>> instanceMembersByName;
   final Set<ClassElement> seenClasses;
+  final Universe universe;
 
   bool queueIsClosed = false;
   EnqueueTask task;
@@ -40,10 +41,9 @@
            ItemCompilationContext itemCompilationContextCreator())
     : this.itemCompilationContextCreator = itemCompilationContextCreator,
       instanceMembersByName = new Map<String, Link<Element>>(),
+      universe = new Universe(),
       seenClasses = new Set<ClassElement>();
 
-  Universe get universe;
-
   /// Returns [:true:] if this enqueuer is the resolution enqueuer.
   bool get isResolutionQueue => false;
 
@@ -272,7 +272,7 @@
 
   void handleUnseenSelector(SourceString methodName, Selector selector) {
     processInstanceMembers(methodName, (Element member) {
-      if (selector.applies(member, compiler)) {
+      if (selector.appliesUnnamed(member, compiler)) {
         if (member.isField() && member.enclosingElement.isNative()) {
           if (selector.isGetter() || selector.isCall()) {
             nativeEnqueuer.registerFieldLoad(member);
@@ -319,8 +319,26 @@
     registerInvocation(methodName, selector);
   }
 
-  void registerDynamicInvocationOf(Element element) {
-    addToWorkList(element);
+  void registerDynamicInvocationOf(Element element, Selector selector) {
+    assert(selector.isCall()
+           || selector.isOperator()
+           || selector.isIndex()
+           || selector.isIndexSet());
+    if (element.isFunction()) {
+      addToWorkList(element);
+    } else if (element.isAbstractField()) {
+      AbstractFieldElement field = element;
+      // Since the invocation is a dynamic call on a getter, we only
+      // need to schedule the getter on the work list.
+      addToWorkList(field.getter);
+    } else {
+      assert(element.isField());
+    }
+    // We also need to add the selector to the invoked names map,
+    // because the emitter uses that map to generate parameter stubs.
+    Set<Selector> selectors = universe.invokedNames.putIfAbsent(
+        element.name, () => new Set<Selector>());
+    selectors.add(selector);
   }
 
   void registerDynamicGetter(SourceString methodName, Selector selector) {
@@ -331,6 +349,28 @@
     registerInvokedSetter(methodName, selector);
   }
 
+  void registerFieldGetter(SourceString getterName,
+                           LibraryElement library,
+                           DartType type) {
+    task.measure(() {
+      Selector getter = new Selector.getter(getterName, library);
+      registerNewSelector(getterName,
+                          new TypedSelector(type, getter),
+                          universe.fieldGetters);
+    });
+  }
+
+  void registerFieldSetter(SourceString setterName,
+                           LibraryElement library,
+                           DartType type) {
+    task.measure(() {
+      Selector setter = new Selector.setter(setterName, library);
+      registerNewSelector(setterName,
+                          new TypedSelector(type, setter),
+                          universe.fieldSetters);
+    });
+  }
+
   void registerIsCheck(DartType type) {
     universe.isChecks.add(type);
   }
@@ -350,8 +390,6 @@
 
 /// [Enqueuer] which is specific to resolution.
 class ResolutionEnqueuer extends Enqueuer {
-  final ResolutionUniverse universe;
-
   /**
    * Map from declaration elements to the [TreeElements] object holding the
    * resolution mapping for the element implementation.
@@ -366,7 +404,6 @@
                      ItemCompilationContext itemCompilationContextCreator())
       : super('resolution enqueuer', compiler, itemCompilationContextCreator),
         resolvedElements = new Map<Element, TreeElements>(),
-        universe = new ResolutionUniverse(),
         queue = new Queue<ResolutionWorkItem>();
 
   bool get isResolutionQueue => true;
@@ -445,12 +482,12 @@
 
   void enableNoSuchMethod(Element element) {
     if (compiler.enabledNoSuchMethod) return;
+    Selector selector = new Selector.noSuchMethod();
     if (identical(element.getEnclosingClass(), compiler.objectClass)) {
-      registerDynamicInvocationOf(element);
+      registerDynamicInvocationOf(element, selector);
       return;
     }
     compiler.enabledNoSuchMethod = true;
-    Selector selector = new Selector.noSuchMethod();
     registerInvocation(Compiler.NO_SUCH_METHOD, selector);
 
     compiler.createInvocationMirrorElement =
@@ -476,40 +513,16 @@
 
 /// [Enqueuer] which is specific to code generation.
 class CodegenEnqueuer extends Enqueuer {
-  final CodegenUniverse universe;
-
   final Queue<CodegenWorkItem> queue;
+  final Map<Element, js.Expression> generatedCode =
+      new Map<Element, js.Expression>();
 
   CodegenEnqueuer(Compiler compiler,
                   ItemCompilationContext itemCompilationContextCreator())
       : super('codegen enqueuer', compiler, itemCompilationContextCreator),
-        universe = new CodegenUniverse(),
         queue = new Queue<CodegenWorkItem>();
 
-  bool isProcessed(Element member) =>
-      universe.generatedCode.containsKey(member);
-
-  /**
-   * Unit test hook that returns code of an element as a String.
-   *
-   * Invariant: [element] must be a declaration element.
-   */
-  String assembleCode(Element element) {
-    assert(invariant(element, element.isDeclaration));
-    return js.prettyPrint(universe.generatedCode[element], compiler).getText();
-  }
-
-  /**
-   * Documentation wanted -- johnniwinther
-   *
-   * Invariant: [element] must be a declaration element.
-   */
-  void eagerRecompile(Element element) {
-    assert(invariant(element, element.isDeclaration));
-    universe.generatedCode.remove(element);
-    universe.generatedBailoutCode.remove(element);
-    addToWorkList(element);
-  }
+  bool isProcessed(Element member) => generatedCode.containsKey(member);
 
   bool addElementToWorkList(Element element, [TreeElements elements]) {
     if (queueIsClosed) {
@@ -526,28 +539,6 @@
     return true;
   }
 
-  void registerFieldGetter(SourceString getterName,
-                           LibraryElement library,
-                           DartType type) {
-    task.measure(() {
-      Selector getter = new Selector.getter(getterName, library);
-      registerNewSelector(getterName,
-                          new TypedSelector(type, getter),
-                          universe.fieldGetters);
-    });
-  }
-
-  void registerFieldSetter(SourceString setterName,
-                           LibraryElement library,
-                           DartType type) {
-    task.measure(() {
-      Selector setter = new Selector.setter(setterName, library);
-      registerNewSelector(setterName,
-                          new TypedSelector(type, setter),
-                          universe.fieldSetters);
-    });
-  }
-
   void forEach(f(WorkItem work)) {
     while(!queue.isEmpty) {
       // TODO(johnniwinther): Find an optimal process order for codegen.
@@ -556,6 +547,6 @@
   }
 
   void _logSpecificSummary(log(message)) {
-    log('Compiled ${universe.generatedCode.length} methods.');
+    log('Compiled ${generatedCode.length} methods.');
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index a3e2a7e..2a681d8 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -621,6 +621,19 @@
   SsaCodeGeneratorTask generator;
   CodeEmitterTask emitter;
 
+  /**
+   * The generated code as a js AST for compiled methods. 
+   */
+  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, js.Expression> generatedBailoutCode =
+      new Map<Element, js.Expression>();
+
   ClassElement jsStringClass;
   ClassElement jsArrayClass;
   ClassElement jsNumberClass;
@@ -636,6 +649,7 @@
   Element jsArrayAdd;
   Element jsStringSplit;
   Element jsStringConcat;
+  Element jsStringToString;
   Element getInterceptorMethod;
   Element fixedLengthListConstructor;
   bool seenAnyClass = false;
@@ -801,6 +815,8 @@
         jsStringClass, const SourceString('split'));
     jsStringConcat = compiler.lookupElementIn(
         jsStringClass, const SourceString('concat'));
+    jsStringToString = compiler.lookupElementIn(
+        jsStringClass, const SourceString('toString'));
 
     for (ClassElement cls in classes) {
       if (cls != null) interceptedClasses[cls] = null;
@@ -868,10 +884,12 @@
       addInterceptors(jsArrayClass, enqueuer);
       // The backend will try to optimize array access and use the
       // `ioore` and `iae` helpers directly.
-      enqueuer.registerStaticUse(
-          compiler.findHelper(const SourceString('ioore')));
-      enqueuer.registerStaticUse(
-          compiler.findHelper(const SourceString('iae')));
+      if (enqueuer.isResolutionQueue) {
+        enqueuer.registerStaticUse(
+            compiler.findHelper(const SourceString('ioore')));
+        enqueuer.registerStaticUse(
+            compiler.findHelper(const SourceString('iae')));
+      }
     } else if (cls == compiler.intClass) {
       addInterceptors(jsIntClass, enqueuer);
       addInterceptors(jsNumberClass, enqueuer);
@@ -888,6 +906,12 @@
       addInterceptors(jsIntClass, enqueuer);
       addInterceptors(jsDoubleClass, enqueuer);
       addInterceptors(jsNumberClass, enqueuer);
+    } else if (cls == compiler.mapClass) {
+      // The backend will use a literal list to initialize the entries
+      // of the map.
+      if (enqueuer.isResolutionQueue) {
+        enqueuer.registerInstantiatedClass(compiler.listClass); 
+      }
     }
   }
 
@@ -917,7 +941,8 @@
   }
 
   void codegen(CodegenWorkItem work) {
-    if (work.element.kind.category == ElementCategory.VARIABLE) {
+    Element element = work.element;
+    if (element.kind.category == ElementCategory.VARIABLE) {
       Constant initialValue = compiler.constantHandler.compileWorkItem(work);
       if (initialValue != null) {
         return;
@@ -935,13 +960,13 @@
     if (work.allowSpeculativeOptimization
         && optimizer.trySpeculativeOptimizations(work, graph)) {
       js.Expression code = generator.generateBailoutMethod(work, graph);
-      compiler.codegenWorld.addBailoutCode(work, code);
+      generatedBailoutCode[element] = code;
       optimizer.prepareForSpeculativeOptimizations(work, graph);
       optimizer.optimize(work, graph, true);
     }
     js.Expression code = generator.generateCode(work, graph);
-    compiler.codegenWorld.addGeneratedCode(work, code);
-    invalidateAfterCodegen.forEach(compiler.enqueuer.codegen.eagerRecompile);
+    generatedCode[element] = code;
+    invalidateAfterCodegen.forEach(eagerRecompile);
     invalidateAfterCodegen.clear();
   }
 
@@ -953,6 +978,16 @@
     return new native.NativeCodegenEnqueuer(world, compiler, emitter);
   }
 
+  /**
+   * Unit test hook that returns code of an element as a String.
+   *
+   * Invariant: [element] must be a declaration element.
+   */
+  String assembleCode(Element element) {
+    assert(invariant(element, element.isDeclaration));
+    return js.prettyPrint(generatedCode[element], compiler).getText();
+  }
+
   void assembleProgram() {
     emitter.assembleProgram();
   }
@@ -1106,6 +1141,13 @@
     return fieldTypes.optimisticFieldType(element);
   }
 
+  /**
+   * Return the checked mode helper name that will be needed to do a
+   * type check on [type] at runtime. Note that this method is being
+   * called both by the resolver with interface types (int, String,
+   * ...), and by the SSA backend with implementation types (JSInt,
+   * JSString, ...).
+   */
   SourceString getCheckedModeHelper(DartType type) {
     Element element = type.element;
     bool nativeCheck =
@@ -1116,17 +1158,18 @@
       return const SourceString('malformedTypeCheck');
     } else if (type == compiler.types.voidType) {
       return const SourceString('voidTypeCheck');
-    } else if (element == compiler.stringClass) {
+    } else if (element == jsStringClass || element == compiler.stringClass) {
       return const SourceString('stringTypeCheck');
-    } else if (element == compiler.doubleClass) {
+    } else if (element == jsDoubleClass || element == compiler.doubleClass) {
       return const SourceString('doubleTypeCheck');
-    } else if (element == compiler.numClass) {
+    } else if (element == jsNumberClass || element == compiler.numClass) {
       return const SourceString('numTypeCheck');
-    } else if (element == compiler.boolClass) {
+    } else if (element == jsBoolClass || element == compiler.boolClass) {
       return const SourceString('boolTypeCheck');
-    } else if (element == compiler.functionClass) {
+    } else if (element == jsFunctionClass
+               || element == compiler.functionClass) {
       return const SourceString('functionTypeCheck');
-    } else if (element == compiler.intClass) {
+    } else if (element == jsIntClass || element == compiler.intClass) {
       return const SourceString('intTypeCheck');
     } else if (Elements.isNumberOrStringSupertype(element, compiler)) {
       return nativeCheck
@@ -1136,7 +1179,7 @@
       return nativeCheck
           ? const SourceString('stringSuperNativeTypeCheck')
           : const SourceString('stringSuperTypeCheck');
-    } else if (identical(element, compiler.listClass)) {
+    } else if (element == compiler.listClass || element == jsArrayClass) {
       return const SourceString('listTypeCheck');
     } else {
       if (Elements.isListSupertype(element, compiler)) {
@@ -1203,4 +1246,17 @@
   Element getGetRuntimeTypeInfo() {
     return compiler.findHelper(const SourceString('getRuntimeTypeInfo'));
   }
+
+  /**
+   * Remove [element] from the set of generated code, and put it back
+   * into the worklist.
+   *
+   * Invariant: [element] must be a declaration element.
+   */
+  void eagerRecompile(Element element) {
+    assert(invariant(element, element.isDeclaration));
+    generatedCode.remove(element);
+    generatedBailoutCode.remove(element);
+    compiler.enqueuer.codegen.addToWorkList(element);
+  }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index c25a335..f401235 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -714,10 +714,11 @@
         || member.isGenerativeConstructorBody()
         || member.isAccessor()) {
       if (member.isAbstract(compiler)) return;
-      js.Expression code = compiler.codegenWorld.generatedCode[member];
+      JavaScriptBackend backend = compiler.backend;
+      js.Expression code = backend.generatedCode[member];
       if (code == null) return;
       builder.addProperty(namer.getName(member), code);
-      code = compiler.codegenWorld.generatedBailoutCode[member];
+      code = backend.generatedBailoutCode[member];
       if (code != null) {
         builder.addProperty(namer.getBailoutName(member), code);
       }
@@ -1125,11 +1126,6 @@
     if (classElement.isNative()) {
       nativeEmitter.generateNativeClass(classElement);
       return;
-    } else {
-      // TODO(ngeoffray): Instead of switching between buffer, we
-      // should create code sections, and decide where to emit them at
-      // the end.
-      buffer = mainBuffer;
     }
 
     needsDefineClass = true;
@@ -1397,21 +1393,21 @@
   }
 
   void emitStaticFunctions(CodeBuffer buffer) {
+    JavaScriptBackend backend = compiler.backend;
     bool isStaticFunction(Element element) =>
         !element.isInstanceMember() && !element.isField();
 
     Iterable<Element> elements =
-        compiler.codegenWorld.generatedCode.keys.where(isStaticFunction);
+        backend.generatedCode.keys.where(isStaticFunction);
     Set<Element> pendingElementsWithBailouts =
-        compiler.codegenWorld.generatedBailoutCode.keys
+        backend.generatedBailoutCode.keys
             .where(isStaticFunction)
             .toSet();
 
     for (Element element in Elements.sortedByPosition(elements)) {
-      js.Expression code = compiler.codegenWorld.generatedCode[element];
+      js.Expression code = backend.generatedCode[element];
       emitStaticFunction(buffer, namer.getName(element), code);
-      js.Expression bailoutCode =
-          compiler.codegenWorld.generatedBailoutCode[element];
+      js.Expression bailoutCode = backend.generatedBailoutCode[element];
       if (bailoutCode != null) {
         pendingElementsWithBailouts.remove(element);
         emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
@@ -1421,8 +1417,7 @@
     // Is it possible the primary function was inlined but the bailout was not?
     for (Element element in
              Elements.sortedByPosition(pendingElementsWithBailouts)) {
-      js.Expression bailoutCode =
-          compiler.codegenWorld.generatedBailoutCode[element];
+      js.Expression bailoutCode = backend.generatedBailoutCode[element];
       emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
     }
   }
@@ -1665,8 +1660,17 @@
       }
     }
 
+    // Two selectors may match but differ only in type.  To avoid generating
+    // identical stubs for each we track untyped selectors which already have
+    // stubs.
+    Set<Selector> generatedSelectors = new Set<Selector>();
+
     for (Selector selector in selectors) {
       if (selector.applies(member, compiler)) {
+        selector = selector.asUntyped;
+        if (generatedSelectors.contains(selector)) continue;
+        generatedSelectors.add(selector);
+
         String invocationName = namer.invocationName(selector);
         Selector callSelector = new Selector.callClosureFrom(selector);
         String closureCallName = namer.invocationName(callSelector);
@@ -1719,11 +1723,12 @@
     ConstantHandler handler = compiler.constantHandler;
     List<VariableElement> lazyFields =
         handler.getLazilyInitializedFieldsForEmission();
+    JavaScriptBackend backend = compiler.backend;
     if (!lazyFields.isEmpty) {
       needsLazyInitializer = true;
       for (VariableElement element in Elements.sortedByPosition(lazyFields)) {
-        assert(compiler.codegenWorld.generatedBailoutCode[element] == null);
-        js.Expression code = compiler.codegenWorld.generatedCode[element];
+        assert(backend.generatedBailoutCode[element] == null);
+        js.Expression code = backend.generatedCode[element];
         assert(code != null);
         // The code only computes the initial value. We build the lazy-check
         // here:
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart
index bbe7368..98344a1 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart
@@ -23,8 +23,15 @@
   // counterpart it will never return the proposedName as the new fresh name.
   String getFreshName(String proposedName,
                       Set<String> usedNames,
+                      Map<String, String> suggestedNames,
                       {bool ensureSafe: true}) {
-    var freshName = _getUnusedName(proposedName, usedNames);
+    var freshName;
+    var suggestion = suggestedNames[proposedName];
+    if (suggestion != null && !usedNames.contains(suggestion)) {
+      freshName = suggestion;
+    } else {
+      freshName = _getUnusedName(proposedName, usedNames);
+    }
     usedNames.add(freshName);
     return freshName;
   }
@@ -37,16 +44,90 @@
   }
 
   void reserveBackendNames() {
-     // TODO(7554): We need a complete list from the DOM.
-    const reservedNativeProperties = const <String>["x", "y", "z"];
+    // From issue 7554.  These should not be used on objects (as instance
+    // variables) because they clash with names from the DOM.
+    const reservedNativeProperties = const <String>[
+        'Q', 'a', 'b', 'c', 'd', 'e', 'f', 'r', 'x', 'y', 'z',
+        // 2-letter:
+        'ch', 'cx', 'cy', 'db', 'dx', 'dy', 'fr', 'fx', 'fy', 'go', 'id', 'k1',
+        'k2', 'k3', 'k4', 'r1', 'r2', 'rx', 'ry', 'x1', 'x2', 'y1', 'y2',
+        // 3-letter:
+        'add', 'all', 'alt', 'arc', 'CCW', 'cmp', 'dir', 'end', 'get', 'in1',
+        'in2', 'INT', 'key', 'log', 'low', 'm11', 'm12', 'm13', 'm14', 'm21',
+        'm22', 'm23', 'm24', 'm31', 'm32', 'm33', 'm34', 'm41', 'm42', 'm43',
+        'm44', 'max', 'min', 'now', 'ONE', 'put', 'red', 'rel', 'rev', 'RGB',
+        'sdp', 'set', 'src', 'tag', 'top', 'uid', 'uri', 'url', 'URL',
+        // 4-letter:
+        'abbr', 'atob', 'Attr', 'axes', 'axis', 'back', 'BACK', 'beta', 'bias',
+        'Blob', 'blue', 'blur', 'BLUR', 'body', 'BOOL', 'BOTH', 'btoa', 'BYTE',
+        'cite', 'clip', 'code', 'cols', 'cues', 'data', 'DECR', 'DONE', 'face',
+        'file', 'File', 'fill', 'find', 'font', 'form', 'gain', 'hash', 'head',
+        'high', 'hint', 'host', 'href', 'HRTF', 'IDLE', 'INCR', 'info', 'INIT',
+        'isId', 'item', 'KEEP', 'kind', 'knee', 'lang', 'left', 'LESS', 'line',
+        'link', 'list', 'load', 'loop', 'mode', 'name', 'Node', 'None', 'NONE',
+        'only', 'open', 'OPEN', 'ping', 'play', 'port', 'rect', 'Rect', 'refX',
+        'refY', 'RGBA', 'root', 'rows', 'save', 'seed', 'seek', 'self', 'send',
+        'show', 'SINE', 'size', 'span', 'stat', 'step', 'stop', 'tags', 'text',
+        'Text', 'time', 'type', 'view', 'warn', 'wrap', 'ZERO'];
     for (var name in reservedNativeProperties) {
-      if (name.length < 3) {
+      if (name.length < 2) {
         instanceNameMap[name] = name;
       }
       usedInstanceNames.add(name);
     }
+
+    // This list of popular instance variable names generated with:
+    // cat out.js |
+    // perl -ne '$_=~s/(?<![^a-z0-9_\$]\$)\.([a-z0-9_\$]+)/print("$1\n")/gei' |
+    // sort | uniq -c | sort -nr | head -40
+    // Removed: html, call*, hasOwnProperty.
+    _populateSuggestedNames(
+        suggestedInstanceNames,
+        usedInstanceNames,
+        const <String>[
+            r'$add', r'add$1', r'box_0', r'charCodeAt$1', r'constructor',
+            r'current', r'$defineNativeClass', r'$eq', r'$ne',
+            r'getPrototypeOf', r'hasOwnProperty', r'$index', r'$indexSet',
+            r'$isJavaScriptIndexingBehavior', r'$isolateProperties',
+            r'iterator', r'length', r'$lt', r'$gt', r'$le', r'$ge',
+            r'moveNext$0', r'node', r'on', r'prototype', r'push', r'self',
+            r'start', r'target', r'this_0', r'value', r'width', r'style']);
+
+    _populateSuggestedNames(
+        suggestedGlobalNames,
+        usedGlobalNames,
+        const <String>[
+            r'Object', r'$throw', r'$eq', r'S', r'ioore', r'UnsupportedError$',
+            r'length', r'$sub', r'getInterceptor$JSStringJSArray', r'$add',
+            r'$gt', r'$ge', r'$lt', r'$le', r'add', r'getInterceptor$JSNumber',
+            r'iterator', r'$index', r'iae', r'getInterceptor$JSArray',
+            r'ArgumentError$', r'BoundClosure', r'StateError$',
+            r'getInterceptor', r'max', r'$mul', r'List_List', r'Map_Map',
+            r'getInterceptor$JSString', r'$div', r'$indexSet',
+            r'List_List$from', r'Set_Set$from', r'toString', r'toInt', r'min',
+            r'StringBuffer_StringBuffer', r'contains1', r'WhereIterable$',
+            r'RangeError$value', r'JSString', r'JSNumber',
+            r'JSArray'
+            ]);
   }
 
+  void _populateSuggestedNames(Map<String, String> suggestionMap,
+                               Set<String> used,
+                               List<String> suggestions) {
+    int c = $a - 1;
+    String letter;
+    for (String name in suggestions) {
+      do {
+        assert(c != $Z);
+        c = (c == $z) ? $A : c + 1;
+        letter = new String.fromCharCodes([c]);
+      } while (used.contains(letter));
+      assert(suggestionMap[name] == null);
+      suggestionMap[name] = letter;
+    }
+  }
+
+
   // This gets a minified name based on a hash of the proposed name.  This
   // is slightly less efficient than just getting the next name in a series,
   // but it means that small changes in the input program will give smallish
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index e424168..e5bb967 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -184,22 +184,17 @@
   final Map<Element, String> globals;
   final Map<Selector, String> oneShotInterceptorNames;
   final Map<String, LibraryElement> shortPrivateNameOwners;
+
   final Set<String> usedGlobalNames;
   final Set<String> usedInstanceNames;
   final Map<String, String> globalNameMap;
+  final Map<String, String> suggestedGlobalNames;
   final Map<String, String> instanceNameMap;
+  final Map<String, String> suggestedInstanceNames;
+      
   final Map<String, String> operatorNameMap;
   final Map<String, int> popularNameCounters;
 
-  /**
-   * A cache of names used for bailout methods. We make sure two
-   * bailout methods cannot have the same name because if the two
-   * bailout methods are in a class and a subclass, we would
-   * call the wrong bailout method at runtime. To make it
-   * simple, we don't keep track of inheritance and always avoid
-   * similar names.
-   */
-  final Set<String> usedBailoutInstanceNames;
   final Map<Element, String> bailoutNames;
 
   final Map<Constant, String> constantNames;
@@ -209,12 +204,13 @@
         oneShotInterceptorNames = new Map<Selector, String>(),
         shortPrivateNameOwners = new Map<String, LibraryElement>(),
         bailoutNames = new Map<Element, String>(),
-        usedBailoutInstanceNames = new Set<String>(),
         usedGlobalNames = new Set<String>(),
         usedInstanceNames = new Set<String>(),
         instanceNameMap = new Map<String, String>(),
         operatorNameMap = new Map<String, String>(),
         globalNameMap = new Map<String, String>(),
+        suggestedGlobalNames = new Map<String, String>(),
+        suggestedInstanceNames = new Map<String, String>(),
         constantNames = new Map<Constant, String>(),
         popularNameCounters = new Map<String, int>();
 
@@ -251,7 +247,8 @@
       } else {
         longName = "CONSTANT";
       }
-      result = getFreshName(longName, usedGlobalNames, ensureSafe: true);
+      result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames,
+                            ensureSafe: true);
       constantNames[constant] = result;
     }
     return result;
@@ -447,7 +444,8 @@
   String getMappedGlobalName(String proposedName) {
     var newName = globalNameMap[proposedName];
     if (newName == null) {
-      newName = getFreshName(proposedName, usedGlobalNames, ensureSafe: true);
+      newName = getFreshName(proposedName, usedGlobalNames,
+                             suggestedGlobalNames, ensureSafe: true);
       globalNameMap[proposedName] = newName;
     }
     return newName;
@@ -456,7 +454,8 @@
   String getMappedInstanceName(String proposedName) {
     var newName = instanceNameMap[proposedName];
     if (newName == null) {
-      newName = getFreshName(proposedName, usedInstanceNames, ensureSafe: true);
+      newName = getFreshName(proposedName, usedInstanceNames,
+                             suggestedInstanceNames, ensureSafe: true);
       instanceNameMap[proposedName] = newName;
     }
     return newName;
@@ -465,8 +464,8 @@
   String getMappedOperatorName(String proposedName) {
     var newName = operatorNameMap[proposedName];
     if (newName == null) {
-      newName = getFreshName(
-          proposedName, usedInstanceNames, ensureSafe: false);
+      newName = getFreshName(proposedName, usedInstanceNames,
+                             suggestedInstanceNames, ensureSafe: false);
       operatorNameMap[proposedName] = newName;
     }
     return newName;
@@ -474,6 +473,7 @@
 
   String getFreshName(String proposedName,
                       Set<String> usedNames,
+                      Map<String, String> suggestedNames,
                       {bool ensureSafe: true}) {
     var candidate;
     if (ensureSafe) {
@@ -537,11 +537,12 @@
       // need to go through the generic getInterceptorMethod.
       return getName(element);
     }
-    // This gets the minified name, but it doesn't really make much difference.
-    // The important thing is that it is a unique name.
-    StringBuffer buffer = new StringBuffer('${getName(element)}\$');
+    // Use the unminified names here to construct the interceptor names.  This
+    // helps ensure that they don't all suddenly change names due to a name
+    // clash in the minifier, which would affect the diff size.
+    StringBuffer buffer = new StringBuffer('${element.name.slowToString()}\$');
     for (ClassElement cls in classes) {
-      buffer.add(getName(cls));
+      buffer.add(cls.name.slowToString());
     }
     return getMappedGlobalName(buffer.toString());
   }
@@ -558,12 +559,21 @@
     if (global) {
       name = getMappedGlobalName(unminifiedName);
     } else {
-      name = unminifiedName;
-      int i = 0;
-      while (usedBailoutInstanceNames.contains(name)) {
-        name = '$unminifiedName${i++}';
+      // Make sure two bailout methods on the same inheritance chain do not have
+      // the same name to prevent a subclass bailout method being accidentally
+      // called from the superclass main method.  Use the count of the number of
+      // elements with the same name on the superclass chain to disambiguate
+      // based on 'level'.
+      int level = 0;
+      ClassElement classElement = element.getEnclosingClass().superclass;
+      while (classElement != null) {
+        if (classElement.localLookup(element.name) != null) level++;
+        classElement = classElement.superclass;
       }
-      usedBailoutInstanceNames.add(name);
+      name = unminifiedName;
+      if (level != 0) {
+        name = '$unminifiedName$level';
+      }
       name = getMappedInstanceName(name);
     }
     bailoutNames[element] = name;
@@ -625,7 +635,8 @@
         }
         String result = fixedName
             ? guess
-            : getFreshName(guess, usedGlobalNames, ensureSafe: true);
+            : getFreshName(guess, usedGlobalNames, suggestedGlobalNames,
+                           ensureSafe: true);
         globals[element] = result;
         return result;
       }
@@ -685,7 +696,8 @@
     String cached = oneShotInterceptorNames[selector];
     if (cached != null) return cached;
     SourceString name = operatorNameToIdentifier(selector.name);
-    String result = getFreshName(name.slowToString(), usedGlobalNames);
+    String result = getFreshName(name.slowToString(), usedGlobalNames,
+                                 suggestedGlobalNames);
     oneShotInterceptorNames[selector] = result;
     return result;
   }
diff --git a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
index 8d68c8d..09e31da 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
@@ -158,7 +158,7 @@
 
 
 // Patch for Stopwatch implementation.
-patch class _StopwatchImpl {
+patch class Stopwatch {
   patch static int _frequency() => 1000000;
   patch static int _now() => Primitives.numMicroseconds();
 }
diff --git a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
index 89c2a58..2ad4a1e 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
@@ -87,8 +87,11 @@
  * optimizations around the code.  This might be an extension of [JS] or a new
  * function similar to [JS] with additional arguments for the new information.
  */
+// Add additional optional arguments if needed. The method is treated internally
+// as a variable argument method.
 dynamic JS(String typeDescription, String codeTemplate,
-    [var arg0, var arg1, var arg2]) {}
+    [var arg0, var arg1, var arg2, var arg3, var arg4, var arg5, var arg6,
+     var arg7, var arg8, var arg9, var arg10, var arg11]) {}
 
 /**
  * Returns the isolate in which this code is running.
diff --git a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart b/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
index b133d12..6a32f17 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
@@ -5,7 +5,7 @@
 library _interceptors;
 
 import 'dart:collection';
-import 'dart:collection-dev';
+import 'dart:_collection-dev';
 import 'dart:_js_helper' show allMatchesInStringUnchecked,
                               Null,
                               JSSyntaxRegExp,
@@ -43,7 +43,7 @@
  * to emit a call to an intercepted method, that is a method that is
  * defined in an interceptor class.
  */
-getInterceptor() {
+getInterceptor(object) {
   // This is a magic method: the compiler does specialization of it
   // depending on the uses of intercepted methods and instantiated
   // primitive types.
@@ -86,5 +86,5 @@
   String toString() => 'null';
 
   int get hashCode => 0;
-  Type get runtimeType => createRuntimeType('Null');
+  Type get runtimeType => Null;
 }
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart b/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
index fad48f0..e33ae3f 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
@@ -65,6 +65,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(E element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   void addAll(Collection<E> collection) {
     for (E e in collection) {
       this.add(e);
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
index 2c80eaa..0fbff9c 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
@@ -13,6 +13,7 @@
                                    JS_HAS_EQUALS,
                                    RAW_DART_FUNCTION_REF,
                                    UNINTERCEPTED;
+import 'dart:_interceptors' show getInterceptor;
 
 part 'constant_map.dart';
 part 'native_helper.dart';
@@ -95,11 +96,19 @@
     return map;
   }
 
+  static final _objectInterceptor = getInterceptor(new Object());
   invokeOn(Object object) {
-    List arguments = _arguments;
-    if (!isJsArray(arguments)) arguments = new List.from(arguments);
-    return JS("var", "#[#].apply(#, #)",
-              object, _internalName, object, arguments);
+    var interceptor = getInterceptor(object);
+    var receiver = object;
+    var name = _internalName;
+    var arguments = _arguments;
+    if (identical(interceptor, _objectInterceptor)) {
+      if (!isJsArray(arguments)) arguments = new List.from(arguments);
+    } else {
+      arguments = [object]..addAll(arguments);
+      receiver = interceptor;
+    }
+    return JS("var", "#[#].apply(#, #)", receiver, name, receiver, arguments);
   }
 }
 
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
index 975c1a5..fa5677f 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
@@ -10,7 +10,7 @@
  * [:this:] to actually use the receiver of the method, which is
  * generated as an extra argument added to each member.
  */
-class JSNumber {
+class JSNumber implements num {
   const JSNumber();
 
   int compareTo(num b) {
@@ -254,7 +254,7 @@
   }
 }
 
-class JSInt extends JSNumber {
+class JSInt extends JSNumber implements int {
   const JSInt();
 
   bool get isEven => (this & 1) == 0;
@@ -266,7 +266,7 @@
   int operator ~() => JS('int', r'(~#) >>> 0', this);
 }
 
-class JSDouble extends JSNumber {
+class JSDouble extends JSNumber implements double {
   const JSDouble();
   Type get runtimeType => double;
 }
diff --git a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
index 860e706..c75e554 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
@@ -27,6 +27,7 @@
   if (name == 'JavaScriptAudioNode') return 'ScriptProcessorNode';
   if (name == 'Oscillator') return 'OscillatorNode';
   if (name == 'RealtimeAnalyserNode') return 'AnalyserNode';
+  if (name == 'IDBVersionChangeRequest') return 'IDBOpenDBRequest';
   return name;
 }
 
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
index ea9b593..13a15f8 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
@@ -12,10 +12,10 @@
 import '../../compiler.dart' as diagnostics;
 import '../elements/elements.dart';
 import '../resolution/resolution.dart' show ResolverTask, ResolverVisitor;
-import '../apiimpl.dart' as api;
+import '../apiimpl.dart' show Compiler;
 import '../scanner/scannerlib.dart' hide SourceString;
 import '../ssa/ssa.dart';
-import '../dart2jslib.dart';
+import '../dart2jslib.dart' hide Compiler;
 import '../dart_types.dart';
 import '../filenames.dart';
 import '../source_file.dart';
@@ -237,152 +237,20 @@
 }
 
 //------------------------------------------------------------------------------
-// Compiler extension for apidoc.
-//------------------------------------------------------------------------------
-
-/**
- * Extension of the compiler that enables the analysis of several libraries with
- * no particular entry point.
- */
-class LibraryCompiler extends api.Compiler {
-  LibraryCompiler(diagnostics.ReadStringFromUri provider,
-                  diagnostics.DiagnosticHandler handler,
-                  Uri libraryRoot, Uri packageRoot,
-                  List<String> options)
-      : super(provider, null, handler, libraryRoot, packageRoot, options) {
-    checker = new LibraryTypeCheckerTask(this);
-    resolver = new LibraryResolverTask(this);
-  }
-
-  // TODO(johnniwinther): The following methods are added to enable the analysis
-  // of a collection of libraries to be used for apidoc. Most of the methods
-  // are based on copies of existing methods and could probably be implemented
-  // such that the duplicate code is avoided. Not to affect the correctness and
-  // speed of dart2js as is, the redundancy is accepted temporarily.
-
-  /**
-   * Run the compiler on a list of libraries. No entry point is used.
-   */
-  bool runList(List<Uri> uriList) {
-    bool success = _runList(uriList);
-    for (final task in tasks) {
-      log('${task.name} took ${task.timing}msec');
-    }
-    return success;
-  }
-
-  bool _runList(List<Uri> uriList) {
-    try {
-      runCompilerList(uriList);
-    } on CompilerCancelledException catch (exception) {
-      log(exception.toString());
-      log('compilation failed');
-      return false;
-    }
-    tracer.close();
-    log('compilation succeeded');
-    return true;
-  }
-
-  void runCompilerList(List<Uri> uriList) {
-    scanBuiltinLibraries();
-    var elementList = <LibraryElement>[];
-    for (var uri in uriList) {
-      elementList.add(libraryLoader.loadLibrary(uri, null, uri));
-    }
-
-    world.populate();
-
-    log('Resolving...');
-    phase = Compiler.PHASE_RESOLVING;
-    backend.enqueueHelpers(enqueuer.resolution);
-    processQueueList(enqueuer.resolution, elementList);
-    log('Resolved ${enqueuer.resolution.resolvedElements.length} elements.');
-  }
-
-  void processQueueList(Enqueuer world, List<LibraryElement> elements) {
-    world.nativeEnqueuer.processNativeClasses(libraries.values);
-    for (var library in elements) {
-      fullyEnqueueLibrary(library);
-    }
-    progress.reset();
-    world.forEach((WorkItem work) {
-      withCurrentElement(work.element, () => work.run(this, world));
-    });
-  }
-
-  String codegen(WorkItem work, Enqueuer world) {
-    return null;
-  }
-}
-
-// TODO(johnniwinther): The source for the apidoc includes calls to methods on
-// for instance [MathPrimitives] which are not resolved by dart2js. Since we
-// do not need to analyse the body of functions to produce the documenation
-// we use a specialized resolver which bypasses method bodies.
-class LibraryResolverTask extends ResolverTask {
-  LibraryResolverTask(api.Compiler compiler) : super(compiler);
-
-  void visitBody(ResolverVisitor visitor, Statement body) {}
-}
-
-// TODO(johnniwinther): As a side-effect of bypassing method bodies in
-// [LibraryResolveTask] we can not perform the typecheck.
-class LibraryTypeCheckerTask extends TypeCheckerTask {
-  LibraryTypeCheckerTask(api.Compiler compiler) : super(compiler);
-
-  void check(Node tree, TreeElements elements) {}
-}
-
-//------------------------------------------------------------------------------
 // Compilation implementation
 //------------------------------------------------------------------------------
 
+// TODO(johnniwinther): Support client configurable handlers/providers.
 class Dart2JsCompilation implements Compilation {
-  bool isWindows = (Platform.operatingSystem == 'windows');
-  api.Compiler _compiler;
-  Uri cwd;
-  bool isAborting = false;
-  Map<String, SourceFile> sourceFiles;
-
-  Future<String> provider(Uri uri) {
-    if (uri.scheme != 'file') {
-      throw new ArgumentError(uri);
-    }
-    String source;
-    try {
-      source = readAll(uriPathToNative(uri.path));
-    } on FileIOException catch (ex) {
-      throw 'Error: Cannot read "${relativize(cwd, uri, isWindows)}" '
-            '(${ex.osError}).';
-    }
-    sourceFiles[uri.toString()] =
-      new SourceFile(relativize(cwd, uri, isWindows), source);
-    return new Future.immediate(source);
-  }
-
-  void handler(Uri uri, int begin, int end,
-               String message, diagnostics.Diagnostic kind) {
-    if (isAborting) return;
-    bool fatal =
-        kind == diagnostics.Diagnostic.CRASH ||
-        kind == diagnostics.Diagnostic.ERROR;
-    if (uri == null) {
-      if (!fatal) {
-        return;
-      }
-      print(message);
-      throw message;
-    } else if (fatal) {
-      SourceFile file = sourceFiles[uri.toString()];
-      print(file.getLocationMessage(message, begin, end, true, (s) => s));
-      throw message;
-    }
-  }
+  Compiler _compiler;
+  final Uri cwd;
+  final SourceFileProvider provider;
 
   Dart2JsCompilation(Path script, Path libraryRoot,
                      [Path packageRoot, List<String> opts = const <String>[]])
-      : cwd = getCurrentDirectory(), sourceFiles = <String, SourceFile>{} {
+      : cwd = getCurrentDirectory(),
+        provider = new SourceFileProvider() {
+    var handler = new FormattingDiagnosticHandler(provider);
     var libraryUri = cwd.resolve(libraryRoot.toString());
     var packageUri;
     if (packageRoot != null) {
@@ -390,8 +258,10 @@
     } else {
       packageUri = libraryUri;
     }
-    _compiler = new api.Compiler(provider, null, handler,
-        libraryUri, packageUri, opts);
+    _compiler = new Compiler(provider.readStringFromUri,
+                                 null,
+                                 handler.diagnosticHandler,
+                                 libraryUri, packageUri, opts);
     var scriptUri = cwd.resolve(script.toString());
     // TODO(johnniwinther): Detect file not found
     _compiler.run(scriptUri);
@@ -399,7 +269,8 @@
 
   Dart2JsCompilation.library(List<Path> libraries, Path libraryRoot,
                      [Path packageRoot, List<String> opts = const <String>[]])
-      : cwd = getCurrentDirectory(), sourceFiles = <String, SourceFile>{} {
+      : cwd = getCurrentDirectory(),
+        provider = new SourceFileProvider() {
     var libraryUri = cwd.resolve(libraryRoot.toString());
     var packageUri;
     if (packageRoot != null) {
@@ -407,15 +278,20 @@
     } else {
       packageUri = libraryUri;
     }
-    _compiler = new LibraryCompiler(provider, handler,
-        libraryUri, packageUri, opts);
+    opts = new List<String>.from(opts);
+    opts.add('--analyze-only');
+    opts.add('--analyze-all');
+    _compiler = new Compiler(provider.readStringFromUri,
+                                 null,
+                                 silentDiagnosticHandler,
+                                 libraryUri, packageUri, opts);
     var librariesUri = <Uri>[];
     for (Path library in libraries) {
       librariesUri.add(cwd.resolve(library.toString()));
       // TODO(johnniwinther): Detect file not found
     }
-    LibraryCompiler libraryCompiler = _compiler;
-    libraryCompiler.runList(librariesUri);
+    _compiler.librariesToAnalyzeWhenRun = librariesUri;
+    _compiler.run(null);
   }
 
   MirrorSystem get mirrors => new Dart2JsMirrorSystem(_compiler);
@@ -581,7 +457,7 @@
 //------------------------------------------------------------------------------
 
 class Dart2JsMirrorSystem implements MirrorSystem {
-  final api.Compiler compiler;
+  final Compiler compiler;
   Map<String, Dart2JsLibraryMirror> _libraries;
   Map<LibraryElement, Dart2JsLibraryMirror> _libraryMap;
 
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 5640670..373f16e 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -824,7 +824,7 @@
     // TODO(ngeoffray): For static methods, we could pass a method with a
     // defined arity.
     Element helper = builder.backend.getClosureConverter();
-    builder.pushInvokeHelper2(helper, local, arity);
+    builder.pushInvokeHelper2(helper, local, arity, HType.UNKNOWN);
     HInstruction closure = builder.pop();
     return closure;
   }
diff --git a/sdk/lib/_internal/compiler/implementation/patch_parser.dart b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
index 57dbd25..5a0da01 100644
--- a/sdk/lib/_internal/compiler/implementation/patch_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
@@ -118,6 +118,7 @@
 import "tree/tree.dart" as tree;
 import "dart2jslib.dart" as leg;  // CompilerTask, Compiler.
 import "apiimpl.dart";
+import "../compiler.dart" as api;
 import "scanner/scannerlib.dart";  // Scanner, Parsers, Listeners
 import "elements/elements.dart";
 import "elements/modelx.dart" show LibraryElementX, MetadataAnnotationX;
@@ -192,89 +193,14 @@
     }));
   }
 
-  void applyContainerPatch(ScopeContainerElement original,
+  void applyContainerPatch(ClassElement originClass,
                            Link<Element> patches) {
-    while (!patches.isEmpty) {
-      Element patchElement = patches.head;
-      Element originalElement = original.localLookup(patchElement.name);
-      if (patchElement.isAccessor() && originalElement != null) {
-        if (!identical(originalElement.kind, ElementKind.ABSTRACT_FIELD)) {
-          compiler.internalError(
-              "Cannot patch non-getter/setter with getter/setter",
-              element: originalElement);
-        }
-        AbstractFieldElement originalField = originalElement;
-        if (patchElement.isGetter()) {
-          originalElement = originalField.getter;
-        } else {
-          originalElement = originalField.setter;
-        }
-      }
-      if (originalElement == null) {
-        if (isPatchElement(patchElement)) {
-          compiler.internalError("Cannot patch non-existing member '"
-                        "${patchElement.name.slowToString()}'.");
-        }
-      } else {
-        patchMember(originalElement, patchElement);
-      }
-      patches = patches.tail;
-    }
-  }
+    for (Element patch in patches) {
+      if (!isPatchElement(patch)) continue;
 
-  bool isPatchElement(Element element) {
-    // TODO(lrn): More checks needed if we introduce metadata for real.
-    // In that case, it must have the identifier "native" as metadata.
-    for (Link link = element.metadata; !link.isEmpty; link = link.tail) {
-      if (link.head is PatchMetadataAnnotation) return true;
+      Element origin = originClass.localLookup(patch.name);
+      patchElement(compiler, origin, patch);
     }
-    return false;
-  }
-
-  void patchMember(Element originalElement, Element patchElement) {
-    // The original library has an element with the same name as the patch
-    // library element.
-    // In this case, the patch library element must be a function marked as
-    // "patch" and it must have the same signature as the function it patches.
-    if (!isPatchElement(patchElement)) {
-      compiler.internalError("Cannot overwrite existing '"
-                    "${originalElement.name.slowToString()}' with non-patch.");
-    }
-    if (originalElement is! FunctionElement) {
-      // TODO(lrn): Handle class declarations too.
-      compiler.internalError("Can only patch functions", element: originalElement);
-    }
-    FunctionElement original = originalElement;
-    if (!original.modifiers.isExternal()) {
-      compiler.internalError("Can only patch external functions.", element: original);
-    }
-    if (patchElement is! FunctionElement ||
-        !patchSignatureMatches(original, patchElement)) {
-      compiler.internalError("Can only patch functions with matching signatures",
-                    element: original);
-    }
-    applyFunctionPatch(original, patchElement);
-  }
-
-  bool patchSignatureMatches(FunctionElement original, FunctionElement patch) {
-    // TODO(lrn): Check that patches actually match the signature of
-    // the function it's patching.
-    return true;
-  }
-
-  void applyFunctionPatch(FunctionElement element,
-                          FunctionElement patchElement) {
-    if (element.isPatched) {
-      compiler.internalError("Trying to patch a function more than once.",
-                    element: element);
-    }
-    if (element.cachedNode != null) {
-      compiler.internalError("Trying to patch an already compiled function.",
-                    element: element);
-    }
-    // Don't just assign the patch field. This also updates the cachedNode.
-    element.setPatch(patchElement);
-    patchElement.origin = element;
   }
 }
 
@@ -370,7 +296,7 @@
                        this.imports)
     : super(listener, patchElement, idGenerator);
 
-  MetadataAnnotation popMetadata() {
+  MetadataAnnotation popMetadataHack() {
     // TODO(ahe): Remove this method.
     popNode(); // Discard null.
     return new PatchMetadataAnnotation();
@@ -404,59 +330,16 @@
     imports.addLast(tag);
   }
 
-  void pushElement(Element element) {
-    if (isMemberPatch || (isClassPatch && element is ClassElement)) {
+  void pushElement(Element patch) {
+    if (isMemberPatch || (isClassPatch && patch is ClassElement)) {
       // Apply patch.
-      element.addMetadata(popMetadata());
+      patch.addMetadata(popMetadataHack());
       LibraryElement originLibrary = compilationUnitElement.getLibrary();
       assert(originLibrary.isPatched);
-      Element existing = originLibrary.localLookup(element.name);
-      if (isMemberPatch) {
-        if (element is! FunctionElement) {
-          listener.internalErrorOnElement(element,
-                                          "Member patch is not a function.");
-        }
-        FunctionElement functionElement = element;
-        if (identical(existing.kind, ElementKind.ABSTRACT_FIELD)) {
-          if (!element.isAccessor()) {
-            listener.internalErrorOnElement(
-                functionElement, "Patching non-accessor with accessor");
-          }
-          AbstractFieldElement field = existing;
-          if (functionElement.isGetter()) {
-            existing = field.getter;
-          } else {
-            existing = field.setter;
-          }
-        }
-        if (existing is! FunctionElement) {
-          listener.internalErrorOnElement(functionElement,
-                                          "No corresponding method for patch.");
-        }
-        FunctionElement existingFunction = existing;
-        if (existingFunction.isPatched) {
-          listener.internalErrorOnElement(
-              functionElement, "Patching the same function more than once.");
-        }
-        existingFunction.patch = functionElement;
-        functionElement.origin = existingFunction;
-      } else {
-        assert(leg.invariant(element, element is ClassElement));
-        ClassElement classElement = element;
-        if (existing is! ClassElement) {
-          listener.internalErrorOnElement(
-              classElement, "Patching a non-class with a class patch.");
-        }
-        ClassElement existingClass = existing;
-        if (existingClass.isPatched) {
-          listener.internalErrorOnElement(
-              classElement, "Patching the same class more than once.");
-        }
-        existingClass.patch = classElement;
-        classElement.origin = existingClass;
-      }
+      Element origin = originLibrary.localLookup(patch.name);
+      patchElement(listener, origin, patch);
     }
-    super.pushElement(element);
+    super.pushElement(patch);
   }
 }
 
@@ -470,7 +353,7 @@
                       Element enclosingElement)
     : super(listener, enclosingElement);
 
-  MetadataAnnotation popMetadata() {
+  MetadataAnnotation popMetadataHack() {
     // TODO(ahe): Remove this method.
     popNode(); // Discard null.
     return new PatchMetadataAnnotation();
@@ -495,7 +378,7 @@
 
   void addMember(Element element) {
     if (isMemberPatch || (isClassPatch && element is ClassElement)) {
-      element.addMetadata(popMetadata());
+      element.addMetadata(popMetadataHack());
     }
     super.addMember(element);
   }
@@ -508,4 +391,206 @@
   PatchMetadataAnnotation() : super(STATE_DONE);
 
   Token get beginToken => null;
+  Token get endToken => null;
+}
+
+void patchElement(leg.DiagnosticListener listener,
+                   Element origin,
+                   Element patch) {
+  if (origin == null) {
+    listener.reportMessage(
+        listener.spanFromSpannable(patch),
+        leg.MessageKind.PATCH_NON_EXISTING.error({'name': patch.name}),
+        api.Diagnostic.ERROR);
+    return;
+  }
+  if (!(origin.isClass() ||
+        origin.isConstructor() ||
+        origin.isFunction() ||
+        origin.isAbstractField())) {
+    listener.reportMessage(
+        listener.spanFromSpannable(origin),
+        leg.MessageKind.PATCH_NONPATCHABLE.error(),
+        api.Diagnostic.ERROR);
+    return;
+  }
+  if (patch.isClass()) {
+    tryPatchClass(listener, origin, patch);
+  } else if (patch.isGetter()) {
+    tryPatchGetter(listener, origin, patch);
+  } else if (patch.isSetter()) {
+    tryPatchSetter(listener, origin, patch);
+  } else if (patch.isConstructor()) {
+    tryPatchConstructor(listener, origin, patch);
+  } else if(patch.isFunction()) {
+    tryPatchFunction(listener, origin, patch);
+  } else {
+    listener.reportMessage(
+        listener.spanFromSpannable(patch),
+        leg.MessageKind.PATCH_NONPATCHABLE.error(),
+        api.Diagnostic.ERROR);
+  }
+}
+
+void tryPatchClass(leg.DiagnosticListener listener,
+                    Element origin,
+                    ClassElement patch) {
+  if (!origin.isClass()) {
+    listener.reportMessage(
+        listener.spanFromSpannable(origin),
+        leg.MessageKind.PATCH_NON_CLASS.error({'className': patch.name}),
+        api.Diagnostic.ERROR);
+    listener.reportMessage(
+        listener.spanFromSpannable(patch),
+        leg.MessageKind.PATCH_POINT_TO_CLASS.error({'className': patch.name}),
+        api.Diagnostic.INFO);
+    return;
+  }
+  patchClass(listener, origin, patch);
+}
+
+void patchClass(leg.DiagnosticListener listener,
+                 ClassElement origin,
+                 ClassElement patch) {
+  if (origin.isPatched) {
+    listener.internalErrorOnElement(
+        origin, "Patching the same class more than once.");
+  }
+  // TODO(johnniwinther): Change to functions on the ElementX class.
+  origin.patch = patch;
+  patch.origin = origin;
+}
+
+void tryPatchGetter(leg.DiagnosticListener listener,
+                     Element origin,
+                     FunctionElement patch) {
+  if (!origin.isAbstractField()) {
+    listener.reportMessage(
+        listener.spanFromSpannable(origin),
+        leg.MessageKind.PATCH_NON_GETTER.error({'name': origin.name}),
+        api.Diagnostic.ERROR);
+    listener.reportMessage(
+        listener.spanFromSpannable(patch),
+        leg.MessageKind.PATCH_POINT_TO_GETTER.error({'getterName': patch.name}),
+        api.Diagnostic.INFO);
+    return;
+  }
+  AbstractFieldElement originField = origin;
+  if (originField.getter == null) {
+    listener.reportMessage(
+        listener.spanFromSpannable(origin),
+        leg.MessageKind.PATCH_NO_GETTER.error({'getterName': patch.name}),
+        api.Diagnostic.ERROR);
+    listener.reportMessage(
+        listener.spanFromSpannable(patch),
+        leg.MessageKind.PATCH_POINT_TO_GETTER.error({'getterName': patch.name}),
+        api.Diagnostic.INFO);
+    return;
+  }
+  patchFunction(listener, originField.getter, patch);
+}
+
+void tryPatchSetter(leg.DiagnosticListener listener,
+                     Element origin,
+                     FunctionElement patch) {
+  if (!origin.isAbstractField()) {
+    listener.reportMessage(
+        listener.spanFromSpannable(origin),
+        leg.MessageKind.PATCH_NON_SETTER.error({'name': origin.name}),
+        api.Diagnostic.ERROR);
+    listener.reportMessage(
+        listener.spanFromSpannable(patch),
+        leg.MessageKind.PATCH_POINT_TO_SETTER.error({'setterName': patch.name}),
+        api.Diagnostic.INFO);
+    return;
+  }
+  AbstractFieldElement originField = origin;
+  if (originField.setter == null) {
+    listener.reportMessage(
+        listener.spanFromSpannable(origin),
+        leg.MessageKind.PATCH_NO_SETTER.error({'setterName': patch.name}),
+        api.Diagnostic.ERROR);
+    listener.reportMessage(
+        listener.spanFromSpannable(patch),
+        leg.MessageKind.PATCH_POINT_TO_SETTER.error({'setterName': patch.name}),
+        api.Diagnostic.INFO);
+    return;
+  }
+  patchFunction(listener, originField.setter, patch);
+}
+
+void tryPatchConstructor(leg.DiagnosticListener listener,
+                          Element origin,
+                          FunctionElement patch) {
+  if (!origin.isConstructor()) {
+    listener.reportMessage(
+        listener.spanFromSpannable(origin),
+        leg.MessageKind.PATCH_NON_CONSTRUCTOR.error(
+            {'constructorName': patch.name}),
+        api.Diagnostic.ERROR);
+    listener.reportMessage(
+        listener.spanFromSpannable(patch),
+        leg.MessageKind.PATCH_POINT_TO_CONSTRUCTOR.error(
+            {'constructorName': patch.name}),
+        api.Diagnostic.INFO);
+    return;
+  }
+  patchFunction(listener, origin, patch);
+}
+
+void tryPatchFunction(leg.DiagnosticListener listener,
+                       Element origin,
+                       FunctionElement patch) {
+  if (!origin.isFunction()) {
+    listener.reportMessage(
+        listener.spanFromSpannable(origin),
+        leg.MessageKind.PATCH_NON_FUNCTION.error({'functionName': patch.name}),
+        api.Diagnostic.ERROR);
+    listener.reportMessage(
+        listener.spanFromSpannable(patch),
+        leg.MessageKind.PATCH_POINT_TO_FUNCTION.error(
+            {'functionName': patch.name}),
+        api.Diagnostic.INFO);
+    return;
+  }
+  patchFunction(listener, origin, patch);
+}
+
+void patchFunction(leg.DiagnosticListener listener,
+                    FunctionElement origin,
+                    FunctionElement patch) {
+  if (!origin.modifiers.isExternal()) {
+    listener.reportMessage(
+        listener.spanFromSpannable(origin),
+        leg.MessageKind.PATCH_NON_EXTERNAL.error(),
+        api.Diagnostic.ERROR);
+    listener.reportMessage(
+        listener.spanFromSpannable(patch),
+        leg.MessageKind.PATCH_POINT_TO_FUNCTION.error(
+            {'functionName': patch.name}),
+        api.Diagnostic.INFO);
+    return;
+  }
+  if (origin.isPatched) {
+    listener.internalErrorOnElement(origin,
+        "Trying to patch a function more than once.");
+  }
+  if (origin.cachedNode != null) {
+    listener.internalErrorOnElement(origin,
+        "Trying to patch an already compiled function.");
+  }
+  // Don't just assign the patch field. This also updates the cachedNode.
+  // TODO(johnniwinther): Change to functions on the ElementX class.
+  origin.setPatch(patch);
+  patch.origin = origin;
+}
+
+// TODO(johnniwinther): Add unittest when patch is (real) metadata.
+bool isPatchElement(Element element) {
+  // TODO(lrn): More checks needed if we introduce metadata for real.
+  // In that case, it must have the identifier "native" as metadata.
+  for (Link link = element.metadata; !link.isEmpty; link = link.tail) {
+    if (link.head is PatchMetadataAnnotation) return true;
+  }
+  return false;
 }
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index bc90813..e62aa70 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -99,7 +99,11 @@
         ClassElement cls = element;
         cls.ensureResolved(compiler);
         return null;
-      } else if (element.isTypedef() || element.isTypeVariable()) {
+      } else if (element.isTypedef()) {
+        TypedefElement typdef = element;
+        resolveTypedef(typdef);
+        return null;
+      } else if (element.isTypeVariable()) {
         element.computeType(compiler);
         return null;
       }
@@ -250,7 +254,7 @@
       return compiler.withCurrentElement(element, () {
         FunctionExpression tree = element.parseNode(compiler);
         if (tree.modifiers.isExternal()) {
-          error(tree, MessageKind.EXTERNAL_WITHOUT_IMPLEMENTATION);
+          error(tree, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
           return;
         }
         if (isConstructor) {
@@ -691,13 +695,16 @@
     if (value == null) return;
     if (!(isUserDefinableOperator(value) || identical(value, 'unary-'))) return;
 
+    bool isMinus = false;
     int requiredParameterCount;
     MessageKind messageKind;
     FunctionSignature signature = function.computeSignature(compiler);
     if (identical(value, 'unary-')) {
+      isMinus = true;
       messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY;
       requiredParameterCount = 0;
     } else if (isMinusOperator(value)) {
+      isMinus = true;
       messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY;
       requiredParameterCount = 1;
     } else if (isUnaryOperator(value)) {
@@ -713,17 +720,40 @@
       compiler.internalErrorOnElement(function,
           'Unexpected user defined operator $value');
     }
-    checkArity(function, requiredParameterCount, messageKind);
+    checkArity(function, requiredParameterCount, messageKind, isMinus);
   }
 
   void checkArity(FunctionElement function,
-                  int requiredParameterCount, MessageKind messageKind) {
+                  int requiredParameterCount, MessageKind messageKind,
+                  bool isMinus) {
     FunctionExpression node = function.parseNode(compiler);
     FunctionSignature signature = function.computeSignature(compiler);
     if (signature.requiredParameterCount != requiredParameterCount) {
       Node errorNode = node;
       if (node.parameters != null) {
-        if (signature.requiredParameterCount < requiredParameterCount) {
+        if (isMinus ||
+            signature.requiredParameterCount < requiredParameterCount) {
+          // If there are too few parameters, point to the whole parameter list.
+          // For instance
+          //
+          //     int operator +() {}
+          //                   ^^
+          //
+          //     int operator []=(value) {}
+          //                     ^^^^^^^
+          //
+          // For operator -, always point the whole parameter list, like
+          //
+          //     int operator -(a, b) {}
+          //                   ^^^^^^
+          //
+          // instead of
+          //
+          //     int operator -(a, b) {}
+          //                       ^
+          //
+          // since the correction might not be to remove 'b' but instead to
+          // remove 'a, b'.
           errorNode = node.parameters;
         } else {
           errorNode = node.parameters.nodes.skip(requiredParameterCount).head;
@@ -2593,6 +2623,7 @@
   }
 
   visitLiteralMap(LiteralMap node) {
+    world.registerInstantiatedClass(compiler.mapClass);
     node.visitChildren(this);
   }
 
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
index 9f99715..1e359aa 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
@@ -192,6 +192,6 @@
       popNode(); // Discard name.
     }
     popNode(); // Discard node (Send or Identifier).
-    pushMetadata(new PartialMetadataAnnotation(beginToken));
+    pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
index 289c2c8..e535f62 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
@@ -105,7 +105,7 @@
   void beginFormalParameter(Token token) {
   }
 
-  void endFormalParameter(Token token, Token thisKeyword) {
+  void endFormalParameter(Token thisKeyword) {
   }
 
   void handleNoFormalParameters(Token token) {
@@ -348,6 +348,9 @@
   void endRethrowStatement(Token throwToken, Token endToken) {
   }
 
+  void endTopLevelDeclaration(Token token) {
+  }
+
   void beginTopLevelMember(Token token) {
   }
 
@@ -682,7 +685,8 @@
 
   void endLibraryName(Token libraryKeyword, Token semicolon) {
     Expression name = popNode();
-    addLibraryTag(new LibraryName(libraryKeyword, name));
+    addLibraryTag(new LibraryName(libraryKeyword, name,
+                                  popMetadata(compilationUnitElement)));
   }
 
   void endImport(Token importKeyword, Token asKeyword, Token semicolon) {
@@ -692,13 +696,15 @@
       prefix = popNode();
     }
     StringNode uri = popLiteralString();
-    addLibraryTag(new Import(importKeyword, uri, prefix, combinators));
+    addLibraryTag(new Import(importKeyword, uri, prefix, combinators,
+                             popMetadata(compilationUnitElement)));
   }
 
   void endExport(Token exportKeyword, Token semicolon) {
     NodeList combinators = popNode();
     StringNode uri = popNode();
-    addLibraryTag(new Export(exportKeyword, uri, combinators));
+    addLibraryTag(new Export(exportKeyword, uri, combinators,
+                             popMetadata(compilationUnitElement)));
   }
 
   void endCombinators(int count) {
@@ -728,12 +734,14 @@
 
   void endPart(Token partKeyword, Token semicolon) {
     StringNode uri = popLiteralString();
-    addLibraryTag(new Part(partKeyword, uri));
+    addLibraryTag(new Part(partKeyword, uri,
+                           popMetadata(compilationUnitElement)));
   }
 
   void endPartOf(Token partKeyword, Token semicolon) {
     Expression name = popNode();
-    addPartOfTag(new PartOf(partKeyword, name));
+    addPartOfTag(new PartOf(partKeyword, name,
+                            popMetadata(compilationUnitElement)));
   }
 
   void addPartOfTag(PartOf tag) {
@@ -765,7 +773,15 @@
       popNode(); // Discard name.
     }
     popNode(); // Discard node (Send or Identifier).
-    pushMetadata(new PartialMetadataAnnotation(beginToken));
+    pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
+  }
+
+  void endTopLevelDeclaration(Token token) {
+    if (!metadata.isEmpty) {
+      recoverableError('Error: Metadata not supported here.',
+                       token: metadata.head.beginToken);
+      metadata = const Link<MetadataAnnotation>();
+    }
   }
 
   void endClassDeclaration(int interfacesCount, Token beginToken,
@@ -1050,11 +1066,17 @@
   }
 
   void pushElement(Element element) {
+    popMetadata(element);
+    compilationUnitElement.addMember(element, listener);
+  }
+
+  Link<MetadataAnnotation> popMetadata(Element element) {
+    var result = metadata;
     for (Link link = metadata; !link.isEmpty; link = link.tail) {
       element.addMetadata(link.head);
     }
     metadata = const Link<MetadataAnnotation>();
-    compilationUnitElement.addMember(element, listener);
+    return result;
   }
 
   void pushMetadata(MetadataAnnotation annotation) {
@@ -1252,9 +1274,9 @@
   }
 
   void endTopLevelFields(int count, Token beginToken, Token endToken) {
-    NodeList variables = makeNodeList(count, null, null, ",");
+    NodeList variables = makeNodeList(count, null, endToken, ",");
     Modifiers modifiers = popNode();
-    pushNode(new VariableDefinitions(null, modifiers, variables, endToken));
+    pushNode(new VariableDefinitions(null, modifiers, variables));
   }
 
   void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
@@ -1275,7 +1297,7 @@
                                            modifiers, compilationUnitElement));
   }
 
-  void endFormalParameter(Token token, Token thisKeyword) {
+  void endFormalParameter(Token thisKeyword) {
     Expression name = popNode();
     if (thisKeyword != null) {
       Identifier thisIdentifier = new Identifier(thisKeyword);
@@ -1287,8 +1309,8 @@
     }
     TypeAnnotation type = popNode();
     Modifiers modifiers = popNode();
-    pushNode(new VariableDefinitions(type, modifiers,
-                                     new NodeList.singleton(name), token));
+    pushNode(
+        new VariableDefinitions(type, modifiers, new NodeList.singleton(name)));
   }
 
   void endFormalParameters(int count, Token beginToken, Token endToken) {
@@ -1507,10 +1529,10 @@
   void endVariablesDeclaration(int count, Token endToken) {
     // TODO(ahe): Pick one name for this concept, either
     // VariablesDeclaration or VariableDefinitions.
-    NodeList variables = makeNodeList(count, null, null, ",");
+    NodeList variables = makeNodeList(count, null, endToken, ",");
     TypeAnnotation type = popNode();
     Modifiers modifiers = popNode();
-    pushNode(new VariableDefinitions(type, modifiers, variables, endToken));
+    pushNode(new VariableDefinitions(type, modifiers, variables));
   }
 
   void endInitializer(Token assignmentOperator) {
@@ -1617,10 +1639,10 @@
   }
 
   void endFields(int count, Token beginToken, Token endToken) {
-    NodeList variables = makeNodeList(count, null, null, ",");
+    NodeList variables = makeNodeList(count, null, endToken, ",");
     TypeAnnotation type = popNode();
     Modifiers modifiers = popNode();
-    pushNode(new VariableDefinitions(type, modifiers, variables, endToken));
+    pushNode(new VariableDefinitions(type, modifiers, variables));
   }
 
   void endMethod(Token getOrSet, Token beginToken, Token endToken) {
@@ -2008,10 +2030,19 @@
 /// A [MetadataAnnotation] which is constructed on demand.
 class PartialMetadataAnnotation extends MetadataAnnotationX {
   final Token beginToken;
+  final Token tokenAfterEndToken;
   Expression cachedNode;
   Constant value;
 
-  PartialMetadataAnnotation(this.beginToken);
+  PartialMetadataAnnotation(this.beginToken, this.tokenAfterEndToken);
+
+  Token get endToken {
+    Token token = beginToken;
+    while (token.kind != EOF_TOKEN) {
+      if (identical(token.next, tokenAfterEndToken)) return token;
+      token = token.next;
+    }
+  }
 
   Node parseNode(DiagnosticListener listener) {
     if (cachedNode != null) return cachedNode;
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
index ef0f417..5a85e00 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
@@ -38,6 +38,7 @@
     int count = 0;
     while (!identical(token.kind, EOF_TOKEN)) {
       token = parseTopLevelDeclaration(token);
+      listener.endTopLevelDeclaration(token);
       count++;
     }
     listener.endCompilationUnit(count, token);
@@ -363,7 +364,7 @@
       token = parseExpression(token.next);
       listener.handleValuedFormalParameter(equal, token);
     }
-    listener.endFormalParameter(token, thisKeyword);
+    listener.endFormalParameter(thisKeyword);
     return token;
   }
 
@@ -554,10 +555,26 @@
   /**
    * Returns true if the stringValue of the [token] is [value].
    */
-  bool optional(String value, Token token) => identical(value, token.stringValue);
+  bool optional(String value, Token token) {
+      return identical(value, token.stringValue);
+  }
+
+  /**
+   * Returns true if the stringValue of the [token] is either [value1],
+   * [value2], [value3], or [value4].
+   */
+  bool isOneOf4(Token token,
+                String value1, String value2, String value3, String value4) {
+    String stringValue = token.stringValue;
+    return identical(value1, stringValue) ||
+           identical(value2, stringValue) ||
+           identical(value3, stringValue) ||
+           identical(value4, stringValue);
+  }
 
   bool notEofOrValue(String value, Token token) {
-    return !identical(token.kind, EOF_TOKEN) && !identical(value, token.stringValue);
+    return !identical(token.kind, EOF_TOKEN) &&
+           !identical(value, token.stringValue);
   }
 
   Token parseType(Token token) {
@@ -1868,11 +1885,15 @@
   }
 
   Token parseVariablesDeclaration(Token token) {
-    token = parseVariablesDeclarationNoSemicolon(token);
-    return expectSemicolon(token);
+    return parseVariablesDeclarationMaybeSemicolon(token, true);
   }
 
   Token parseVariablesDeclarationNoSemicolon(Token token) {
+    return parseVariablesDeclarationMaybeSemicolon(token, false);
+  }
+
+  Token parseVariablesDeclarationMaybeSemicolon(Token token,
+                                                bool endWithSemicolon) {
     int count = 1;
     listener.beginVariablesDeclaration(token);
     token = parseModifiers(token);
@@ -1882,8 +1903,15 @@
       token = parseOptionallyInitializedIdentifier(token.next);
       ++count;
     }
-    listener.endVariablesDeclaration(count, token);
-    return token;
+    if (endWithSemicolon) {
+      Token semicolon = token;
+      token = expectSemicolon(semicolon);
+      listener.endVariablesDeclaration(count, semicolon);
+      return token;
+    } else {
+      listener.endVariablesDeclaration(count, null);
+      return token;
+    }
   }
 
   Token parseOptionallyInitializedIdentifier(Token token) {
@@ -1933,10 +1961,7 @@
     Token identifier = peekIdentifierAfterType(token);
     if (identifier != null) {
       assert(identifier.isIdentifier());
-      Token afterId = identifier.next;
-      int afterIdKind = afterId.kind;
-      if (identical(afterIdKind, EQ_TOKEN) || identical(afterIdKind, SEMICOLON_TOKEN) ||
-          identical(afterIdKind, COMMA_TOKEN) || optional('in', afterId)) {
+      if (isOneOf4(identifier.next, '=', ';', ',', 'in')) {
         return parseVariablesDeclarationNoSemicolon(token);
       }
     }
diff --git a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
index 1c27852..c100694 100644
--- a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
+++ b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
@@ -49,6 +49,10 @@
   }
 }
 
+void silentDiagnosticHandler(Uri uri, int begin, int end, String message,
+                             api.Diagnostic kind) {
+}
+
 class FormattingDiagnosticHandler {
   final SourceFileProvider provider;
   bool showWarnings = true;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
index ddf6bab..0e10ecf 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
@@ -112,9 +112,17 @@
     if (source != null) {
       DartType sourceType = source.computeType(compiler);
       DartType speculatedType = speculativeType.computeType(compiler);
-      if (speculatedType != null &&
-          !compiler.types.isAssignable(speculatedType, sourceType)) {
-        return false;
+      JavaScriptBackend backend = compiler.backend;
+      if (speculatedType != null) {
+        // Use the num type instead of JSNumber because JSNumber
+        // is not assignment compatible with int and double, but we
+        // still want to generate a type guard.
+        if (speculatedType.element == backend.jsNumberClass) {
+          speculatedType = compiler.numClass.computeType(compiler);
+        }
+        if (!compiler.types.isAssignable(speculatedType, sourceType)) {
+          return false;
+        }
       }
     }
 
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 5ae62cb..ac19fea 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -2399,7 +2399,7 @@
         // creating an [HStatic].
         push(new HStatic(element.declaration));
         if (element.isGetter()) {
-          push(new HInvokeStatic(<HInstruction>[pop()]));
+          push(new HInvokeStatic(<HInstruction>[pop()], HType.UNKNOWN));
         }
       }
     } else if (Elements.isInstanceSend(send, elements)) {
@@ -2455,7 +2455,9 @@
       if (element.isSetter()) {
         HStatic target = new HStatic(element);
         add(target);
-        addWithPosition(new HInvokeStatic(<HInstruction>[target, value]), send);
+        addWithPosition(
+            new HInvokeStatic(<HInstruction>[target, value], HType.UNKNOWN),
+            send);
       } else {
         value = potentiallyCheckType(value, element.computeType(compiler));
         addWithPosition(new HStaticStore(element, value), send);
@@ -2493,54 +2495,69 @@
     return interceptor;
   }
 
-  void pushInvokeHelper0(Element helper) {
+  void pushInvokeHelper0(Element helper, HType type) {
     HInstruction reference = new HStatic(helper);
     add(reference);
     List<HInstruction> inputs = <HInstruction>[reference];
-    HInstruction result = new HInvokeStatic(inputs);
+    HInstruction result = new HInvokeStatic(inputs, type);
     push(result);
   }
 
-  void pushInvokeHelper1(Element helper, HInstruction a0) {
+  void pushInvokeHelper1(Element helper, HInstruction a0, HType type) {
     HInstruction reference = new HStatic(helper);
     add(reference);
     List<HInstruction> inputs = <HInstruction>[reference, a0];
-    HInstruction result = new HInvokeStatic(inputs);
+    HInstruction result = new HInvokeStatic(inputs, type);
     push(result);
   }
 
-  void pushInvokeHelper2(Element helper, HInstruction a0, HInstruction a1) {
+  void pushInvokeHelper2(Element helper,
+                         HInstruction a0,
+                         HInstruction a1,
+                         HType type) {
     HInstruction reference = new HStatic(helper);
     add(reference);
     List<HInstruction> inputs = <HInstruction>[reference, a0, a1];
-    HInstruction result = new HInvokeStatic(inputs);
+    HInstruction result = new HInvokeStatic(inputs, type);
     push(result);
   }
 
-  void pushInvokeHelper3(Element helper, HInstruction a0, HInstruction a1,
-                         HInstruction a2) {
+  void pushInvokeHelper3(Element helper,
+                         HInstruction a0,
+                         HInstruction a1,
+                         HInstruction a2,
+                         HType type) {
     HInstruction reference = new HStatic(helper);
     add(reference);
     List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2];
-    HInstruction result = new HInvokeStatic(inputs);
+    HInstruction result = new HInvokeStatic(inputs, type);
     push(result);
   }
 
-  void pushInvokeHelper4(Element helper, HInstruction a0, HInstruction a1,
-                         HInstruction a2, HInstruction a3) {
+  void pushInvokeHelper4(Element helper,
+                         HInstruction a0,
+                         HInstruction a1,
+                         HInstruction a2,
+                         HInstruction a3,
+                         HType type) {
     HInstruction reference = new HStatic(helper);
     add(reference);
     List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2, a3];
-    HInstruction result = new HInvokeStatic(inputs);
+    HInstruction result = new HInvokeStatic(inputs, type);
     push(result);
   }
 
-  void pushInvokeHelper5(Element helper, HInstruction a0, HInstruction a1,
-                         HInstruction a2, HInstruction a3, HInstruction a4) {
+  void pushInvokeHelper5(Element helper,
+                         HInstruction a0,
+                         HInstruction a1,
+                         HInstruction a2,
+                         HInstruction a3,
+                         HInstruction a4,
+                         HType type) {
     HInstruction reference = new HStatic(helper);
     add(reference);
     List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2, a3, a4];
-    HInstruction result = new HInvokeStatic(inputs);
+    HInstruction result = new HInvokeStatic(inputs, type);
     push(result);
   }
 
@@ -2549,7 +2566,7 @@
   }
 
   HInstruction getRuntimeTypeInfo(HInstruction target) {
-    pushInvokeHelper1(backend.getGetRuntimeTypeInfo(), target);
+    pushInvokeHelper1(backend.getGetRuntimeTypeInfo(), target, HType.UNKNOWN);
     return pop();
   }
 
@@ -2662,7 +2679,7 @@
           // Create the call to isSubtype.
           List<HInstruction> inputs =
               <HInstruction>[isSubtype, typeArgument, representation];
-          HInstruction call = new HInvokeStatic(inputs);
+          HInstruction call = new HInvokeStatic(inputs, HType.BOOLEAN);
           add(call);
           checks.add(call);
           index++;
@@ -2906,7 +2923,7 @@
         compiler.cancel(
             'Isolate library and compiler mismatch', node: node);
       }
-      pushInvokeHelper0(element);
+      pushInvokeHelper0(element, HType.UNKNOWN);
     }
   }
 
@@ -2930,7 +2947,7 @@
       add(target);
       List<HInstruction> inputs = <HInstruction>[target];
       addGenericSendArgumentsToList(link, inputs);
-      push(new HInvokeStatic(inputs));
+      push(new HInvokeStatic(inputs, HType.UNKNOWN));
     }
   }
 
@@ -3067,7 +3084,8 @@
                       graph.addConstant(internalNameConstant),
                       graph.addConstant(kindConstant),
                       argumentsInstruction,
-                      argumentNamesInstruction);
+                      argumentNamesInstruction,
+                      HType.UNKNOWN);
 
     var inputs = <HInstruction>[
         target,
@@ -3153,7 +3171,8 @@
         // The type variable is stored in [this].
         if (typeInfo == null) {
           pushInvokeHelper1(backend.getGetRuntimeTypeInfo(),
-                            localsHandler.readThis());
+                            localsHandler.readThis(),
+                            HType.UNKNOWN);
           typeInfo = pop();
         }
         int index = RuntimeTypeInformation.getTypeVariableIndex(type);
@@ -3204,7 +3223,7 @@
     HInstruction typeInfoSetter = new HStatic(typeInfoSetterElement);
     add(typeInfoSetter);
     add(new HInvokeStatic(
-        <HInstruction>[typeInfoSetter, newObject, typeInfo]));
+        <HInstruction>[typeInfoSetter, newObject, typeInfo], HType.UNKNOWN));
   }
 
   /**
@@ -3334,7 +3353,7 @@
         return;
       }
 
-      HInvokeStatic instruction = new HInvokeStatic(inputs);
+      HInvokeStatic instruction = new HInvokeStatic(inputs, HType.UNKNOWN);
       // TODO(ngeoffray): Only do this if knowing the return type is
       // useful.
       HType returnType =
@@ -3395,7 +3414,7 @@
 
   void generateError(Node node, String message, Element helper) {
     HInstruction errorMessage = addConstantString(node, message);
-    pushInvokeHelper1(helper, errorMessage);
+    pushInvokeHelper1(helper, errorMessage, HType.UNKNOWN);
   }
 
   void generateRuntimeError(Node node, String message) {
@@ -3446,7 +3465,8 @@
     } else {
       existingNamesList = graph.addConstantNull(constantSystem);
     }
-    pushInvokeHelper4(helper, receiver, name, arguments, existingNamesList);
+    pushInvokeHelper4(
+        helper, receiver, name, arguments, existingNamesList, HType.UNKNOWN);
   }
 
   /**
@@ -3473,7 +3493,7 @@
     HInstruction typeString = addConstantString(node, type.toString());
     HInstruction reasonsString = addConstantString(node, reasons);
     Element helper = backend.getThrowMalformedSubtypeError();
-    pushInvokeHelper3(helper, value, typeString, reasonsString);
+    pushInvokeHelper3(helper, value, typeString, reasonsString, HType.UNKNOWN);
   }
 
   visitNewExpression(NewExpression node) {
@@ -4000,7 +4020,10 @@
     }
     HLiteralList keyValuePairs = new HLiteralList(inputs);
     add(keyValuePairs);
-    pushInvokeHelper1(backend.getMapMaker(), keyValuePairs);
+    pushInvokeHelper1(backend.getMapMaker(), keyValuePairs,
+        new HType.fromBoundedType(compiler.mapClass.computeType(compiler),
+                                  compiler,
+                                  false));
   }
 
   visitLiteralMapEntry(LiteralMapEntry node) {
@@ -4161,7 +4184,7 @@
       localsHandler = new LocalsHandler.from(savedLocals);
       visit(switchCase.statements);
       if (!isAborted() && caseIterator.hasNext) {
-        pushInvokeHelper0(getFallThroughErrorElement);
+        pushInvokeHelper0(getFallThroughErrorElement, HType.UNKNOWN);
         HInstruction error = pop();
         close(new HThrow(error));
       }
@@ -4278,7 +4301,7 @@
         compiler.reportWarning(node, 'Missing break at end of switch case');
         Element element =
             compiler.findHelper(const SourceString("getFallThroughError"));
-        pushInvokeHelper0(element);
+        pushInvokeHelper0(element, HType.UNKNOWN);
         HInstruction error = pop();
         close(new HThrow(error));
       }
@@ -4415,7 +4438,8 @@
       HInstruction oldRethrowableException = rethrowableException;
       rethrowableException = exception;
 
-      pushInvokeHelper1(backend.getExceptionUnwrapper(), exception);
+      pushInvokeHelper1(
+          backend.getExceptionUnwrapper(), exception, HType.UNKNOWN);
       HInvokeStatic unwrappedException = pop();
       tryInstruction.exception = exception;
       Link<Node> link = node.catchBlocks.nodes;
@@ -4462,7 +4486,8 @@
         }
         Node trace = catchBlock.trace;
         if (trace != null) {
-          pushInvokeHelper1(backend.getTraceFromException(), exception);
+          pushInvokeHelper1(
+              backend.getTraceFromException(), exception, HType.UNKNOWN);
           HInstruction traceInstruction = pop();
           localsHandler.updateLocal(elements[trace], traceInstruction);
         }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 8164118..e5caac1 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -100,7 +100,6 @@
       codegen.visitGraph(graph);
 
       js.Block body = new js.Block(<js.Statement>[]);
-      if (codegen.setup != null) body.statements.add(codegen.setup);
       body.statements.add(codegen.body);
       js.Fun fun =
           buildJavaScriptFunction(work.element, codegen.newParameters, body);
@@ -196,11 +195,8 @@
    */
   final Set<String> declaredLocals;
 
-  Element equalsNullElement;
-  Element boolifiedEqualsNullElement;
   int indent = 0;
   HGraph currentGraph;
-  HBasicBlock currentBlock;
 
   // Records a block-information that is being handled specially.
   // Used to break bad recursion.
@@ -1114,7 +1110,6 @@
     // Abort traversal if we are leaving the currently active sub-graph.
     if (!subGraph.contains(node)) return;
 
-    currentBlock = node;
     // If this node has block-structure based information attached,
     // try using that to traverse from here.
     if (node.blockFlow != null && handleBlockFlow(node.blockFlow)) {
@@ -1329,8 +1324,9 @@
   }
 
   visitGoto(HGoto node) {
-    assert(currentBlock.successors.length == 1);
-    List<HBasicBlock> dominated = currentBlock.dominatedBlocks;
+    HBasicBlock block = node.block;
+    assert(block.successors.length == 1);
+    List<HBasicBlock> dominated = block.dominatedBlocks;
     // With the exception of the entry-node which dominates its successor
     // and the exit node, no block finishing with a 'goto' can have more than
     // one dominated block (since it has only one successor).
@@ -1341,11 +1337,11 @@
       compiler.internalError('dominated.length = ${dominated.length}',
                              instruction: node);
     }
-    if (dominated.length == 2 && !identical(currentBlock, currentGraph.entry)) {
-      compiler.internalError('currentBlock !== currentGraph.entry',
+    if (dominated.length == 2 && block != currentGraph.entry) {
+      compiler.internalError('node.block != currentGraph.entry',
                              instruction: node);
     }
-    assert(dominated[0] == currentBlock.successors[0]);
+    assert(dominated[0] == block.successors[0]);
     visitBasicBlock(dominated[0]);
   }
 
@@ -1374,7 +1370,7 @@
   }
 
   visitBreak(HBreak node) {
-    assert(currentBlock.successors.length == 1);
+    assert(node.block.successors.length == 1);
     if (node.label != null) {
       LabelElement label = node.label;
       if (!tryCallAction(breakAction, label)) {
@@ -1389,7 +1385,7 @@
   }
 
   visitContinue(HContinue node) {
-    assert(currentBlock.successors.length == 1);
+    assert(node.block.successors.length == 1);
     if (node.label != null) {
       LabelElement label = node.label;
       if (!tryCallAction(continueAction, label)) {
@@ -1519,18 +1515,20 @@
       // seen selectors.
       if (target.isGenerativeConstructorBody()) {
         methodName = name.slowToString();
-      } else if (target == backend.jsArrayAdd) {
-        methodName = 'push';
-      } else if (target == backend.jsArrayRemoveLast) {
-        methodName = 'pop';
-      } else if (target == backend.jsStringSplit) {
-        methodName = 'split';
-        // Split returns a List, so we make sure the backend knows the
-        // list class is instantiated.
-        world.registerInstantiatedClass(compiler.listClass);
-      } else if (target == backend.jsStringConcat) {
-        push(new js.Binary('+', object, arguments[0]), node);
-        return;
+      } else if (!node.isInterceptorCall) {
+        if (target == backend.jsArrayAdd) {
+          methodName = 'push';
+        } else if (target == backend.jsArrayRemoveLast) {
+          methodName = 'pop';
+        } else if (target == backend.jsStringSplit) {
+          methodName = 'split';
+          // Split returns a List, so we make sure the backend knows the
+          // list class is instantiated.
+          world.registerInstantiatedClass(compiler.listClass);
+        } else if (target == backend.jsStringConcat) {
+          push(new js.Binary('+', object, arguments[0]), node);
+          return;
+        }
       }
     }
 
@@ -1560,17 +1558,14 @@
 
   Selector getOptimizedSelectorFor(HInvokeDynamic node,
                                    Selector defaultSelector) {
-    // TODO(4434): For private members we need to use the untyped selector.
-    if (defaultSelector.name.isPrivate()) return defaultSelector;
-    // TODO(ngeoffray): Type intercepted calls.
-    if (node.isInterceptorCall) return defaultSelector;
     // If [JSInvocationMirror.invokeOn] has been called, we must not create a
     // typed selector based on the receiver type.
     if (node.element == null && // Invocation is not exact.
         backend.compiler.enabledInvokeOn) {
       return defaultSelector;
     }
-    HType receiverHType = types[node.inputs[0]];
+    int receiverIndex = node.isInterceptorCall ? 1 : 0;
+    HType receiverHType = types[node.inputs[receiverIndex]];
     DartType receiverType = receiverHType.computeType(compiler);
     if (receiverType != null &&
         !identical(receiverType.kind, TypeKind.MALFORMED_TYPE)) {
@@ -1617,7 +1612,7 @@
     if (target != null) {
       // If we know we're calling a specific method, register that
       // method only.
-      world.registerDynamicInvocationOf(target);
+      world.registerDynamicInvocationOf(target, selector);
     } else {
       SourceString name = node.selector.name;
       world.registerDynamicInvocation(name, selector);
@@ -2425,10 +2420,10 @@
       world.registerIsCheck(type);
 
       if (node.isArgumentTypeCheck) {
-        if (element == compiler.intClass) {
+        if (element == backend.jsIntClass) {
           checkInt(node.checkedInput, '!==');
         } else {
-          assert(element == compiler.numClass);
+          assert(element == backend.jsNumberClass);
           checkNum(node.checkedInput, '!==');
         }
         js.Expression test = pop();
@@ -2635,7 +2630,6 @@
 
 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator {
 
-  js.Statement setup;
   js.Switch currentBailoutSwitch;
   final List<js.Switch> oldBailoutSwitches;
   final List<js.Parameter> newParameters;
@@ -2941,7 +2935,7 @@
         new js.Binary('===', generateStateUse(), new js.LiteralNumber('0'));
     js.Expression condition = new js.Binary('&&', stateEquals0, pop());
     // TODO(ngeoffray): Put the condition initialization in the
-    // [setup] buffer.
+    // arguments?
     List<HBailoutTarget> targets = node.thenBlock.bailoutTargets;
     for (int i = 0, len = targets.length; i < len; i++) {
       js.VariableUse stateRef = generateStateUse();
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 21b3d71..afbd2e1 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -1441,8 +1441,8 @@
 
 class HInvokeStatic extends HInvoke {
   /** The first input must be the target. */
-  HInvokeStatic(inputs, [HType knownType = HType.UNKNOWN]) : super(inputs) {
-    guaranteedType = knownType;
+  HInvokeStatic(inputs, HType type) : super(inputs) {
+    guaranteedType = type;
   }
 
   toString() => 'invoke static: ${element.name}';
@@ -1454,7 +1454,7 @@
 
 class HInvokeSuper extends HInvokeStatic {
   final bool isSetter;
-  HInvokeSuper(inputs, {this.isSetter: false}) : super(inputs);
+  HInvokeSuper(inputs, {this.isSetter: false}) : super(inputs, HType.UNKNOWN);
   toString() => 'invoke super: ${element.name}';
   accept(HVisitor visitor) => visitor.visitInvokeSuper(this);
 
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index c51395f..35ba2cb 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -145,15 +145,8 @@
     while (instruction != null) {
       HInstruction next = instruction.next;
       HInstruction replacement = instruction.accept(this);
-      if (!identical(replacement, instruction)) {
-        if (!replacement.isInBasicBlock()) {
-          // The constant folding can return an instruction that is already
-          // part of the graph (like an input), so we only add the replacement
-          // if necessary.
-          block.addAfter(instruction, replacement);
-        }
+      if (replacement != instruction) {
         block.rewrite(instruction, replacement);
-        block.remove(instruction);
 
         // If we can replace [instruction] with [replacement], then
         // [replacement]'s type can be narrowed.
@@ -169,6 +162,16 @@
         if (replacement.sourcePosition == null) {
           replacement.sourcePosition = instruction.sourcePosition;
         }
+        if (!replacement.isInBasicBlock()) {
+          // The constant folding can return an instruction that is already
+          // part of the graph (like an input), so we only add the replacement
+          // if necessary.
+          block.addAfter(instruction, replacement);
+          // Visit the replacement as the next instruction in case it
+          // can also be constant folded away.
+          next = replacement;
+        }
+        block.remove(instruction);
       }
       instruction = next;
     }
@@ -182,10 +185,10 @@
     List<HInstruction> inputs = node.inputs;
     assert(inputs.length == 1);
     HInstruction input = inputs[0];
-    if (input.isBoolean(types)) return input;
+    HType type = types[input];
+    if (type.isBoolean()) return input;
     // All values !== true are boolified to false.
-    DartType type = types[input].computeType(compiler);
-    if (type != null && !identical(type.element, compiler.boolClass)) {
+    if (!type.isBooleanOrNull() && !type.isUnknown()) {
       return graph.addConstantBool(false, constantSystem);
     }
     return node;
@@ -220,15 +223,43 @@
     return null;
   }
 
+  HInstruction optimizeLengthInterceptedGetter(HInvokeDynamic node) {
+    HInstruction actualReceiver = node.inputs[1];
+    if (actualReceiver.isIndexablePrimitive(types)) {
+      if (actualReceiver.isConstantString()) {
+        HConstant constantInput = actualReceiver;
+        StringConstant constant = constantInput.constant;
+        return graph.addConstantInt(constant.length, constantSystem);
+      } else if (actualReceiver.isConstantList()) {
+        HConstant constantInput = actualReceiver;
+        ListConstant constant = constantInput.constant;
+        return graph.addConstantInt(constant.length, constantSystem);
+      }
+      Element element;
+      bool isAssignable;
+      if (actualReceiver.isString(types)) {
+        element = backend.jsStringLength;
+        isAssignable = false;
+      } else {
+        element = backend.jsArrayLength;
+        isAssignable = !actualReceiver.isFixedArray(types);
+      }
+      HFieldGet result = new HFieldGet(
+          element, actualReceiver, isAssignable: isAssignable);
+      result.guaranteedType = HType.INTEGER;
+      types[result] = HType.INTEGER;
+      return result;
+    } else if (actualReceiver.isConstantMap()) {
+      HConstant constantInput = actualReceiver;
+      MapConstant constant = constantInput.constant;
+      return graph.addConstantInt(constant.length, constantSystem);
+    }
+    return node;
+  }
+
   HInstruction handleInterceptorCall(HInvokeDynamic node) {
     // We only optimize for intercepted method calls in this method.
-    if (node.selector.isGetter() || node.selector.isSetter()) return node;
-
-    HInstruction input = node.inputs[1];
-    if (input.isString(types)
-        && node.selector.name == const SourceString('toString')) {
-      return node.inputs[1];
-    }
+    Selector selector = node.selector;
 
     // Try constant folding the instruction.
     Operation operation = node.specializer.operation(constantSystem);
@@ -245,8 +276,16 @@
     if (instruction != null) return instruction;
 
     // Check if this call does not need to be intercepted.
+    HInstruction input = node.inputs[1];
     HType type = types[input];
     var interceptor = node.inputs[0];
+
+    if (interceptor.isConstant() && selector.isCall()) {
+      DartType type = types[interceptor].computeType(compiler);
+      ClassElement cls = type.element;
+      node.element = cls.lookupSelector(selector);
+    }
+
     if (interceptor is !HThis && !type.canBePrimitive()) {
       // If the type can be null, and the intercepted method can be in
       // the object class, keep the interceptor.
@@ -260,42 +299,62 @@
         }
         if (interceptedClasses.contains(compiler.objectClass)) return node;
       }
-      // Change the call to a regular invoke dynamic call.
-      return new HInvokeDynamicMethod(
-          node.selector, node.inputs.getRange(1, node.inputs.length - 1));
+      if (selector.isGetter()) {
+        // Change the call to a regular invoke dynamic call.
+        return new HInvokeDynamicGetter(selector, null, input, false);
+      } else if (selector.isSetter()) {
+        return new HInvokeDynamicSetter(
+            selector, null, input, node.inputs[2], false);
+      } else {
+        // Change the call to a regular invoke dynamic call.
+        return new HInvokeDynamicMethod(
+            selector, node.inputs.getRange(1, node.inputs.length - 1));
+      }
     }
 
-    Selector selector = node.selector;
-    SourceString selectorName = selector.name;
-    Element target;
-    if (input.isExtendableArray(types)) {
-      if (selectorName == backend.jsArrayRemoveLast.name
-          && selector.argumentCount == 0) {
-        target = backend.jsArrayRemoveLast;
-      } else if (selectorName == backend.jsArrayAdd.name
-                 && selector.argumentCount == 1
-                 && selector.namedArgumentCount == 0
-                 && !compiler.enableTypeAssertions) {
-        target = backend.jsArrayAdd;
+    if (selector.isCall()) {
+      Element target;
+      if (input.isExtendableArray(types)) {
+        if (selector.applies(backend.jsArrayRemoveLast, compiler)) {
+          target = backend.jsArrayRemoveLast;
+        } else if (selector.applies(backend.jsArrayAdd, compiler)) {
+          // The codegen special cases array calls, but does not
+          // inline argument type checks.
+          if (!compiler.enableTypeAssertions) {
+            target = backend.jsArrayAdd;
+          }
+        }
+      } else if (input.isString(types)) {
+        if (selector.applies(backend.jsStringSplit, compiler)) {
+          if (node.inputs[2].isString(types)) {
+            target = backend.jsStringSplit;
+          }
+        } else if (selector.applies(backend.jsStringConcat, compiler)) {
+          if (node.inputs[2].isString(types)) {
+            target = backend.jsStringConcat;
+          }
+        } else if (selector.applies(backend.jsStringToString, compiler)) {
+          return input;
+        }
       }
-    } else if (input.isString(types)) {
-      if (selectorName == backend.jsStringSplit.name
-          && selector.argumentCount == 1
-          && selector.namedArgumentCount == 0
-          && node.inputs[2].isString(types)) {
-        target = backend.jsStringSplit;
-      } else if (selectorName == backend.jsStringConcat.name
-                 && selector.argumentCount == 1
-                 && selector.namedArgumentCount == 0
-                 && node.inputs[2].isString(types)) {
-        target = backend.jsStringConcat;
+      if (target != null) {
+        // TODO(ngeoffray): There is a strong dependency between codegen
+        // and this optimization that the dynamic invoke does not need an
+        // interceptor. We currently need to keep a
+        // HInvokeDynamicMethod and not create a HForeign because
+        // HForeign is too opaque for the SssaCheckInserter (that adds a
+        // bounds check on removeLast). Once we start inlining, the
+        // bounds check will become explicit, so we won't need this
+        // optimization.
+        HInvokeDynamicMethod result = new HInvokeDynamicMethod(
+            node.selector, node.inputs.getRange(1, node.inputs.length - 1));
+        result.element = target;
+        return result;
       }
-    }
-    if (target != null) {
-      HInvokeDynamicMethod result = new HInvokeDynamicMethod(
-          node.selector, node.inputs.getRange(1, node.inputs.length - 1));
-      result.element = target;
-      return result;
+    } else if (selector.isGetter()) {
+      if (selector.applies(backend.jsArrayLength, compiler)) {
+        return optimizeLengthInterceptedGetter(node);
+      }
     }
     return node;
   }
@@ -345,29 +404,6 @@
     return node;
   }
 
-  /**
-   * Turns a primitive instruction (e.g. [HIndex], [HAdd], ...) into a
-   * [HInvokeDynamic] because we know the receiver is not a JS
-   * primitive object.
-   */
-  HInstruction fromPrimitiveInstructionToDynamicInvocation(HInstruction node,
-                                                           Selector selector) {
-    HBoundedType type = types[node.inputs[1]];
-    HInvokeDynamicMethod result = new HInvokeDynamicMethod(
-        selector,
-        node.inputs.getRange(1, node.inputs.length - 1));
-    if (type.isExact()) {
-      HBoundedType concrete = type;
-      // TODO(johnniwinther): Add lookup by selector to HBoundedType.
-      Element element = concrete.lookupMember(selector.name);
-      if (selector.applies(element, compiler)) {
-        // The target is only valid if the selector applies.
-        result.element = element;
-      }
-    }
-    return result;
-  }
-
   HInstruction visitIntegerCheck(HIntegerCheck node) {
     HInstruction value = node.value;
     if (value.isInteger(types)) return value;
@@ -584,45 +620,8 @@
     return node;
   }
 
-  HInstruction optimizeLengthInterceptedCall(HInvokeDynamicGetter node) {
-    HInstruction actualReceiver = node.inputs[1];
-    if (actualReceiver.isIndexablePrimitive(types)) {
-      if (actualReceiver.isConstantString()) {
-        HConstant constantInput = actualReceiver;
-        StringConstant constant = constantInput.constant;
-        return graph.addConstantInt(constant.length, constantSystem);
-      } else if (actualReceiver.isConstantList()) {
-        HConstant constantInput = actualReceiver;
-        ListConstant constant = constantInput.constant;
-        return graph.addConstantInt(constant.length, constantSystem);
-      }
-      Element element;
-      bool isAssignable;
-      if (actualReceiver.isString(types)) {
-        element = backend.jsStringLength;
-        isAssignable = false;
-      } else {
-        element = backend.jsArrayLength;
-        isAssignable = !actualReceiver.isFixedArray(types);
-      }
-      HFieldGet result = new HFieldGet(
-          element, actualReceiver, isAssignable: isAssignable);
-      result.guaranteedType = HType.INTEGER;
-      types[result] = HType.INTEGER;
-      return result;
-    } else if (actualReceiver.isConstantMap()) {
-      HConstant constantInput = actualReceiver;
-      MapConstant constant = constantInput.constant;
-      return graph.addConstantInt(constant.length, constantSystem);
-    }
-    return node;
-  }
-
   HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
-    if (node.selector.name == const SourceString('length')
-        && node.isInterceptorCall) {
-      return optimizeLengthInterceptedCall(node);
-    }
+    if (node.isInterceptorCall) return handleInterceptorCall(node);
 
     Element field =
         findConcreteFieldForDynamicAccess(node.receiver, node.selector);
@@ -647,6 +646,8 @@
   }
 
   HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
+    if (node.isInterceptorCall) return handleInterceptorCall(node);
+
     Element field =
         findConcreteFieldForDynamicAccess(node.receiver, node.selector);
     if (field == null || !field.isAssignable()) return node;
@@ -700,7 +701,7 @@
     } else if (type.isArray()) {
       constantInterceptor = backend.jsArrayClass;
     } else if (type.isNull()) {
-      constantInterceptor = backend.jsIntClass;
+      constantInterceptor = backend.jsNullClass;
     } else if (type.isNumber()) {
       // If the method being intercepted is not defined in [int] or
       // [double] we can safely use the number interceptor.
@@ -826,6 +827,7 @@
 
   void visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
     Element element = node.element;
+    if (node.isInterceptorCall) return;
     if (element != backend.jsArrayRemoveLast) return;
     if (boundsChecked.contains(node)) return;
     insertBoundsCheck(
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index 06e432e..b6d4746 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -173,7 +173,8 @@
   String toString() => 'null';
 
   DartType computeType(Compiler compiler) {
-    return compiler.nullClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsNullClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -211,7 +212,8 @@
   bool isBooleanOrNull() => true;
 
   DartType computeType(Compiler compiler) {
-    return compiler.boolClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsBoolClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -243,7 +245,8 @@
   String toString() => "boolean";
 
   DartType computeType(Compiler compiler) {
-    return compiler.boolClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsBoolClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -270,7 +273,8 @@
   String toString() => "number or null";
 
   DartType computeType(Compiler compiler) {
-    return compiler.numClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsNumberClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -306,7 +310,8 @@
   String toString() => "number";
 
   DartType computeType(Compiler compiler) {
-    return compiler.numClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsNumberClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -335,7 +340,8 @@
   String toString() => "integer or null";
 
   DartType computeType(Compiler compiler) {
-    return compiler.intClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsIntClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -373,7 +379,8 @@
   String toString() => "integer";
 
   DartType computeType(Compiler compiler) {
-    return compiler.intClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsIntClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -406,7 +413,8 @@
   String toString() => "double or null";
 
   DartType computeType(Compiler compiler) {
-    return compiler.doubleClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsDoubleClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -444,7 +452,8 @@
   String toString() => "double";
 
   DartType computeType(Compiler compiler) {
-    return compiler.doubleClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsDoubleClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -512,7 +521,8 @@
   String toString() => "String or null";
 
   DartType computeType(Compiler compiler) {
-    return compiler.stringClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsStringClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -562,7 +572,8 @@
   String toString() => "String";
 
   DartType computeType(Compiler compiler) {
-    return compiler.stringClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsStringClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
@@ -594,7 +605,8 @@
   String toString() => "readable array";
 
   DartType computeType(Compiler compiler) {
-    return compiler.listClass.computeType(compiler);
+    JavaScriptBackend backend = compiler.backend;
+    return backend.jsArrayClass.computeType(compiler);
   }
 
   HType union(HType other, Compiler compiler) {
diff --git a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
index 9875b25..1b3b455 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
@@ -1069,12 +1069,10 @@
 }
 
 class VariableDefinitions extends Statement {
-  final Token endToken;
   final TypeAnnotation type;
   final Modifiers modifiers;
   final NodeList definitions;
-  VariableDefinitions(this.type, this.modifiers, this.definitions,
-                      this.endToken) {
+  VariableDefinitions(this.type, this.modifiers, this.definitions) {
     assert(modifiers != null);
   }
 
@@ -1095,7 +1093,7 @@
     return token;
   }
 
-  Token getEndToken() => endToken;
+  Token getEndToken() => definitions.getEndToken();
 }
 
 abstract class Loop extends Statement {
@@ -1703,11 +1701,11 @@
         token.next = prefixToken.next;
         prefixNode = new Identifier(token);
       }
-      return new Import(tag.token, argument, prefixNode, null);
+      return new Import(tag.token, argument, prefixNode, null, null);
     } else if (isLibrary()) {
-      return new LibraryName(tag.token, argument);
+      return new LibraryName(tag.token, argument, null);
     } else if (isSource()) {
-      return new Part(tag.token, argument);
+      return new Part(tag.token, argument, null);
     } else {
       throw 'Unknown script tag ${tag.token.slowToString()}';
     }
@@ -1715,6 +1713,10 @@
 }
 
 abstract class LibraryTag extends Node {
+  final Link<MetadataAnnotation> metadata;
+
+  LibraryTag(this.metadata);
+
   bool get isLibraryName => false;
   bool get isImport => false;
   bool get isExport => false;
@@ -1727,7 +1729,10 @@
 
   final Token libraryKeyword;
 
-  LibraryName(this.libraryKeyword, this.name);
+  LibraryName(this.libraryKeyword,
+              this.name,
+              Link<MetadataAnnotation> metadata)
+    : super(metadata);
 
   bool get isLibraryName => true;
 
@@ -1751,7 +1756,10 @@
   final StringNode uri;
   final NodeList combinators;
 
-  LibraryDependency(this.uri, this.combinators);
+  LibraryDependency(this.uri,
+                    this.combinators,
+                    Link<MetadataAnnotation> metadata)
+    : super(metadata);
 }
 
 /**
@@ -1766,8 +1774,9 @@
   final Token importKeyword;
 
   Import(this.importKeyword, StringNode uri,
-         this.prefix, NodeList combinators)
-      : super(uri, combinators);
+         this.prefix, NodeList combinators,
+         Link<MetadataAnnotation> metadata)
+      : super(uri, combinators, metadata);
 
   bool get isImport => true;
 
@@ -1802,8 +1811,11 @@
 class Export extends LibraryDependency {
   final Token exportKeyword;
 
-  Export(this.exportKeyword, StringNode uri, NodeList combinators)
-      : super(uri, combinators);
+  Export(this.exportKeyword,
+         StringNode uri,
+         NodeList combinators,
+         Link<MetadataAnnotation> metadata)
+      : super(uri, combinators, metadata);
 
   bool get isExport => true;
 
@@ -1829,7 +1841,8 @@
 
   final Token partKeyword;
 
-  Part(this.partKeyword, this.uri);
+  Part(this.partKeyword, this.uri, Link<MetadataAnnotation> metadata)
+    : super(metadata);
 
   bool get isPart => true;
 
@@ -1849,7 +1862,9 @@
 
   final Token partKeyword;
 
-  PartOf(this.partKeyword, this.name);
+  final Link<MetadataAnnotation> metadata;
+
+  PartOf(this.partKeyword, this.name, this.metadata);
 
   Token get ofKeyword => partKeyword.next;
 
diff --git a/sdk/lib/_internal/compiler/implementation/tree/tree.dart b/sdk/lib/_internal/compiler/implementation/tree/tree.dart
index 316b153..3faa36c 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/tree.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/tree.dart
@@ -13,6 +13,8 @@
 
 import '../resolution/secret_tree_element.dart' show TreeElementMixin;
 
+import '../elements/elements.dart' show MetadataAnnotation;
+
 part 'dartstring.dart';
 part 'nodes.dart';
 part 'prettyprint.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
index eee95d4..9c20f2d 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
@@ -123,7 +123,7 @@
     add(node.forToken.value);
     sb.add('(');
     visit(node.initializer);
-    if (node.initializer is !Statement) sb.add(';');
+    sb.add(';');
     visit(node.conditionStatement);
     visit(node.update);
     sb.add(')');
@@ -366,9 +366,6 @@
       sb.add(' ');
     }
     visit(node.definitions);
-    if (node.endToken.value == const SourceString(';')) {
-      add(node.endToken.value);
-    }
   }
 
   visitDoWhile(DoWhile node) {
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index ed5ac45..01fa607 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -258,6 +258,8 @@
     return types.dynamicType;
   }
 
+  // TODO(johnniwinther): Provide the element from which the type came in order
+  // to give better error messages.
   void analyzeArguments(Send send, DartType type) {
     Link<Node> arguments = send.arguments;
     if (type == null || identical(type, types.dynamicType)) {
@@ -268,17 +270,50 @@
     } else {
       FunctionType funType = type;
       Link<DartType> parameterTypes = funType.parameterTypes;
-      while (!arguments.isEmpty && !parameterTypes.isEmpty) {
-        checkAssignable(arguments.head, parameterTypes.head,
-                        analyze(arguments.head));
+      Link<DartType> optionalParameterTypes = funType.optionalParameterTypes;
+      while (!arguments.isEmpty) {
+        Node argument = arguments.head;
+        NamedArgument namedArgument = argument.asNamedArgument();
+        if (namedArgument != null) {
+          argument = namedArgument.expression;
+          SourceString argumentName = namedArgument.name.source;
+          DartType namedParameterType =
+              funType.getNamedParameterType(argumentName);
+          if (namedParameterType == null) {
+            // TODO(johnniwinther): Provide better information on the called
+            // function.
+            reportTypeWarning(argument, MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+                {'argumentName': argumentName});
+
+            analyze(argument);
+          } else {
+            checkAssignable(argument, namedParameterType, analyze(argument));
+          }
+        } else {
+          if (parameterTypes.isEmpty) {
+            if (optionalParameterTypes.isEmpty) {
+              // TODO(johnniwinther): Provide better information on the
+              // called function.
+              reportTypeWarning(argument, MessageKind.ADDITIONAL_ARGUMENT);
+
+              analyze(argument);
+            } else {
+              checkAssignable(argument, optionalParameterTypes.head,
+                              analyze(argument));
+              optionalParameterTypes = optionalParameterTypes.tail;
+            }
+          } else {
+            checkAssignable(argument, parameterTypes.head, analyze(argument));
+            parameterTypes = parameterTypes.tail;
+          }
+        }
         arguments = arguments.tail;
-        parameterTypes = parameterTypes.tail;
       }
-      if (!arguments.isEmpty) {
-        reportTypeWarning(arguments.head, MessageKind.ADDITIONAL_ARGUMENT);
-      } else if (!parameterTypes.isEmpty) {
+      if (!parameterTypes.isEmpty) {
+        // TODO(johnniwinther): Provide better information on the called
+        // function.
         reportTypeWarning(send, MessageKind.MISSING_ARGUMENT,
-                          {'argumentType': parameterTypes.head});
+            {'argumentType': parameterTypes.head});
       }
     }
   }
diff --git a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
index f55ad50..23bc782 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
@@ -67,7 +67,7 @@
       Element member = node.membersByName[selector.name];
       // Since we're running through the entire tree we have to use
       // the applies method that takes types into account.
-      if (member != null && selector.applies(member, compiler)) {
+      if (member != null && selector.appliesUnnamed(member, compiler)) {
         result.add(member);
       }
       return true;
@@ -95,7 +95,7 @@
       Element member = node.membersByName[selector.name];
       // Since we're running through the entire tree we have to use
       // the applies method that takes types into account.
-      if (member != null && selector.applies(member, compiler)) {
+      if (member != null && selector.appliesUnnamed(member, compiler)) {
         result = true;
         // End the traversal.
         return false;
diff --git a/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart b/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
index f4a416d..cf98a10 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
@@ -90,7 +90,7 @@
         Selector selector = existing.selector;
         // Since we're running through the entire tree we have to use
         // the applies method that takes types into account.
-        if (selector.applies(member, compiler)) {
+        if (selector.appliesUnnamed(member, compiler)) {
           if (!visit(selector, existing.value)) return false;
         }
       }
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index 34954ec..6b64382 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -35,6 +35,18 @@
   final Map<SourceString, Set<Selector>> invokedNames;
   final Map<SourceString, Set<Selector>> invokedGetters;
   final Map<SourceString, Set<Selector>> invokedSetters;
+
+  /**
+   * Fields accessed. Currently only the codegen knows this
+   * information. The resolver is too conservative when seeing a
+   * getter and only registers an invoked getter.
+   */
+  final Map<SourceString, Set<Selector>> fieldGetters;
+
+  /**
+   * Fields set. See comment in [fieldGetters].
+   */
+  final Map<SourceString, Set<Selector>> fieldSetters;
   final Set<DartType> isChecks;
 
   Universe() : instantiatedClasses = new Set<ClassElement>(),
@@ -42,6 +54,8 @@
                staticFunctionsNeedingGetter = new Set<FunctionElement>(),
                invokedNames = new Map<SourceString, Set<Selector>>(),
                invokedGetters = new Map<SourceString, Set<Selector>>(),
+               fieldGetters = new Map<SourceString, Set<Selector>>(),
+               fieldSetters = new Map<SourceString, Set<Selector>>(),
                invokedSetters = new Map<SourceString, Set<Selector>>(),
                isChecks = new Set<DartType>();
 
@@ -50,7 +64,7 @@
                            Compiler compiler) {
     if (selectors == null) return false;
     for (Selector selector in selectors) {
-      if (selector.applies(member, compiler)) return true;
+      if (selector.appliesUnnamed(member, compiler)) return true;
     }
     return false;
   }
@@ -66,46 +80,6 @@
   bool hasInvokedSetter(Element member, Compiler compiler) {
     return hasMatchingSelector(invokedSetters[member.name], member, compiler);
   }
-}
-
-/// [Universe] which is specific to resolution.
-class ResolutionUniverse extends Universe {
-}
-
-/// [Universe] which is specific to code generation.
-class CodegenUniverse extends Universe {
-  /**
-   * Documentation wanted -- johnniwinther
-   *
-   * Invariant: Key elements are declaration elements.
-   */
-  Map<Element, js.Expression> generatedCode;
-
-  /**
-   * Documentation wanted -- johnniwinther
-   *
-   * Invariant: Key elements are declaration elements.
-   */
-  Map<Element, js.Expression> generatedBailoutCode;
-
-  final Map<SourceString, Set<Selector>> fieldGetters;
-  final Map<SourceString, Set<Selector>> fieldSetters;
-
-  CodegenUniverse()
-      : generatedCode = new Map<Element, js.Expression>(),
-        generatedBailoutCode = new Map<Element, js.Expression>(),
-        fieldGetters = new Map<SourceString, Set<Selector>>(),
-        fieldSetters = new Map<SourceString, Set<Selector>>();
-
-  void addGeneratedCode(CodegenWorkItem work, js.Expression code) {
-    assert(invariant(work.element, work.element.isDeclaration));
-    generatedCode[work.element] = code;
-  }
-
-  void addBailoutCode(CodegenWorkItem work, js.Expression code) {
-    assert(invariant(work.element, work.element.isDeclaration));
-    generatedBailoutCode[work.element] = code;
-  }
 
   bool hasFieldGetter(Element member, Compiler compiler) {
     return hasMatchingSelector(fieldGetters[member.name], member, compiler);
@@ -236,6 +210,8 @@
   int get positionalArgumentCount => argumentCount - namedArgumentCount;
   DartType get receiverType => null;
 
+  Selector get asUntyped => this;
+
   /**
    * The member name for invocation mirrors created from this selector.
    */
@@ -255,10 +231,13 @@
     return kind;
   }
 
-  bool applies(Element element, Compiler compiler)
-      => appliesUntyped(element, compiler);
+  bool appliesUnnamed(Element element, Compiler compiler) {
+    assert(sameNameHack(element, compiler));
+    return appliesUntyped(element, compiler);
+  }
 
   bool appliesUntyped(Element element, Compiler compiler) {
+    assert(sameNameHack(element, compiler));
     if (Elements.isUnresolved(element)) return false;
     if (name.isPrivate() && library != element.getLibrary()) return false;
     if (element.isForeign(compiler)) return true;
@@ -301,7 +280,27 @@
     }
   }
 
+  bool sameNameHack(Element element, Compiler compiler) {
+    // TODO(ngeoffray): Remove workaround checks.
+    return element == compiler.assertMethod
+        || element.isConstructor()
+        || name == element.name;
+  }
+
+  bool applies(Element element, Compiler compiler) {
+    if (!sameNameHack(element, compiler)) return false;
+    return appliesUnnamed(element, compiler);
+  }
+
   /**
+   * Fills [list] with the arguments in a defined order.
+   *
+   * [compileArgument] is a function that returns a compiled version
+   * of an argument located in [arguments].
+   *
+   * [compileConstant] is a function that returns a compiled constant
+   * of an optional argument that is not in [arguments.
+   *
    * Returns [:true:] if the selector and the [element] match; [:false:]
    * otherwise.
    *
@@ -415,14 +414,18 @@
    */
   final DartType receiverType;
 
+  final Selector asUntyped;
+
   TypedSelector(DartType this.receiverType, Selector selector)
-    : super(selector.kind,
-            selector.name,
-            selector.library,
-            selector.argumentCount,
-            selector.namedArguments) {
+      : asUntyped = selector.asUntyped,
+        super(selector.kind,
+              selector.name,
+              selector.library,
+              selector.argumentCount,
+              selector.namedArguments) {
     // Invariant: Typed selector can not be based on a malformed type.
     assert(!identical(receiverType.kind, TypeKind.MALFORMED_TYPE));
+    assert(asUntyped.receiverType == null);
   }
 
   /**
@@ -430,12 +433,14 @@
    * invoked on an instance of [cls].
    */
   bool hasElementIn(ClassElement cls, Element element) {
-    Element resolved = cls.lookupMember(element.name);
-    if (identical(resolved, element)) return true;
+    // Use the selector for the lookup instead of [:element.name:]
+    // because the selector has the right privacy information.
+    Element resolved = cls.lookupSelector(this);
+    if (resolved == element) return true;
     if (resolved == null) return false;
-    if (identical(resolved.kind, ElementKind.ABSTRACT_FIELD)) {
+    if (resolved.isAbstractField()) {
       AbstractFieldElement field = resolved;
-      if (identical(element, field.getter) || identical(element, field.setter)) {
+      if (element == field.getter || element == field.setter) {
         return true;
       } else {
         ClassElement otherCls = field.getEnclosingClass();
@@ -447,7 +452,8 @@
     return false;
   }
 
-  bool applies(Element element, Compiler compiler) {
+  bool appliesUnnamed(Element element, Compiler compiler) {
+    assert(sameNameHack(element, compiler));
     // [TypedSelector] are only used when compiling.
     assert(compiler.phase == Compiler.PHASE_COMPILING);
     if (!element.isMember()) return false;
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index 343ad14..56f3698 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -24,6 +24,8 @@
       'missing argument of type #{argumentType}');
   static const ADDITIONAL_ARGUMENT = const MessageKind(
       'additional argument');
+  static const NAMED_ARGUMENT_NOT_FOUND = const MessageKind(
+      "no named argument '#{argumentName}' found on method");
   static const METHOD_NOT_FOUND = const MessageKind(
       'no method named #{methodName} in class #{className}');
   static const MEMBER_NOT_STATIC = const MessageKind(
@@ -360,31 +362,6 @@
 File: #{fileName}
 Length: #{length}''');
 
-  static const PATCH_RETURN_TYPE_MISMATCH = const MessageKind(
-      "Patch return type '#{patchReturnType}' doesn't match "
-      "'#{originReturnType}' on origin method '#{methodName}'.");
-
-  static const PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH = const MessageKind(
-      "Required parameter count of patch method (#{patchParameterCount}) "
-      "doesn't match parameter count on origin method '#{methodName}' "
-      "(#{originParameterCount}).");
-
-  static const PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH = const MessageKind(
-      "Optional parameter count of patch method (#{patchParameterCount}) "
-      "doesn't match parameter count on origin method '#{methodName}' "
-      "(#{originParameterCount}).");
-
-  static const PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH = const MessageKind(
-      "Optional parameters of origin and patch method '#{methodName}' must "
-      "both be either named or positional.");
-
-  static const PATCH_PARAMETER_MISMATCH = const MessageKind(
-      "Patch method parameter '#{patchParameter}' doesn't match "
-      "'#{originParameter}' on origin method #{methodName}.");
-
-  static const EXTERNAL_WITHOUT_IMPLEMENTATION = const MessageKind(
-      "External method without an implementation.");
-
   static const TOP_LEVEL_VARIABLE_DECLARED_STATIC = const MessageKind(
       "Top-level variable cannot be declared static.");
 
@@ -424,6 +401,87 @@
   below as well as the source location above).
 ''');
 
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Patch errors start.
+  //////////////////////////////////////////////////////////////////////////////
+
+  static const PATCH_RETURN_TYPE_MISMATCH = const MessageKind(
+      "Patch return type '#{patchReturnType}' doesn't match "
+      "'#{originReturnType}' on origin method '#{methodName}'.");
+
+  static const PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH = const MessageKind(
+      "Required parameter count of patch method (#{patchParameterCount}) "
+      "doesn't match parameter count on origin method '#{methodName}' "
+      "(#{originParameterCount}).");
+
+  static const PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH = const MessageKind(
+      "Optional parameter count of patch method (#{patchParameterCount}) "
+      "doesn't match parameter count on origin method '#{methodName}' "
+      "(#{originParameterCount}).");
+
+  static const PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH = const MessageKind(
+      "Optional parameters of origin and patch method '#{methodName}' must "
+      "both be either named or positional.");
+
+  static const PATCH_PARAMETER_MISMATCH = const MessageKind(
+      "Patch method parameter '#{patchParameter}' doesn't match "
+      "'#{originParameter}' on origin method #{methodName}.");
+
+  static const PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION = const MessageKind(
+      "External method without an implementation.");
+
+  static const PATCH_POINT_TO_FUNCTION = const MessageKind(
+      "Info: This is the function patch '#{functionName}'.");
+
+  static const PATCH_POINT_TO_CLASS = const MessageKind(
+      "Info: This is the class patch '#{className}'.");
+
+  static const PATCH_POINT_TO_GETTER = const MessageKind(
+      "Info: This is the getter patch '#{getterName}'.");
+
+  static const PATCH_POINT_TO_SETTER = const MessageKind(
+      "Info: This is the setter patch '#{setterName}'.");
+
+  static const PATCH_POINT_TO_CONSTRUCTOR = const MessageKind(
+      "Info: This is the constructor patch '#{constructorName}'.");
+
+  static const PATCH_NON_EXISTING = const MessageKind(
+      "Error: Origin does not exist for patch '#{name}'.");
+
+  static const PATCH_NONPATCHABLE = const MessageKind(
+      "Error: Only classes and functions can be patched.");
+
+  static const PATCH_NON_EXTERNAL = const MessageKind(
+      "Error: Only external functions can be patched.");
+
+  static const PATCH_NON_CLASS = const MessageKind(
+      "Error: Patching non-class with class patch '#{className}'.");
+
+  static const PATCH_NON_GETTER = const MessageKind(
+      "Error: Cannot patch non-getter '#{name}' with getter patch.");
+
+  static const PATCH_NO_GETTER = const MessageKind(
+      "Error: No getter found for getter patch '#{getterName}'.");
+
+  static const PATCH_NON_SETTER = const MessageKind(
+      "Error: Cannot patch non-setter '#{name}' with setter patch.");
+
+  static const PATCH_NO_SETTER = const MessageKind(
+      "Error: No setter found for setter patch '#{setterName}'.");
+
+  static const PATCH_NON_CONSTRUCTOR = const MessageKind(
+      "Error: Cannot patch non-constructor with constructor patch "
+      "'#{constructorName}'.");
+
+  static const PATCH_NON_FUNCTION = const MessageKind(
+      "Error: Cannot patch non-function with function patch "
+      "'#{functionName}'.");
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Patch errors end.
+  //////////////////////////////////////////////////////////////////////////////
+
   toString() => template;
 
   Message message([Map arguments = const {}]) {
diff --git a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
index 2520489..e9882ff 100644
--- a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
+++ b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
@@ -1465,9 +1465,6 @@
     }
   }
 
-  DocComment createDocComment(String text, [ClassMirror inheritedFrom]) =>
-      new DocComment(text, inheritedFrom);
-
   /** Get the doc comment associated with the given library. */
   DocComment getLibraryComment(LibraryMirror library) => getComment(library);
 
@@ -1511,7 +1508,7 @@
       }
     }
     if (comment == null) return null;
-    return createDocComment(comment, inheritedFrom);
+    return new DocComment(comment, inheritedFrom);
   }
 
   /**
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart b/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart
index 194bc5f..a5b04d6 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart
@@ -20,8 +20,8 @@
   setup();
 
   // Request the navigation data so we can build the HTML for it.
-  new HttpRequest.get('${prefix}nav.json', (request) {
-    var json = jsonlib.parse(request.responseText);
+  HttpRequest.getString('${prefix}nav.json').then((text) {
+    var json = jsonlib.parse(text);
     buildNavigation(json);
     setupSearch(json);
   });
@@ -54,7 +54,7 @@
 
   // Insert it into the DOM.
   final navElement = document.query('.nav');
-  navElement.innerHTML = html.toString();
+  navElement.innerHtml = html.toString();
 }
 
 /** Writes the navigation for the types contained by [library] to [html]. */
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart b/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
index 7348f2e..c90469a 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
@@ -48,7 +48,7 @@
 
     var preList = elem.queryAll('pre.source');
 
-    showCode.on.click.add((e) {
+    showCode.onClick.listen((e) {
       for (final pre in preList) {
         if (pre.classes.contains('expanded')) {
           pre.classes.remove('expanded');
@@ -72,7 +72,7 @@
   var showInherited = document.query('#show-inherited');
   if (showInherited == null) return;
   showInherited.dataAttributes.putIfAbsent('show-inherited', () => 'block');
-  showInherited.on.click.add((e) {
+  showInherited.onClick.listen((e) {
     String display = showInherited.dataAttributes['show-inherited'];
     if (display == 'block') {
       display = 'none';
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart b/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart
index 05798b3..b5e877a 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart
@@ -345,7 +345,7 @@
  * Setup window shortcuts.
  */
 void setupShortcuts() {
-  window.on.keyDown.add(shortcutHandler);
+  window.onKeyDown.listen(shortcutHandler);
 }
 
 /** Setup search hooks. */
@@ -354,10 +354,10 @@
   searchInput = query('#q');
   dropdown = query('#drop-down');
 
-  searchInput.on.keyDown.add(handleUpDown);
-  searchInput.on.keyUp.add(updateDropDown);
-  searchInput.on.change.add(updateDropDown);
-  searchInput.on.reset.add(updateDropDown);
-  searchInput.on.focus.add((event) => showDropDown());
-  searchInput.on.blur.add((event) => hideDropDown());
+  searchInput.onKeyDown.listen(handleUpDown);
+  searchInput.onKeyUp.listen(updateDropDown);
+  searchInput.onChange.listen(updateDropDown);
+  searchInput.onReset.listen(updateDropDown);
+  searchInput.onFocus.listen((event) => showDropDown());
+  searchInput.onBlur.listen((event) => hideDropDown());
 }
\ No newline at end of file
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/search.dart b/sdk/lib/_internal/dartdoc/lib/src/client/search.dart
index 22f4880..9686755 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/client/search.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/client/search.dart
@@ -108,9 +108,9 @@
 
     row = table.insertRow(table.rows.length);
     row.classes.add('drop-down-link-tr');
-    row.on.mouseDown.add((event) => hideDropDownSuspend = true);
-    row.on.click.add(clickHandler);
-    row.on.mouseUp.add((event) => hideDropDownSuspend = false);
+    row.onMouseDown.listen((event) => hideDropDownSuspend = true);
+    row.onClick.listen(clickHandler);
+    row.onMouseUp.listen((event) => hideDropDownSuspend = false);
     var sb = new StringBuffer();
     sb.add('<td class="drop-down-link-td">');
     sb.add('<table class="drop-down-table"><tr><td colspan="2">');
@@ -146,7 +146,7 @@
       sb.add('library $library');
     }
     sb.add('</td></tr></table></td>');
-    row.innerHTML = sb.toString();
+    row.innerHtml = sb.toString();
   }
 }
 
diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart
index 98efa98..5c35483 100644
--- a/sdk/lib/_internal/libraries.dart
+++ b/sdk/lib/_internal/libraries.dart
@@ -35,10 +35,6 @@
 
   "collection": const LibraryInfo("collection/collection.dart"),
 
-  "collection-dev": const LibraryInfo(
-      "collection_dev/collection_dev.dart",
-      documented: false),
-
   "core": const LibraryInfo(
       "core/core.dart",
       dart2jsPatchPath: "_internal/compiler/implementation/lib/core_patch.dart"),
@@ -111,6 +107,11 @@
         category: "Client",
         dart2jsPath: "web_audio/dart2js/web_audio_dart2js.dart"),
 
+  "_collection-dev": const LibraryInfo(
+      "_collection_dev/collection_dev.dart",
+      category: "Internal",
+      documented: false),
+
   "_js_helper": const LibraryInfo(
       "_internal/compiler/implementation/lib/js_helper.dart",
       category: "Internal",
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index 80716fb..8998f83 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.dart
@@ -5,6 +5,7 @@
 library dart.async;
 
 part 'async_error.dart';
+part 'collection_sink.dart';
 part 'future.dart';
 part 'future_impl.dart';
 part 'stream.dart';
diff --git a/sdk/lib/async/async_sources.gypi b/sdk/lib/async/async_sources.gypi
index fe95d17..549a749 100644
--- a/sdk/lib/async/async_sources.gypi
+++ b/sdk/lib/async/async_sources.gypi
@@ -6,6 +6,7 @@
 {
   'sources': [
     'async_error.dart',
+    'collection_sink.dart',
     'future.dart',
     'future_impl.dart',
     'stream.dart',
diff --git a/sdk/lib/async/collection_sink.dart b/sdk/lib/async/collection_sink.dart
new file mode 100644
index 0000000..a023fd1
--- /dev/null
+++ b/sdk/lib/async/collection_sink.dart
@@ -0,0 +1,46 @@
+// 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.
+
+part of dart.async;
+
+typedef void _CollectionSinkCallback<T>(Collection<T> collection);
+typedef void _CollectionSinkErrorCallback(AsyncError error);
+
+/** StreamSink that stores incoming data in a collection. */
+class CollectionSink<T> implements StreamSink<T> {
+  final Collection<T> collection;
+  final _CollectionSinkCallback<T> _callback;
+  final _CollectionSinkErrorCallback _errorCallback;
+  bool _isClosed = false;
+
+  /**
+   * Create a sink that stores incoming values in a collection.
+   *
+   * The [collection] is the collection to add the values to.
+   *
+   * If [callback] is provided, then it's called with the collection as arugment
+   * when the sink's [close] method is called.
+   */
+  CollectionSink(this.collection,
+                { void onClose(Collection<T> collection),
+                  void onError(AsyncError error) })
+      : this._callback = onClose,
+        this._errorCallback = onError;
+
+  add(T value) {
+    if (_isClosed) throw new StateError("Adding to closed sink");
+    collection.add(value);
+  }
+
+  void signalError(AsyncError error) {
+    if (_isClosed) throw new StateError("Singalling error on closed sink");
+    if (_errorCallback != null) _errorCallback(error);
+  }
+
+  void close() {
+    if (_isClosed) throw new StateError("Closing closed sink");
+    _isClosed = true;
+    if (_callback != null) _callback(collection);
+  }
+}
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 0d32aae..a36ffa1 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -276,17 +276,20 @@
    *
    * If the call to [action] returns a [Future], `f2`, then completion of
    * `f` is delayed until `f2` completes. If `f2` completes with
-   * an error, that will be the result of `f` too.
+   * an error, that will be the result of `f` too. The value of `f2` is always
+   * ignored.
    *
    * This method is equivalent to:
    *
    *     Future<T> whenComplete(action()) {
    *       this.then((v) {
-   *                   action();
+   *                   var f2 = action();
+   *                   if (f2 is Future) return f2.then((_) => v);
    *                   return v
    *                 },
    *                 onError: (AsyncError e) {
-   *                   action();
+   *                   var f2 = action();
+   *                   if (f2 is Future) return f2.then((_) { throw e; });
    *                   throw e;
    *                 });
    *     }
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index afdeaf3..c713d9e 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -215,13 +215,13 @@
   }
 
   // Deprecated method, previously called 'pipe', retained for compatibility.
-  Future pipeInto(Sink<T> sink,
+  Future pipeInto(StreamSink<T> sink,
                   {void onError(AsyncError error),
                    bool unsubscribeOnError}) {
     _FutureImpl<T> result = new _FutureImpl<T>();
     this.listen(
         sink.add,
-        onError: onError,
+        onError: sink.signalError,
         onDone: () {
           sink.close();
           result._setValue(null);
@@ -847,7 +847,7 @@
 /**
  * An interface that abstracts sending events into a [Stream].
  */
-abstract class StreamSink<T> implements Sink<T> {
+abstract class StreamSink<T> {
   void add(T event);
   /** Signal an async error to the receivers of this sink's values. */
   void signalError(AsyncError errorEvent);
diff --git a/sdk/lib/async/stream_pipe.dart b/sdk/lib/async/stream_pipe.dart
index 8867ee0..aaa34b0 100644
--- a/sdk/lib/async/stream_pipe.dart
+++ b/sdk/lib/async/stream_pipe.dart
@@ -215,6 +215,8 @@
   }
 
   void _handleDone() {
+    // On a done-event, we have already been unsubscribed.
+    _subscription = null;
     _stream._handleDone(this);
   }
 }
diff --git a/sdk/lib/collection/collection.dart b/sdk/lib/collection/collection.dart
index d63b8be..b1a8353 100644
--- a/sdk/lib/collection/collection.dart
+++ b/sdk/lib/collection/collection.dart
@@ -4,7 +4,7 @@
 
 library dart.collection;
 
-import 'dart:collection-dev';
+import 'dart:_collection-dev';
 
 part 'arrays.dart';
 part 'collections.dart';
diff --git a/sdk/lib/collection/collections.dart b/sdk/lib/collection/collections.dart
index 369a3d3..81dd6da 100644
--- a/sdk/lib/collection/collections.dart
+++ b/sdk/lib/collection/collections.dart
@@ -326,6 +326,10 @@
     return new MappedList(list, f);
   }
 
+  static Iterable expand(Iterable iterable, Iterable f(var element)) {
+    return new ExpandIterable(iterable, f);
+  }
+
   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.
@@ -365,107 +369,131 @@
  */
 class Collections {
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static bool contains(Iterable iterable, var element)
       => IterableMixinWorkaround.contains(iterable, element);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static void forEach(Iterable iterable, void f(o)) {
     IterableMixinWorkaround.forEach(iterable, f);
   }
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static bool any(Iterable iterable, bool f(o))
       => IterableMixinWorkaround.any(iterable, f);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static bool every(Iterable iterable, bool f(o))
       => IterableMixinWorkaround.every(iterable, f);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic reduce(Iterable iterable,
                         dynamic initialValue,
                         dynamic combine(dynamic previousValue, element))
       => IterableMixinWorkaround.reduce(iterable, initialValue, combine);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static bool isEmpty(Iterable iterable)
       => IterableMixinWorkaround.isEmpty(iterable);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic first(Iterable iterable)
       => IterableMixinWorkaround.first(iterable);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic last(Iterable iterable)
       => IterableMixinWorkaround.last(iterable);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic min(Iterable iterable, [int compare(var a, var b)])
       => IterableMixinWorkaround.min(iterable, compare);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic max(Iterable iterable, [int compare(var a, var b)])
       => IterableMixinWorkaround.max(iterable, compare);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic single(Iterable iterable)
       => IterableMixinWorkaround.single(iterable);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic firstMatching(Iterable iterable,
                                bool test(dynamic value),
                                dynamic orElse())
       => IterableMixinWorkaround.firstMatching(iterable, test, orElse);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic lastMatching(Iterable iterable,
                               bool test(dynamic value),
                               dynamic orElse())
       => IterableMixinWorkaround.lastMatching(iterable, test, orElse);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic lastMatchingInList(List list,
                                     bool test(dynamic value),
                                     dynamic orElse())
       => IterableMixinWorkaround.lastMatchingInList(list, test, orElse);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic singleMatching(Iterable iterable, bool test(dynamic value))
       => IterableMixinWorkaround.singleMatching(iterable, test);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static dynamic elementAt(Iterable iterable, int index)
       => IterableMixinWorkaround.elementAt(iterable, index);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static String join(Iterable iterable, [String separator])
       => IterableMixinWorkaround.join(iterable, separator);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static String joinList(List list, [String separator])
       => IterableMixinWorkaround.joinList(list, separator);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static Iterable where(Iterable iterable, bool f(var element))
       => IterableMixinWorkaround.where(iterable, f);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static List mappedByList(List list, f(var element))
       => IterableMixinWorkaround.mappedByList(list, f);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static Iterable takeList(List list, int n)
       => IterableMixinWorkaround.takeList(list, n);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static Iterable takeWhile(Iterable iterable, bool test(var value))
       => IterableMixinWorkaround.takeWhile(iterable, test);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static Iterable skipList(List list, int n)
       => IterableMixinWorkaround.skipList(list, n);
 
   /** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+  @deprecated
   static Iterable skipWhile(Iterable iterable, bool test(var value))
       => IterableMixinWorkaround.skipWhile(iterable, test);
 
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 1d4e4b0..1c307253 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.dart
@@ -5,7 +5,7 @@
 library dart.core;
 
 import "dart:collection";
-import "dart:collection-dev";
+import "dart:_collection-dev";
 
 part "bool.dart";
 part "collection.dart";
@@ -32,7 +32,6 @@
 part "print.dart";
 part "regexp.dart";
 part "set.dart";
-part "sink.dart";
 part "stopwatch.dart";
 part "string.dart";
 part "string_buffer.dart";
diff --git a/sdk/lib/core/corelib_sources.gypi b/sdk/lib/core/corelib_sources.gypi
index 0506c5d..a3d2202 100644
--- a/sdk/lib/core/corelib_sources.gypi
+++ b/sdk/lib/core/corelib_sources.gypi
@@ -29,7 +29,6 @@
     'print.dart',
     'regexp.dart',
     'set.dart',
-    'sink.dart',
     'stopwatch.dart',
     'string.dart',
     'strings.dart',
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index fadf0cc..cbeeccd 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -7,6 +7,7 @@
 /**
  * Deprecated class. Please use [DateTime] instead.
  */
+@deprecated
 abstract class Date implements Comparable {
   // Weekday constants that are returned by [weekday] method:
   static const int MON = 1;
diff --git a/sdk/lib/core/exceptions.dart b/sdk/lib/core/exceptions.dart
index 7a6d332..8ee78bc 100644
--- a/sdk/lib/core/exceptions.dart
+++ b/sdk/lib/core/exceptions.dart
@@ -53,12 +53,13 @@
   String toString() => "FormatException: $message";
 }
 
-
-class IllegalJSRegExpException implements Exception {
-  const IllegalJSRegExpException(String this._pattern, String this._errmsg);
-  String toString() => "IllegalJSRegExpException: '$_pattern' '$_errmsg'";
-  final String _pattern;
-  final String _errmsg;
+/**
+ * Deprecated. Replaced by [FormatException].
+ */
+@deprecated
+class IllegalJSRegExpException extends FormatException {
+  IllegalJSRegExpException(String pattern, String errmsg)
+      : super("Illegal pattern: $pattern, $errmsg");
 }
 
 
diff --git a/sdk/lib/core/expect.dart b/sdk/lib/core/expect.dart
index 68b765f..bf9053a 100644
--- a/sdk/lib/core/expect.dart
+++ b/sdk/lib/core/expect.dart
@@ -5,16 +5,20 @@
 part of dart.core;
 
 /**
+ * This class is *deprecated*.
+ *
  * Expect is used for tests that do not want to make use of the
  * Dart unit test library - for example, the core language tests.
  * Third parties are discouraged from using this, and should use
  * the expect() function in the unit test library instead for
  * test assertions.
  */
+@deprecated
 class Expect {
   /**
    * Checks whether the expected and actual values are equal (using `==`).
    */
+  @deprecated
   static void equals(var expected, var actual, [String reason = null]) {
     if (expected == actual) return;
     String msg = _getMessage(reason);
@@ -24,6 +28,7 @@
   /**
    * Checks whether the actual value is a bool and its value is true.
    */
+  @deprecated
   static void isTrue(var actual, [String reason = null]) {
     if (_identical(actual, true)) return;
     String msg = _getMessage(reason);
@@ -33,6 +38,7 @@
   /**
    * Checks whether the actual value is a bool and its value is false.
    */
+  @deprecated
   static void isFalse(var actual, [String reason = null]) {
     if (_identical(actual, false)) return;
     String msg = _getMessage(reason);
@@ -42,6 +48,7 @@
   /**
    * Checks whether [actual] is null.
    */
+  @deprecated
   static void isNull(actual, [String reason = null]) {
     if (null == actual) return;
     String msg = _getMessage(reason);
@@ -51,6 +58,7 @@
   /**
    * Checks whether [actual] is not null.
    */
+  @deprecated
   static void isNotNull(actual, [String reason = null]) {
     if (null != actual) return;
     String msg = _getMessage(reason);
@@ -61,6 +69,7 @@
    * Checks whether the expected and actual values are identical
    * (using `identical`).
    */
+  @deprecated
   static void identical(var expected, var actual, [String reason = null]) {
     if (_identical(expected, actual)) return;
     String msg = _getMessage(reason);
@@ -69,6 +78,7 @@
   }
 
   // Unconditional failure.
+  @deprecated
   static void fail(String msg) {
     _fail("Expect.fail('$msg')");
   }
@@ -78,6 +88,7 @@
    * given tolerance. If no tolerance is given, tolerance is assumed to be the
    * value 4 significant digits smaller than the value given for expected.
    */
+  @deprecated
   static void approxEquals(num expected,
                            num actual,
                            [num tolerance = null,
@@ -93,6 +104,7 @@
           'tolerance:<$tolerance>$msg) fails');
   }
 
+  @deprecated
   static void notEquals(unexpected, actual, [String reason = null]) {
     if (unexpected != actual) return;
     String msg = _getMessage(reason);
@@ -106,6 +118,7 @@
    * used by the standard list implementation.  It should also produce nicer
    * error messages than just calling `Expect.equals(expected, actual)`.
    */
+  @deprecated
   static void listEquals(List expected, List actual, [String reason = null]) {
     String msg = _getMessage(reason);
     int n = (expected.length < actual.length) ? expected.length : actual.length;
@@ -130,6 +143,7 @@
    * the semantics of [Map.containsKey] to determine what "same" means. For
    * each key, checks that the values in both maps are equal using `==`.
    */
+  @deprecated
   static void mapEquals(Map expected, Map actual, [String reason = null]) {
     String msg = _getMessage(reason);
 
@@ -154,6 +168,7 @@
    * Specialized equality test for strings. When the strings don't match,
    * this method shows where the mismatch starts and ends.
    */
+  @deprecated
   static void stringEquals(String expected,
                            String actual,
                            [String reason = null]) {
@@ -222,6 +237,7 @@
    * Checks that every element of [expected] is also in [actual], and that
    * every element of [actual] is also in [expected].
    */
+  @deprecated
   static void setEquals(Iterable expected,
                         Iterable actual,
                         [String reason = null]) {
@@ -262,6 +278,7 @@
    *
    *     Expect.throws(myThrowingFunction, (e) => e is MyException);
    */
+  @deprecated
   static void throws(void f(),
                      [_CheckExceptionFn check = null,
                       String reason = null]) {
@@ -292,6 +309,7 @@
 
 typedef bool _CheckExceptionFn(exception);
 
+@deprecated
 class ExpectException implements Exception {
   ExpectException(this.message);
   String toString() => message;
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 160e773..fc1a647 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -52,23 +52,35 @@
 
   /**
    * Deprecated alias for [map].
-   *
-   * @deprecated
    */
+  @deprecated
   Iterable mappedBy(f(E element)) => map(f);
 
   /**
-    * Returns a lazy [Iterable] with all elements that satisfy the
-    * predicate [f].
-    *
-    * This method returns a view of the mapped elements. As long as the
-    * returned [Iterable] is not iterated over, the supplied function [f] will
-    * not be invoked. Iterating will not cache results, and thus iterating
-    * multiple times over the the returned [Iterable] will invoke the supplied
-    * function [f] multiple times on the same element.
-    */
+   * Returns a lazy [Iterable] with all elements that satisfy the
+   * predicate [f].
+   *
+   * This method returns a view of the mapped elements. As long as the
+   * returned [Iterable] is not iterated over, the supplied function [f] will
+   * not be invoked. Iterating will not cache results, and thus iterating
+   * multiple times over the the returned [Iterable] will invoke the supplied
+   * function [f] multiple times on the same element.
+   */
   Iterable<E> where(bool f(E element)) => new WhereIterable<E>(this, f);
 
+
+  /**
+   * Expand each element of this [Iterable] into zero or more elements.
+   *
+   * The resulting Iterable will run through the elements returned
+   * by [f] for each element of this, in order.
+   *
+   * The returned [Iterable] is lazy, and will call [f] for each element
+   * of this every time it's iterated.
+   */
+  Iterable expand(Iterable f(E element)) =>
+      new ExpandIterable<E, dynamic>(this, f);
+
   /**
    * Check whether the collection contains an element equal to [element].
    */
diff --git a/sdk/lib/core/sink.dart b/sdk/lib/core/sink.dart
deleted file mode 100644
index d0dafc0..0000000
--- a/sdk/lib/core/sink.dart
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-part of dart.core;
-/**
- * An interface for an object that can receive a sequence of values.
- */
-abstract class Sink<T> {
-  /** Write a value to the sink. */
-  add(T value);
-  /** Tell the sink that no further values will be written. */
-  void close();
-}
-
-// ----------------------------------------------------------------------
-// Collections/Sink interoperability
-// ----------------------------------------------------------------------
-
-typedef void _CollectionSinkCallback<T>(Collection<T> collection);
-
-/** Sink that stores incoming data in a collection. */
-class CollectionSink<T> implements Sink<T> {
-  final Collection<T> collection;
-  final _CollectionSinkCallback<T> callback;
-  bool _isClosed = false;
-
-  /**
-   * Create a sink that stores incoming values in a collection.
-   *
-   * The [collection] is the collection to add the values to.
-   *
-   * If [callback] is provided, then it's called with the collection as arugment
-   * when the sink's [close] method is called.
-   */
-  CollectionSink(this.collection, [void callback(Collection<T> collection)])
-      : this.callback = callback;
-
-  add(T value) {
-    if (_isClosed) throw new StateError("Adding to closed sink");
-    collection.add(value);
-  }
-
-  void close() {
-    if (_isClosed) throw new StateError("Closing closed sink");
-    _isClosed = true;
-    if (callback != null) callback(collection);
-  }
-}
diff --git a/sdk/lib/core/stopwatch.dart b/sdk/lib/core/stopwatch.dart
index 7d8ce33..5564801 100644
--- a/sdk/lib/core/stopwatch.dart
+++ b/sdk/lib/core/stopwatch.dart
@@ -7,65 +7,7 @@
 /**
  * A simple [Stopwatch] interface to measure elapsed time.
  */
-abstract class Stopwatch {
-  /**
-   * Creates a [Stopwatch] in stopped state with a zero elapsed count.
-   *
-   * The following example shows how to start a [Stopwatch]
-   * right after allocation.
-   *
-   *     Stopwatch stopwatch = new Stopwatch()..start();
-   */
-  factory Stopwatch() => new _StopwatchImpl();
-
-  /**
-   * Starts the [Stopwatch]. The [elapsed] count is increasing monotonically.
-   * If the [Stopwatch] has been stopped, then calling start again restarts it
-   * without resetting the [elapsed] count.
-   * If the [Stopwatch] is currently running, then calling start does nothing.
-   */
-  void start();
-
-  /**
-   * Stops the [Stopwatch]. The [elapsed] count stops increasing.
-   * If the [Stopwatch] is currently not running, then calling stop does
-   * nothing.
-   */
-  void stop();
-
-  /**
-   * Resets the [elapsed] count to zero. This method does not stop or start
-   * the [Stopwatch].
-   */
-  void reset();
-
-  /**
-   * Returns the elapsed number of clock ticks since calling [start] while the
-   * [Stopwatch] is running.
-   * Returns the elapsed number of clock ticks between calling [start] and
-   * calling [stop].
-   * Returns 0 if the [Stopwatch] has never been started.
-   * The elapsed number of clock ticks increases by [frequency] every second.
-   */
-  int get elapsedTicks;
-
-  /**
-   * Returns the [elapsedTicks] counter converted to microseconds.
-   */
-  int get elapsedMicroseconds;
-
-  /**
-   * Returns the [elapsedTicks] counter converted to milliseconds.
-   */
-  int get elapsedMilliseconds;
-
-  /**
-   * Returns the frequency of the elapsed counter in Hz.
-   */
-  int get frequency;
-}
-
-class _StopwatchImpl implements Stopwatch {
+class Stopwatch {
   // The _start and _stop fields capture the time when [start] and [stop]
   // are called respectively.
   // If _start is null, then the [Stopwatch] has not been started yet.
@@ -74,30 +16,49 @@
   int _start;
   int _stop;
 
-  _StopwatchImpl() : _start = null, _stop = null {}
+  /**
+   * Creates a [Stopwatch] in stopped state with a zero elapsed count.
+   *
+   * The following example shows how to start a [Stopwatch]
+   * right after allocation.
+   *
+   *     Stopwatch stopwatch = new Stopwatch()..start();
+   */
+  Stopwatch() : _start = null, _stop = null {}
 
+  /**
+   * Starts the [Stopwatch]. The [elapsed] count is increasing monotonically.
+   * If the [Stopwatch] has been stopped, then calling start again restarts it
+   * without resetting the [elapsed] count.
+   * If the [Stopwatch] is currently running, then calling start does nothing.
+   */
   void start() {
+    if (isRunning) return;
     if (_start == null) {
       // This stopwatch has never been started.
       _start = _now();
     } else {
-      if (_stop == null) {
-        return;
-      }
-      // Restarting this stopwatch. Prepend the elapsed time to the current
+      // Restart this stopwatch. Prepend the elapsed time to the current
       // start time.
       _start = _now() - (_stop - _start);
       _stop = null;
     }
   }
 
+  /**
+   * Stops the [Stopwatch]. The [elapsed] count stops increasing.
+   * If the [Stopwatch] is currently not running, then calling stop does
+   * nothing.
+   */
   void stop() {
-    if (_start == null || _stop != null) {
-      return;
-    }
+    if (!isRunning) return;
     _stop = _now();
   }
 
+  /**
+   * Resets the [elapsed] count to zero. This method does not stop or start
+   * the [Stopwatch].
+   */
   void reset() {
     if (_start == null) return;
     // If [_start] is not null, then the stopwatch had already been started. It
@@ -110,6 +71,14 @@
     }
   }
 
+  /**
+   * Returns the elapsed number of clock ticks since calling [start] while the
+   * [Stopwatch] is running.
+   * Returns the elapsed number of clock ticks between calling [start] and
+   * calling [stop].
+   * Returns 0 if the [Stopwatch] has never been started.
+   * The elapsed number of clock ticks increases by [frequency] every second.
+   */
   int get elapsedTicks {
     if (_start == null) {
       return 0;
@@ -117,16 +86,30 @@
     return (_stop == null) ? (_now() - _start) : (_stop - _start);
   }
 
+  /**
+   * Returns the [elapsedTicks] counter converted to microseconds.
+   */
   int get elapsedMicroseconds {
     return (elapsedTicks * 1000000) ~/ frequency;
   }
 
+  /**
+   * Returns the [elapsedTicks] counter converted to milliseconds.
+   */
   int get elapsedMilliseconds {
     return (elapsedTicks * 1000) ~/ frequency;
   }
 
+  /**
+   * Returns the frequency of the elapsed counter in Hz.
+   */
   int get frequency => _frequency();
 
+  /**
+   * Returns wether the [StopWatch] is currently running.
+   */
+  bool get isRunning => _start != null && _stop == null;
+
   external static int _frequency();
   external static int _now();
 }
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index 247bdef..6fb1b90 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -30,6 +30,7 @@
   /**
    * *Deprecated*. Use [String.fromCharCode] instead.
    */
+  @deprecated
   factory String.character(int charCode) => new String.fromCharCode(charCode);
 
   /**
@@ -75,6 +76,7 @@
    *
    * *This method is deprecated. Please use [codeUnitAt] instead.*
    */
+  @deprecated
   int charCodeAt(int index);
 
   /**
@@ -237,6 +239,7 @@
    *     Iterable<String> characters =
    *         string.runes.map((c) => new String.fromCharCode(c));
    */
+  @deprecated
   List<String> splitChars();
 
   /**
diff --git a/sdk/lib/core/strings.dart b/sdk/lib/core/strings.dart
index 412e23f..c8a2afc 100644
--- a/sdk/lib/core/strings.dart
+++ b/sdk/lib/core/strings.dart
@@ -4,12 +4,14 @@
 
 part of dart.core;
 
+@deprecated
 abstract class Strings {
   /**
    * Joins all the given strings to create a new string.
    *
    * *Deprecated* Use `strings.join(separator)` instead.
    */
+  @deprecated
   external static String join(Iterable<String> strings, String separator);
 
   /**
@@ -17,5 +19,6 @@
    *
    * *Deprecated* Use `strings.join()` instead.
    */
+  @deprecated
   external static String concatAll(Iterable<String> strings);
 }
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 6e2a270..321b381 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -1413,6 +1413,10 @@
   @DocsEditable
   bool isPointInPath(num x, num y, [String winding]) native;
 
+  @DomName('CanvasRenderingContext2D.isPointInStroke')
+  @DocsEditable
+  bool isPointInStroke(num x, num y) native;
+
   @DomName('CanvasRenderingContext2D.lineTo')
   @DocsEditable
   void lineTo(num x, num y) native;
@@ -1592,10 +1596,6 @@
   @DocsEditable
   void insertData(int offset, String data) native;
 
-  @DomName('CharacterData.remove')
-  @DocsEditable
-  void remove() native;
-
   @DomName('CharacterData.replaceData')
   @DocsEditable
   void replaceData(int offset, int length, String data) native;
@@ -2342,6 +2342,8 @@
 
   static const int UNKNOWN_RULE = 0;
 
+  static const int WEBKIT_FILTER_RULE = 17;
+
   static const int WEBKIT_KEYFRAMES_RULE = 7;
 
   static const int WEBKIT_KEYFRAME_RULE = 8;
@@ -7098,7 +7100,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
-/// @domName DOMException
+@DomName('DOMException')
 class DomException native "*DOMException" {
 
   static const String INDEX_SIZE = 'IndexSizeError';
@@ -7249,6 +7251,9 @@
   Iterable<DomMimeType> where(bool f(DomMimeType element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(DomMimeType element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(DomMimeType element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(DomMimeType element)) => IterableMixinWorkaround.any(this, f);
@@ -7503,6 +7508,9 @@
   Iterable<DomPlugin> where(bool f(DomPlugin element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(DomPlugin element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(DomPlugin element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(DomPlugin element)) => IterableMixinWorkaround.any(this, f);
@@ -7864,6 +7872,9 @@
   Iterable<String> where(bool f(String element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(String element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(String element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(String element)) => IterableMixinWorkaround.any(this, f);
@@ -8126,6 +8137,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(Element element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   bool get isEmpty {
     return _element.$dom_firstElementChild == null;
   }
@@ -8343,6 +8358,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(Element element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   bool every(bool f(Element element)) {
     for(Element element in this) {
       if (!f(element)) {
@@ -10785,6 +10804,9 @@
   Iterable<File> where(bool f(File element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(File element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(File element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(File element)) => IterableMixinWorkaround.any(this, f);
@@ -11400,6 +11422,9 @@
   Iterable<num> where(bool f(num element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(num element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(num element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(num element)) => IterableMixinWorkaround.any(this, f);
@@ -11616,6 +11641,9 @@
   Iterable<num> where(bool f(num element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(num element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(num element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(num element)) => IterableMixinWorkaround.any(this, f);
@@ -12131,6 +12159,9 @@
   Iterable<Node> where(bool f(Node element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Node element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -12338,6 +12369,9 @@
   Iterable<Node> where(bool f(Node element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Node element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -12730,6 +12764,11 @@
    * * The `Access-Control-Allow-Credentials` header of `url` must be set to true.
    * * If `Access-Control-Expose-Headers` has not been set to true, only a subset of all the response headers will be returned when calling [getAllRequestHeaders].
    *
+   * Note that requests for file:// URIs are only supported by Chrome extensions
+   * with appropriate permissions in their manifest. Requests to file:// URIs
+   * will also never fail- the Future will always complete successfully, even
+   * when the file cannot be found.
+   *
    * See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access_authentication).
    */
   static Future<HttpRequest> request(String url,
@@ -12756,8 +12795,9 @@
     }
 
     xhr.onLoad.listen((e) {
-      if (xhr.status >= 200 && xhr.status < 300 ||
-          xhr.status == 304 ) {
+      // Note: file:// URIs have status of 0.
+      if ((xhr.status >= 200 && xhr.status < 300) ||
+          xhr.status == 0 || xhr.status == 304) {
         completer.complete(xhr);
       } else {
         completer.completeError(e);
@@ -14374,6 +14414,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -14590,6 +14633,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -14806,6 +14852,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -16155,8 +16204,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
-/// @domName MediaStream; @docsEditable true@DomName('MediaStream')
-
+@DomName('MediaStream')
 class MediaStream extends EventTarget native "*MediaStream" {
 
   @DomName('MediaStream.endedEvent')
@@ -17121,6 +17169,9 @@
   Iterable<Node> where(bool f(Node element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Node element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -17594,6 +17645,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(Node element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -17983,6 +18038,9 @@
   Iterable<Node> where(bool f(Node element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Node element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -18588,7 +18646,7 @@
 
   @DomName('HTMLOutputElement.htmlFor')
   @DocsEditable
-  DomSettableTokenList htmlFor;
+  final DomSettableTokenList htmlFor;
 
   @DomName('HTMLOutputElement.labels')
   @DocsEditable
@@ -20366,6 +20424,9 @@
   Iterable<SourceBuffer> where(bool f(SourceBuffer element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(SourceBuffer element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(SourceBuffer element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(SourceBuffer element)) => IterableMixinWorkaround.any(this, f);
@@ -20646,6 +20707,9 @@
   Iterable<SpeechGrammar> where(bool f(SpeechGrammar element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(SpeechGrammar element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(SpeechGrammar element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(SpeechGrammar element)) => IterableMixinWorkaround.any(this, f);
@@ -21260,6 +21324,9 @@
   Iterable<Map> where(bool f(Map element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Map element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Map element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Map element)) => IterableMixinWorkaround.any(this, f);
@@ -22375,6 +22442,9 @@
   Iterable<TextTrackCue> where(bool f(TextTrackCue element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(TextTrackCue element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(TextTrackCue element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(TextTrackCue element)) => IterableMixinWorkaround.any(this, f);
@@ -22586,6 +22656,9 @@
   Iterable<TextTrack> where(bool f(TextTrack element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(TextTrack element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(TextTrack element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(TextTrack element)) => IterableMixinWorkaround.any(this, f);
@@ -22992,6 +23065,9 @@
   Iterable<Touch> where(bool f(Touch element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Touch element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Touch element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Touch element)) => IterableMixinWorkaround.any(this, f);
@@ -23215,16 +23291,20 @@
 
 
 @DocsEditable
-@DomName('WebKitTransitionEvent')
-class TransitionEvent extends Event native "*WebKitTransitionEvent" {
+@DomName('TransitionEvent')
+class TransitionEvent extends Event native "*TransitionEvent" {
 
-  @DomName('WebKitTransitionEvent.elapsedTime')
+  @DomName('TransitionEvent.elapsedTime')
   @DocsEditable
   final num elapsedTime;
 
-  @DomName('WebKitTransitionEvent.propertyName')
+  @DomName('TransitionEvent.propertyName')
   @DocsEditable
   final String propertyName;
+
+  @DomName('TransitionEvent.pseudoElement')
+  @DocsEditable
+  final String pseudoElement;
 }
 // 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
@@ -23434,6 +23514,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -23650,6 +23733,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -23866,6 +23952,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -24079,6 +24168,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -25860,6 +25952,19 @@
 
 
 @DocsEditable
+@DomName('WebKitCSSFilterRule')
+class WebKitCssFilterRule extends CssRule native "*WebKitCSSFilterRule" {
+
+  @DomName('WebKitCSSFilterRule.style')
+  @DocsEditable
+  final CssStyleDeclaration style;
+}
+// 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.
+
+
+@DocsEditable
 @DomName('WebKitCSSFilterValue')
 class WebKitCssFilterValue extends _CssValueList native "*WebKitCSSFilterValue" {
 
@@ -25959,6 +26064,27 @@
 
 
 @DocsEditable
+@DomName('WebKitTransitionEvent')
+class WebKitTransitionEvent extends Event native "*WebKitTransitionEvent" {
+
+  @DomName('WebKitTransitionEvent.elapsedTime')
+  @DocsEditable
+  final num elapsedTime;
+
+  @DomName('WebKitTransitionEvent.propertyName')
+  @DocsEditable
+  final String propertyName;
+
+  @DomName('WebKitTransitionEvent.pseudoElement')
+  @DocsEditable
+  final String pseudoElement;
+}
+// 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.
+
+
+@DocsEditable
 /**
  * Use the WebSocket interface to connect to a WebSocket,
  * and to send and receive data on that WebSocket.
@@ -27966,6 +28092,9 @@
   Iterable<ClientRect> where(bool f(ClientRect element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(ClientRect element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(ClientRect element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(ClientRect element)) => IterableMixinWorkaround.any(this, f);
@@ -28163,6 +28292,9 @@
   Iterable<CssRule> where(bool f(CssRule element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(CssRule element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(CssRule element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(CssRule element)) => IterableMixinWorkaround.any(this, f);
@@ -28360,6 +28492,9 @@
   Iterable<CssValue> where(bool f(CssValue element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(CssValue element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(CssValue element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(CssValue element)) => IterableMixinWorkaround.any(this, f);
@@ -28557,6 +28692,9 @@
   Iterable<Entry> where(bool f(Entry element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Entry element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Entry element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Entry element)) => IterableMixinWorkaround.any(this, f);
@@ -28754,6 +28892,9 @@
   Iterable<EntrySync> where(bool f(EntrySync element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(EntrySync element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(EntrySync element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(EntrySync element)) => IterableMixinWorkaround.any(this, f);
@@ -28951,6 +29092,9 @@
   Iterable<Gamepad> where(bool f(Gamepad element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Gamepad element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Gamepad element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Gamepad element)) => IterableMixinWorkaround.any(this, f);
@@ -29263,6 +29407,9 @@
   Iterable<MediaStream> where(bool f(MediaStream element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(MediaStream element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(MediaStream element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(MediaStream element)) => IterableMixinWorkaround.any(this, f);
@@ -29460,6 +29607,9 @@
   Iterable<SpeechInputResult> where(bool f(SpeechInputResult element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(SpeechInputResult element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(SpeechInputResult element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(SpeechInputResult element)) => IterableMixinWorkaround.any(this, f);
@@ -29657,6 +29807,9 @@
   Iterable<SpeechRecognitionResult> where(bool f(SpeechRecognitionResult element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(SpeechRecognitionResult element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(SpeechRecognitionResult element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(SpeechRecognitionResult element)) => IterableMixinWorkaround.any(this, f);
@@ -29854,6 +30007,9 @@
   Iterable<StyleSheet> where(bool f(StyleSheet element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(StyleSheet element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(StyleSheet element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(StyleSheet element)) => IterableMixinWorkaround.any(this, f);
@@ -30402,13 +30558,15 @@
 
   Iterable<String> where(bool f(String element)) => readClasses().where(f);
 
+  Iterable expand(Iterable f(String element)) => readClasses.expand(f);
+
   bool every(bool f(String element)) => readClasses().every(f);
 
   bool any(bool f(String element)) => readClasses().any(f);
 
   bool get isEmpty => readClasses().isEmpty;
 
-  int get length =>readClasses().length;
+  int get length => readClasses().length;
 
   dynamic reduce(dynamic initialValue,
       dynamic combine(dynamic previousValue, String element)) {
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 8884e11..50b3922a 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -1816,6 +1816,10 @@
   @DocsEditable
   bool _isPointInPath_2(x, y) native "CanvasRenderingContext2D__isPointInPath_2_Callback";
 
+  @DomName('CanvasRenderingContext2D.isPointInStroke')
+  @DocsEditable
+  bool isPointInStroke(num x, num y) native "CanvasRenderingContext2D_isPointInStroke_Callback";
+
   @DomName('CanvasRenderingContext2D.lineTo')
   @DocsEditable
   void lineTo(num x, num y) native "CanvasRenderingContext2D_lineTo_Callback";
@@ -2023,10 +2027,6 @@
   @DocsEditable
   void insertData(int offset, String data) native "CharacterData_insertData_Callback";
 
-  @DomName('CharacterData.remove')
-  @DocsEditable
-  void remove() native "CharacterData_remove_Callback";
-
   @DomName('CharacterData.replaceData')
   @DocsEditable
   void replaceData(int offset, int length, String data) native "CharacterData_replaceData_Callback";
@@ -2946,6 +2946,8 @@
 
   static const int UNKNOWN_RULE = 0;
 
+  static const int WEBKIT_FILTER_RULE = 17;
+
   static const int WEBKIT_KEYFRAMES_RULE = 7;
 
   static const int WEBKIT_KEYFRAME_RULE = 8;
@@ -7847,7 +7849,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
-/// @domName DOMException
+@DomName('DOMException')
 class DomException extends NativeFieldWrapperClass1 {
 
   static const String INDEX_SIZE = 'IndexSizeError';
@@ -8002,6 +8004,9 @@
   Iterable<DomMimeType> where(bool f(DomMimeType element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(DomMimeType element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(DomMimeType element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(DomMimeType element)) => IterableMixinWorkaround.any(this, f);
@@ -8270,6 +8275,9 @@
   Iterable<DomPlugin> where(bool f(DomPlugin element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(DomPlugin element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(DomPlugin element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(DomPlugin element)) => IterableMixinWorkaround.any(this, f);
@@ -8656,6 +8664,9 @@
   Iterable<String> where(bool f(String element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(String element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(String element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(String element)) => IterableMixinWorkaround.any(this, f);
@@ -8939,6 +8950,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(Element element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   bool get isEmpty {
     return _element.$dom_firstElementChild == null;
   }
@@ -9156,6 +9171,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(Element element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   bool every(bool f(Element element)) {
     for(Element element in this) {
       if (!f(element)) {
@@ -11566,6 +11585,9 @@
   Iterable<File> where(bool f(File element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(File element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(File element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(File element)) => IterableMixinWorkaround.any(this, f);
@@ -12235,6 +12257,9 @@
   Iterable<num> where(bool f(num element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(num element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(num element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(num element)) => IterableMixinWorkaround.any(this, f);
@@ -12470,6 +12495,9 @@
   Iterable<num> where(bool f(num element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(num element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(num element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(num element)) => IterableMixinWorkaround.any(this, f);
@@ -13055,6 +13083,9 @@
   Iterable<Node> where(bool f(Node element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Node element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -13264,6 +13295,9 @@
   Iterable<Node> where(bool f(Node element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Node element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -13673,6 +13707,11 @@
    * * The `Access-Control-Allow-Credentials` header of `url` must be set to true.
    * * If `Access-Control-Expose-Headers` has not been set to true, only a subset of all the response headers will be returned when calling [getAllRequestHeaders].
    *
+   * Note that requests for file:// URIs are only supported by Chrome extensions
+   * with appropriate permissions in their manifest. Requests to file:// URIs
+   * will also never fail- the Future will always complete successfully, even
+   * when the file cannot be found.
+   *
    * See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access_authentication).
    */
   static Future<HttpRequest> request(String url,
@@ -13699,8 +13738,9 @@
     }
 
     xhr.onLoad.listen((e) {
-      if (xhr.status >= 200 && xhr.status < 300 ||
-          xhr.status == 304 ) {
+      // Note: file:// URIs have status of 0.
+      if ((xhr.status >= 200 && xhr.status < 300) ||
+          xhr.status == 0 || xhr.status == 304) {
         completer.complete(xhr);
       } else {
         completer.completeError(e);
@@ -15636,6 +15676,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -15871,6 +15914,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -16106,6 +16152,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -17748,8 +17797,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
-/// @domName MediaStream; @docsEditable true@DomName('MediaStream')
-
+@DomName('MediaStream')
 class MediaStream extends EventTarget {
   MediaStream.internal() : super.internal();
 
@@ -18725,6 +18773,9 @@
   Iterable<Node> where(bool f(Node element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Node element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -19195,6 +19246,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(Node element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -19581,6 +19636,9 @@
   Iterable<Node> where(bool f(Node element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Node element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -20296,10 +20354,6 @@
   @DocsEditable
   DomSettableTokenList get htmlFor native "HTMLOutputElement_htmlFor_Getter";
 
-  @DomName('HTMLOutputElement.htmlFor')
-  @DocsEditable
-  void set htmlFor(DomSettableTokenList value) native "HTMLOutputElement_htmlFor_Setter";
-
   @DomName('HTMLOutputElement.labels')
   @DocsEditable
   List<Node> get labels native "HTMLOutputElement_labels_Getter";
@@ -22290,6 +22344,9 @@
   Iterable<SourceBuffer> where(bool f(SourceBuffer element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(SourceBuffer element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(SourceBuffer element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(SourceBuffer element)) => IterableMixinWorkaround.any(this, f);
@@ -22608,6 +22665,9 @@
   Iterable<SpeechGrammar> where(bool f(SpeechGrammar element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(SpeechGrammar element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(SpeechGrammar element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(SpeechGrammar element)) => IterableMixinWorkaround.any(this, f);
@@ -23309,6 +23369,9 @@
   Iterable<Map> where(bool f(Map element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Map element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Map element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Map element)) => IterableMixinWorkaround.any(this, f);
@@ -24663,6 +24726,9 @@
   Iterable<TextTrackCue> where(bool f(TextTrackCue element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(TextTrackCue element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(TextTrackCue element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(TextTrackCue element)) => IterableMixinWorkaround.any(this, f);
@@ -24878,6 +24944,9 @@
   Iterable<TextTrack> where(bool f(TextTrack element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(TextTrack element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(TextTrack element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(TextTrack element)) => IterableMixinWorkaround.any(this, f);
@@ -25292,6 +25361,9 @@
   Iterable<Touch> where(bool f(Touch element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Touch element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Touch element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Touch element)) => IterableMixinWorkaround.any(this, f);
@@ -25544,17 +25616,21 @@
 
 
 @DocsEditable
-@DomName('WebKitTransitionEvent')
+@DomName('TransitionEvent')
 class TransitionEvent extends Event {
   TransitionEvent.internal() : super.internal();
 
-  @DomName('WebKitTransitionEvent.elapsedTime')
+  @DomName('TransitionEvent.elapsedTime')
   @DocsEditable
-  num get elapsedTime native "WebKitTransitionEvent_elapsedTime_Getter";
+  num get elapsedTime native "TransitionEvent_elapsedTime_Getter";
 
-  @DomName('WebKitTransitionEvent.propertyName')
+  @DomName('TransitionEvent.propertyName')
   @DocsEditable
-  String get propertyName native "WebKitTransitionEvent_propertyName_Getter";
+  String get propertyName native "TransitionEvent_propertyName_Getter";
+
+  @DomName('TransitionEvent.pseudoElement')
+  @DocsEditable
+  String get pseudoElement native "TransitionEvent_pseudoElement_Getter";
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -25779,6 +25855,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -26014,6 +26093,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -26249,6 +26331,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -26482,6 +26567,9 @@
   Iterable<int> where(bool f(int element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(int element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -28458,6 +28546,23 @@
 
 
 @DocsEditable
+@DomName('WebKitCSSFilterRule')
+class WebKitCssFilterRule extends CssRule {
+  WebKitCssFilterRule.internal() : super.internal();
+
+  @DomName('WebKitCSSFilterRule.style')
+  @DocsEditable
+  CssStyleDeclaration get style native "WebKitCSSFilterRule_style_Getter";
+
+}
+// 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.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
 @DomName('WebKitCSSFilterValue')
 class WebKitCssFilterValue extends _CssValueList {
   WebKitCssFilterValue.internal() : super.internal();
@@ -28561,6 +28666,31 @@
 
 
 @DocsEditable
+@DomName('WebKitTransitionEvent')
+class WebKitTransitionEvent extends Event {
+  WebKitTransitionEvent.internal() : super.internal();
+
+  @DomName('WebKitTransitionEvent.elapsedTime')
+  @DocsEditable
+  num get elapsedTime native "WebKitTransitionEvent_elapsedTime_Getter";
+
+  @DomName('WebKitTransitionEvent.propertyName')
+  @DocsEditable
+  String get propertyName native "WebKitTransitionEvent_propertyName_Getter";
+
+  @DomName('WebKitTransitionEvent.pseudoElement')
+  @DocsEditable
+  String get pseudoElement native "WebKitTransitionEvent_pseudoElement_Getter";
+
+}
+// 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.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
 /**
  * Use the WebSocket interface to connect to a WebSocket,
  * and to send and receive data on that WebSocket.
@@ -30371,6 +30501,9 @@
   Iterable<ClientRect> where(bool f(ClientRect element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(ClientRect element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(ClientRect element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(ClientRect element)) => IterableMixinWorkaround.any(this, f);
@@ -30572,6 +30705,9 @@
   Iterable<CssRule> where(bool f(CssRule element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(CssRule element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(CssRule element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(CssRule element)) => IterableMixinWorkaround.any(this, f);
@@ -30773,6 +30909,9 @@
   Iterable<CssValue> where(bool f(CssValue element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(CssValue element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(CssValue element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(CssValue element)) => IterableMixinWorkaround.any(this, f);
@@ -31111,6 +31250,9 @@
   Iterable<Entry> where(bool f(Entry element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Entry element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Entry element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Entry element)) => IterableMixinWorkaround.any(this, f);
@@ -31312,6 +31454,9 @@
   Iterable<EntrySync> where(bool f(EntrySync element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(EntrySync element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(EntrySync element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(EntrySync element)) => IterableMixinWorkaround.any(this, f);
@@ -31513,6 +31658,9 @@
   Iterable<Gamepad> where(bool f(Gamepad element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Gamepad element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Gamepad element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Gamepad element)) => IterableMixinWorkaround.any(this, f);
@@ -31857,6 +32005,9 @@
   Iterable<MediaStream> where(bool f(MediaStream element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(MediaStream element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(MediaStream element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(MediaStream element)) => IterableMixinWorkaround.any(this, f);
@@ -32058,6 +32209,9 @@
   Iterable<SpeechInputResult> where(bool f(SpeechInputResult element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(SpeechInputResult element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(SpeechInputResult element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(SpeechInputResult element)) => IterableMixinWorkaround.any(this, f);
@@ -32259,6 +32413,9 @@
   Iterable<SpeechRecognitionResult> where(bool f(SpeechRecognitionResult element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(SpeechRecognitionResult element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(SpeechRecognitionResult element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(SpeechRecognitionResult element)) => IterableMixinWorkaround.any(this, f);
@@ -32460,6 +32617,9 @@
   Iterable<StyleSheet> where(bool f(StyleSheet element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(StyleSheet element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(StyleSheet element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(StyleSheet element)) => IterableMixinWorkaround.any(this, f);
@@ -33009,13 +33169,15 @@
 
   Iterable<String> where(bool f(String element)) => readClasses().where(f);
 
+  Iterable expand(Iterable f(String element)) => readClasses.expand(f);
+
   bool every(bool f(String element)) => readClasses().every(f);
 
   bool any(bool f(String element)) => readClasses().any(f);
 
   bool get isEmpty => readClasses().isEmpty;
 
-  int get length =>readClasses().length;
+  int get length => readClasses().length;
 
   dynamic reduce(dynamic initialValue,
       dynamic combine(dynamic previousValue, String element)) {
diff --git a/sdk/lib/html/html_common/filtered_element_list.dart b/sdk/lib/html/html_common/filtered_element_list.dart
index a16d42c..330b0df 100644
--- a/sdk/lib/html/html_common/filtered_element_list.dart
+++ b/sdk/lib/html/html_common/filtered_element_list.dart
@@ -104,6 +104,7 @@
   Iterable map(f(Element element)) => _filtered.map(f);
   List mappedBy(f(Element element)) => _filtered.mappedBy(f);
   Iterable<Element> where(bool f(Element element)) => _filtered.where(f);
+  Iterable expand(Iterable f(Element element)) => _filtered.expand(f);
 
   Element removeAt(int index) {
     final result = this[index];
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index fdc5c72..6390ff3 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -234,7 +234,7 @@
 
   @DomName('IDBDatabase.versionchangeEvent')
   @DocsEditable
-  static const EventStreamProvider<UpgradeNeededEvent> versionChangeEvent = const EventStreamProvider<UpgradeNeededEvent>('versionchange');
+  static const EventStreamProvider<VersionChangeEvent> versionChangeEvent = const EventStreamProvider<VersionChangeEvent>('versionchange');
 
   @DocsEditable
   @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
@@ -304,7 +304,7 @@
 
   @DomName('IDBDatabase.onversionchange')
   @DocsEditable
-  Stream<UpgradeNeededEvent> get onVersionChange => versionChangeEvent.forTarget(this);
+  Stream<VersionChangeEvent> get onVersionChange => versionChangeEvent.forTarget(this);
 }
 
 @DocsEditable
@@ -350,7 +350,7 @@
 
   @DomName('IDBFactory.deleteDatabase')
   @DocsEditable
-  VersionChangeRequest deleteDatabase(String name) native;
+  OpenDBRequest deleteDatabase(String name) native;
 
   @DomName('IDBFactory.open')
   @DocsEditable
@@ -867,61 +867,15 @@
 
 @DocsEditable
 @DomName('IDBVersionChangeEvent')
-class UpgradeNeededEvent extends Event native "*IDBVersionChangeEvent" {
-
-  @DomName('IDBUpgradeNeededEvent.newVersion')
-  @DocsEditable
-  final int newVersion;
-
-  @DomName('IDBUpgradeNeededEvent.oldVersion')
-  @DocsEditable
-  final int oldVersion;
-}
-// 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.
-
-
-@DocsEditable
-@DomName('IDBVersionChangeEvent')
 class VersionChangeEvent extends Event native "*IDBVersionChangeEvent" {
 
-  @DomName('IDBVersionChangeEvent.version')
+  @DomName('IDBVersionChangeEvent.newVersion')
   @DocsEditable
-  final String version;
-}
-// 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.
+  final dynamic newVersion;
 
-
-@DocsEditable
-@DomName('IDBVersionChangeRequest')
-class VersionChangeRequest extends Request implements EventTarget native "*IDBVersionChangeRequest" {
-
-  @DomName('IDBVersionChangeRequest.blockedEvent')
+  @DomName('IDBVersionChangeEvent.oldVersion')
   @DocsEditable
-  static const EventStreamProvider<Event> blockedEvent = const EventStreamProvider<Event>('blocked');
-
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  VersionChangeRequestEvents get on =>
-    new VersionChangeRequestEvents(this);
-
-  @DomName('IDBVersionChangeRequest.onblocked')
-  @DocsEditable
-  Stream<Event> get onBlocked => blockedEvent.forTarget(this);
-}
-
-@DocsEditable
-@deprecated
-class VersionChangeRequestEvents extends RequestEvents {
-  @DocsEditable
-  VersionChangeRequestEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get blocked => this['blocked'];
+  final dynamic oldVersion;
 }
 // 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
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index 44cdb37..b044500 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -134,7 +134,7 @@
 
   @DomName('IDBDatabase.versionchangeEvent')
   @DocsEditable
-  static const EventStreamProvider<UpgradeNeededEvent> versionChangeEvent = const EventStreamProvider<UpgradeNeededEvent>('versionchange');
+  static const EventStreamProvider<VersionChangeEvent> versionChangeEvent = const EventStreamProvider<VersionChangeEvent>('versionchange');
 
   @DocsEditable
   @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
@@ -213,7 +213,7 @@
 
   @DomName('IDBDatabase.onversionchange')
   @DocsEditable
-  Stream<UpgradeNeededEvent> get onVersionChange => versionChangeEvent.forTarget(this);
+  Stream<VersionChangeEvent> get onVersionChange => versionChangeEvent.forTarget(this);
 
 }
 
@@ -258,7 +258,7 @@
 
   @DomName('IDBFactory.deleteDatabase')
   @DocsEditable
-  VersionChangeRequest deleteDatabase(String name) native "IDBFactory_deleteDatabase_Callback";
+  OpenDBRequest deleteDatabase(String name) native "IDBFactory_deleteDatabase_Callback";
 
   OpenDBRequest open(String name, [int version]) {
     if (?version) {
@@ -981,71 +981,17 @@
 
 @DocsEditable
 @DomName('IDBVersionChangeEvent')
-class UpgradeNeededEvent extends Event {
-  UpgradeNeededEvent.internal() : super.internal();
-
-  @DomName('IDBUpgradeNeededEvent.newVersion')
-  @DocsEditable
-  int get newVersion native "IDBUpgradeNeededEvent_newVersion_Getter";
-
-  @DomName('IDBUpgradeNeededEvent.oldVersion')
-  @DocsEditable
-  int get oldVersion native "IDBUpgradeNeededEvent_oldVersion_Getter";
-
-}
-// 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.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
-@DomName('IDBVersionChangeEvent')
 class VersionChangeEvent extends Event {
   VersionChangeEvent.internal() : super.internal();
 
-  @DomName('IDBVersionChangeEvent.version')
+  @DomName('IDBVersionChangeEvent.newVersion')
   @DocsEditable
-  String get version native "IDBVersionChangeEvent_version_Getter";
+  dynamic get newVersion native "IDBVersionChangeEvent_newVersion_Getter";
 
-}
-// 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.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
-@DomName('IDBVersionChangeRequest')
-class VersionChangeRequest extends Request implements EventTarget {
-  VersionChangeRequest.internal() : super.internal();
-
-  @DomName('IDBVersionChangeRequest.blockedEvent')
+  @DomName('IDBVersionChangeEvent.oldVersion')
   @DocsEditable
-  static const EventStreamProvider<Event> blockedEvent = const EventStreamProvider<Event>('blocked');
+  dynamic get oldVersion native "IDBVersionChangeEvent_oldVersion_Getter";
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  VersionChangeRequestEvents get on =>
-    new VersionChangeRequestEvents(this);
-
-  @DomName('IDBVersionChangeRequest.onblocked')
-  @DocsEditable
-  Stream<Event> get onBlocked => blockedEvent.forTarget(this);
-
-}
-
-@DocsEditable
-@deprecated
-class VersionChangeRequestEvents extends RequestEvents {
-  @DocsEditable
-  VersionChangeRequestEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get blocked => this['blocked'];
 }
 // 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
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 993cbee..efa341c 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -401,6 +401,7 @@
   int _streamReadInto(List<int> buffer, int offset, int len) {
     List<int> data = _buffer.readBytes(len);
     buffer.setRange(offset, data.length, data);
+    return data.length;
   }
 
   void _streamSetErrorHandler(callback(e)) {
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index 092dc7c..9f47721 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -3217,6 +3217,9 @@
   Iterable<Length> where(bool f(Length element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Length element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Length element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Length element)) => IterableMixinWorkaround.any(this, f);
@@ -3841,6 +3844,9 @@
   Iterable<Number> where(bool f(Number element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Number element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Number element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Number element)) => IterableMixinWorkaround.any(this, f);
@@ -4741,6 +4747,9 @@
   Iterable<PathSeg> where(bool f(PathSeg element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(PathSeg element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(PathSeg element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(PathSeg element)) => IterableMixinWorkaround.any(this, f);
@@ -5625,6 +5634,9 @@
   Iterable<String> where(bool f(String element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(String element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(String element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(String element)) => IterableMixinWorkaround.any(this, f);
@@ -6788,6 +6800,9 @@
   Iterable<Transform> where(bool f(Transform element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Transform element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Transform element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Transform element)) => IterableMixinWorkaround.any(this, f);
@@ -7305,6 +7320,9 @@
   Iterable<ElementInstance> where(bool f(ElementInstance element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(ElementInstance element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(ElementInstance element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(ElementInstance element)) => IterableMixinWorkaround.any(this, f);
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index 12ead7f..70fbe36 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -3481,6 +3481,9 @@
   Iterable<Length> where(bool f(Length element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Length element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Length element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Length element)) => IterableMixinWorkaround.any(this, f);
@@ -4182,6 +4185,9 @@
   Iterable<Number> where(bool f(Number element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Number element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Number element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Number element)) => IterableMixinWorkaround.any(this, f);
@@ -5359,6 +5365,9 @@
   Iterable<PathSeg> where(bool f(PathSeg element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(PathSeg element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(PathSeg element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(PathSeg element)) => IterableMixinWorkaround.any(this, f);
@@ -6341,6 +6350,9 @@
   Iterable<String> where(bool f(String element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(String element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(String element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(String element)) => IterableMixinWorkaround.any(this, f);
@@ -7593,6 +7605,9 @@
   Iterable<Transform> where(bool f(Transform element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(Transform element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(Transform element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Transform element)) => IterableMixinWorkaround.any(this, f);
@@ -8164,6 +8179,9 @@
   Iterable<ElementInstance> where(bool f(ElementInstance element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f(ElementInstance element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f(ElementInstance element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(ElementInstance element)) => IterableMixinWorkaround.any(this, f);
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index 668ac80..57ef07d 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -16,6 +16,8 @@
 import "../../../sdk/lib/_internal/compiler/implementation/ssa/ssa.dart" as ssa;
 import "../../../sdk/lib/_internal/compiler/implementation/util/util.dart";
 import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
+       show Compiler;
 
 import "mock_compiler.dart";
 import "parser_helper.dart";
@@ -34,6 +36,7 @@
   compiler.parseScript(code);
   lego.Element element = compiler.mainApp.find(buildSourceString(entry));
   if (element == null) return null;
+  compiler.phase = Compiler.PHASE_RESOLVING;
   compiler.backend.enqueueHelpers(compiler.enqueuer.resolution);
   compiler.processQueue(compiler.enqueuer.resolution, element);
   var context = new js.JavaScriptItemCompilationContext();
@@ -42,19 +45,24 @@
   resolutionWork.run(compiler, compiler.enqueuer.resolution);
   leg.CodegenWorkItem work =
       new leg.CodegenWorkItem(element, resolutionWork.resolutionTree, context);
+  compiler.phase = Compiler.PHASE_COMPILING;
   work.run(compiler, compiler.enqueuer.codegen);
-  return compiler.enqueuer.codegen.assembleCode(element);
+  js.JavaScriptBackend backend = compiler.backend;
+  return backend.assembleCode(element);
 }
 
-MockCompiler compilerFor(String code, Uri uri, {bool analyzeAll: false}) {
-  MockCompiler compiler = new MockCompiler(analyzeAll: analyzeAll);
+MockCompiler compilerFor(String code, Uri uri,
+                         {bool analyzeAll: false,
+                          String coreSource: DEFAULT_CORELIB}) {
+  MockCompiler compiler = new MockCompiler(
+      analyzeAll: analyzeAll, coreSource: coreSource);
   compiler.sourceFiles[uri.toString()] = new SourceFile(uri.toString(), code);
   return compiler;
 }
 
-String compileAll(String code) {
+String compileAll(String code, {String coreSource: DEFAULT_CORELIB}) {
   Uri uri = new Uri.fromComponents(scheme: 'source');
-  MockCompiler compiler = compilerFor(code, uri);
+  MockCompiler compiler = compilerFor(code, uri, coreSource: coreSource);
   compiler.runCompiler(uri);
   Expect.isFalse(compiler.compilationFailed,
                  'Unexpected compilation error');
diff --git a/tests/compiler/dart2js/interceptor_test.dart b/tests/compiler/dart2js/interceptor_test.dart
index c7be7c5..3a346e1 100644
--- a/tests/compiler/dart2js/interceptor_test.dart
+++ b/tests/compiler/dart2js/interceptor_test.dart
@@ -22,6 +22,16 @@
   }
 """;
 
+const String TEST_THREE = r"""
+  class A {
+    var length;
+  }
+  foo(a) {
+    print([]); // Make sure the array class is instantiated.
+    return new A().length + a.length;
+  }
+""";
+
 main() {
   var generated = compile(TEST_ONE, entry: 'foo');
   // Check that the one shot interceptor got converted to a direct
@@ -33,4 +43,12 @@
   generated = compile(TEST_TWO, entry: 'foo');
   Expect.isTrue(generated.contains('\$.\$\$add(a, 42)'));
   Expect.isTrue(generated.contains('myVariableName'));
+
+  // Check that an intercepted getter that does not need to be
+  // intercepted, is turned into a regular getter call or field
+  // access.
+  generated = compile(TEST_THREE, entry: 'foo');
+  Expect.isFalse(generated.contains(r'get$length'));
+  Expect.isTrue(generated.contains(r'$.A$().length'));
+  Expect.isTrue(generated.contains(r'length(a)'));
 }
diff --git a/tests/compiler/dart2js/literal_map_test.dart b/tests/compiler/dart2js/literal_map_test.dart
new file mode 100644
index 0000000..88be94d
--- /dev/null
+++ b/tests/compiler/dart2js/literal_map_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "compiler_helper.dart";
+
+const String TEST = """
+foo() {
+  var a = {};
+  var index = foo(); // Make sure we want to optimize this method.
+  while (true) a[index] = 1;
+}
+""";
+
+main() {
+  String generated = compile(TEST, entry: 'foo');
+  // Make sure we have all the type information we need.
+  Expect.isFalse(generated.contains('bailout'));
+  Expect.isFalse(generated.contains('interceptor'));
+  // Make sure we don't go through an interceptor.
+  Expect.isTrue(generated.contains('a.\$indexSet'));
+}
diff --git a/tests/compiler/dart2js/metadata_test.dart b/tests/compiler/dart2js/metadata_test.dart
index 79a0595..1591ebc 100644
--- a/tests/compiler/dart2js/metadata_test.dart
+++ b/tests/compiler/dart2js/metadata_test.dart
@@ -9,6 +9,22 @@
 
 import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/util/util.dart'
+    show Spannable, Link;
+import '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart'
+    show Node, LibraryTag;
+
+void checkPosition(Spannable spannable, Node node, String source, compiler) {
+  SourceSpan span = compiler.spanFromSpannable(spannable);
+  Expect.isTrue(span.begin < span.end,
+                'begin = ${span.begin}; end = ${span.end}');
+  Expect.isTrue(span.end < source.length,
+                'end = ${span.end}; length = ${source.length}');
+  String yield = source.substring(span.begin, span.end);
+
+  // TODO(ahe): The node does not include "@". Fix that.
+  Expect.stringEquals('@$node', yield);
+}
 
 void checkAnnotation(String name, String declaration,
                      {bool isTopLevelOnly: false}) {
@@ -24,10 +40,12 @@
   compileAndCheck(source, name, (compiler, element) {
     compiler.enqueuer.resolution.queueIsClosed = false;
     Expect.equals(1, length(element.metadata));
-    MetadataAnnotation annotation = element.metadata.head;
+    PartialMetadataAnnotation annotation = element.metadata.head;
     annotation.ensureResolved(compiler);
     Constant value = annotation.value;
     Expect.stringEquals('xyz', value.value.slowToString());
+
+    checkPosition(annotation, annotation.cachedNode, source, compiler);
   });
 
   // Ensure that each repeated annotation has a unique instance of
@@ -40,8 +58,8 @@
   compileAndCheck(source, name, (compiler, element) {
     compiler.enqueuer.resolution.queueIsClosed = false;
     Expect.equals(2, length(element.metadata));
-    MetadataAnnotation annotation1 = element.metadata.head;
-    MetadataAnnotation annotation2 = element.metadata.tail.head;
+    PartialMetadataAnnotation annotation1 = element.metadata.head;
+    PartialMetadataAnnotation annotation2 = element.metadata.tail.head;
     annotation1.ensureResolved(compiler);
     annotation2.ensureResolved(compiler);
     Expect.isFalse(identical(annotation1, annotation2),
@@ -52,6 +70,9 @@
     Expect.identical(value1, value2, 'expected same compile-time constant');
     Expect.stringEquals('xyz', value1.value.slowToString());
     Expect.stringEquals('xyz', value2.value.slowToString());
+
+    checkPosition(annotation1, annotation1.cachedNode, source, compiler);
+    checkPosition(annotation2, annotation2.cachedNode, source, compiler);
   });
 
   if (isTopLevelOnly) return;
@@ -72,10 +93,12 @@
     Expect.equals(0, length(element.metadata));
     element = element.lookupLocalMember(buildSourceString(name));
     Expect.equals(1, length(element.metadata));
-    MetadataAnnotation annotation = element.metadata.head;
+    PartialMetadataAnnotation annotation = element.metadata.head;
     annotation.ensureResolved(compiler);
     Constant value = annotation.value;
     Expect.stringEquals('xyz', value.value.slowToString());
+
+    checkPosition(annotation, annotation.cachedNode, source, compiler);
   });
 
   // Ensure that each repeated annotation has a unique instance of
@@ -94,8 +117,8 @@
     Expect.equals(0, length(element.metadata));
     element = element.lookupLocalMember(buildSourceString(name));
     Expect.equals(2, length(element.metadata));
-    MetadataAnnotation annotation1 = element.metadata.head;
-    MetadataAnnotation annotation2 = element.metadata.tail.head;
+    PartialMetadataAnnotation annotation1 = element.metadata.head;
+    PartialMetadataAnnotation annotation2 = element.metadata.tail.head;
     annotation1.ensureResolved(compiler);
     annotation2.ensureResolved(compiler);
     Expect.isFalse(identical(annotation1, annotation2),
@@ -106,6 +129,9 @@
     Expect.identical(value1, value2, 'expected same compile-time constant');
     Expect.stringEquals('xyz', value1.value.slowToString());
     Expect.stringEquals('xyz', value2.value.slowToString());
+
+    checkPosition(annotation1, annotation1.cachedNode, source, compiler);
+    checkPosition(annotation1, annotation2.cachedNode, source, compiler);
   });
 }
 
@@ -121,8 +147,74 @@
   checkAnnotation('foo', 'var foo;');
 }
 
+void testLibraryTags() {
+  void compileAndCheckLibrary(
+      String source,
+      Link<MetadataAnnotation> extractMetadata(LibraryElement element)) {
+    Uri partUri = new Uri.fromComponents(scheme: 'source', path: 'part.dart');
+    String partSource = '@native part of foo;';
+
+    Uri libUri = new Uri.fromComponents(scheme: 'source', path: 'lib.dart');
+    String libSource = 'library lib;';
+
+    Uri uri = new Uri.fromComponents(scheme: 'source', path: 'main.dart');
+
+    var compiler = compilerFor(source, uri)
+        ..registerSource(partUri, partSource)
+        ..registerSource(libUri, libSource)
+        ..runCompiler(uri);
+    compiler.enqueuer.resolution.queueIsClosed = false;
+    LibraryElement element = compiler.libraries['$uri'];
+    Expect.isNotNull(element, 'Cannot find $uri');
+
+    Link<MetadataAnnotation> metadata = extractMetadata(element);
+    Expect.equals(1, length(metadata));
+
+    PartialMetadataAnnotation annotation = metadata.head;
+    annotation.ensureResolved(compiler);
+    Constant value = annotation.value;
+    Expect.stringEquals('xyz', value.value.slowToString());
+
+    checkPosition(annotation, annotation.cachedNode, source, compiler);
+  }
+
+  var source;
+
+  source = """@native
+              library foo;
+              const native = 'xyz';
+              main() {}""";
+  compileAndCheckLibrary(source, (e) => e.libraryTag.metadata);
+
+  source = """@native
+              import 'lib.dart';
+              const native = 'xyz';
+              main() {}""";
+  compileAndCheckLibrary(source, (e) => e.tags.single.metadata);
+
+  source = """@native
+              export 'lib.dart';
+              const native = 'xyz';
+              main() {}""";
+  compileAndCheckLibrary(source, (e) => e.tags.single.metadata);
+
+  source = """@native
+              part 'part.dart';
+              const native = 'xyz';
+              main() {}""";
+  compileAndCheckLibrary(source, (e) => e.tags.single.metadata);
+
+  source = """@native
+              part 'part.dart';
+              const native = 'xyz';
+              main() {}""";
+  compileAndCheckLibrary(source,
+                         (e) => e.compilationUnits.first.partTag.metadata);
+}
+
 void main() {
   testClassMetadata();
   testTopLevelMethodMetadata();
   testTopLevelFieldMetadata();
+  testLibraryTags();
 }
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index b12336e..2ab105e 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -47,6 +47,9 @@
   boolConversionCheck(x) {}
   abstract class JavaScriptIndexingBehavior {}
   class JSInvocationMirror {}
+  class Closure {}
+  class Null {}
+  class Dynamic_ {}
   S() {}
   assertHelper(a){}
   throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) {}
@@ -62,6 +65,7 @@
   class JSString {
     var length;
     operator[](index) {}
+    toString() {}
   }
   class JSNumber {
     operator-() {}
@@ -111,9 +115,6 @@
   class Function {}
   class List<E> {}
   abstract class Map<K,V> {}
-  class Closure {}
-  class Null {}
-  class Dynamic_ {}
   bool identical(Object a, Object b) {}''';
 
 const String DEFAULT_ISOLATE_HELPERLIB = r'''
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 883ca27..272bf9d 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -44,7 +44,8 @@
                 bool expectIsPatch: false,
                 bool checkHasBody: false,
                 bool expectIsGetter: false,
-                bool expectIsFound: true}) {
+                bool expectIsFound: true,
+                bool expectIsRegular: false}) {
   var element = lookup(buildSourceString(name));
   if (!expectIsFound) {
     Expect.isNull(element);
@@ -86,7 +87,7 @@
   } else {
     Expect.isTrue(element.isDeclaration);
   }
-  if (!(element.isPatched || element.isPatch)) {
+  if (expectIsRegular) {
     Expect.isNull(element.origin);
     Expect.isNull(element.patch);
 
@@ -116,6 +117,43 @@
                 "Unexpected errors: ${compiler.errors}");
 }
 
+testPatchConstructor() {
+  var compiler = applyPatch(
+      """
+      class Class {
+        external Class();
+      }
+      """,
+      """
+      patch class Class {
+        patch Class();
+      }
+      """);
+  var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
+                           expectIsPatched: true);
+  classOrigin.ensureResolved(compiler);
+  var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+                          expectIsPatch: true);
+
+  Expect.equals(classPatch, classOrigin.patch);
+  Expect.equals(classOrigin, classPatch.origin);
+
+  var constructorOrigin = ensure(compiler, "Class",
+                                 (name) => classOrigin.localLookup(name),
+                                 expectIsPatched: true);
+  var constructorPatch = ensure(compiler, "Class",
+                                (name) => classPatch.localLookup(name),
+                                expectIsPatch: true);
+
+  Expect.equals(constructorPatch, constructorOrigin.patch);
+  Expect.equals(constructorOrigin, constructorPatch.origin);
+
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  Expect.isTrue(compiler.errors.isEmpty,
+                "Unexpected errors: ${compiler.errors}");
+}
+
 testPatchMember() {
   var compiler = applyPatch(
       """
@@ -197,9 +235,9 @@
          expectIsPatch: true);
 
   ensure(compiler, "regular", container.lookupLocalMember,
-         checkHasBody: true);
+         checkHasBody: true, expectIsRegular: true);
   ensure(compiler, "regular", container.patch.lookupLocalMember,
-         checkHasBody: true);
+         checkHasBody: true, expectIsRegular: true);
 
   Expect.isTrue(compiler.warnings.isEmpty,
                 "Unexpected warnings: ${compiler.warnings}");
@@ -227,7 +265,7 @@
   ensure(compiler, "ghost", container.lookupLocalMember,
          expectIsFound: false);
   ensure(compiler, "ghost", container.patch.lookupLocalMember,
-         checkHasBody: true);
+         checkHasBody: true, expectIsRegular: true);
 
   Expect.isTrue(compiler.warnings.isEmpty,
                 "Unexpected warnings: ${compiler.warnings}");
@@ -246,7 +284,7 @@
   ensure(compiler,
          "_function",
          compiler.coreLibrary.patch.find,
-         checkHasBody: true);
+         checkHasBody: true, expectIsRegular: true);
 
   Expect.isTrue(compiler.warnings.isEmpty,
                 "Unexpected warnings: ${compiler.warnings}");
@@ -380,7 +418,7 @@
   Expect.equals(1, compiler.errors.length);
   Expect.isTrue(
       compiler.errors[0].message.kind ==
-          MessageKind.EXTERNAL_WITHOUT_IMPLEMENTATION);
+          MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
   Expect.equals('External method without an implementation.',
                 compiler.errors[0].message.toString());
 }
@@ -411,12 +449,255 @@
   Expect.equals(1, compiler.errors.length);
   Expect.isTrue(
       compiler.errors[0].message.kind ==
-          MessageKind.EXTERNAL_WITHOUT_IMPLEMENTATION);
+          MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
   Expect.equals('External method without an implementation.',
                 compiler.errors[0].message.toString());
 }
 
+testIsSubclass() {
+  var compiler = applyPatch(
+      """
+      class A {}
+      """,
+      """
+      patch class A {}
+      """);
+  ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
+                            expectIsPatched: true);
+  ClassElement patch = cls.patch;
+  Expect.isTrue(cls != patch);
+  Expect.isTrue(cls.isSubclassOf(patch));
+  Expect.isTrue(patch.isSubclassOf(cls));
+}
+
+testPatchNonExistingTopLevel() {
+  var compiler = applyPatch(
+      """
+      // class Class {}
+      """,
+      """
+      patch class Class {}
+      """);
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  print('testPatchNonExistingTopLevel:${compiler.errors}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXISTING);
+}
+
+testPatchNonExistingMember() {
+  var compiler = applyPatch(
+      """
+      class Class {}
+      """,
+      """
+      patch class Class {
+        patch void foo() {}
+      }
+      """);
+  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+                         expectIsPatched: true);
+  container.parseNode(compiler);
+
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  print('testPatchNonExistingMember:${compiler.errors}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXISTING);
+}
+
+testPatchNonPatchablePatch() {
+  var compiler = applyPatch(
+      """
+      external get foo;
+      """,
+      """
+      patch var foo;
+      """);
+  ensure(compiler, "foo", compiler.coreLibrary.find);
+
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  print('testPatchNonPatchablePatch:${compiler.errors}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NONPATCHABLE);
+}
+
+testPatchNonPatchableOrigin() {
+  var compiler = applyPatch(
+      """
+      external var foo;
+      """,
+      """
+      patch get foo => 0;
+      """);
+  ensure(compiler, "foo", compiler.coreLibrary.find);
+
+  Expect.isTrue(compiler.warnings.isEmpty,
+                "Unexpected warnings: ${compiler.warnings}");
+  print('testPatchNonPatchableOrigin:${compiler.errors}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NONPATCHABLE);
+}
+
+testPatchNonExternalTopLevel() {
+  var compiler = applyPatch(
+      """
+      void foo() {}
+      """,
+      """
+      patch void foo() {}
+      """);
+  print('testPatchNonExternalTopLevel.errors:${compiler.errors}');
+  print('testPatchNonExternalTopLevel.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXTERNAL);
+  Expect.equals(1, compiler.warnings.length);
+  Expect.isTrue(
+      compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_FUNCTION);
+}
+
+testPatchNonExternalMember() {
+  var compiler = applyPatch(
+      """
+      class Class {
+        void foo() {}
+      }
+      """,
+      """
+      patch class Class {
+        patch void foo() {}
+      }
+      """);
+  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+                         expectIsPatched: true);
+  container.parseNode(compiler);
+
+  print('testPatchNonExternalMember.errors:${compiler.errors}');
+  print('testPatchNonExternalMember.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXTERNAL);
+  Expect.equals(1, compiler.warnings.length);
+  Expect.isTrue(
+      compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_FUNCTION);
+}
+
+testPatchNonClass() {
+  var compiler = applyPatch(
+      """
+      external void Class() {}
+      """,
+      """
+      patch class Class {}
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_CLASS);
+  Expect.equals(1, compiler.warnings.length);
+  Expect.isTrue(
+      compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_CLASS);
+}
+
+testPatchNonGetter() {
+  var compiler = applyPatch(
+      """
+      external void foo() {}
+      """,
+      """
+      patch get foo => 0;
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_GETTER);
+  Expect.equals(1, compiler.warnings.length);
+  Expect.isTrue(
+      compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_GETTER);
+}
+
+testPatchNoGetter() {
+  var compiler = applyPatch(
+      """
+      external set foo(var value) {}
+      """,
+      """
+      patch get foo => 0;
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NO_GETTER);
+  Expect.equals(1, compiler.warnings.length);
+  Expect.isTrue(
+      compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_GETTER);
+}
+
+testPatchNonSetter() {
+  var compiler = applyPatch(
+      """
+      external void foo() {}
+      """,
+      """
+      patch set foo(var value) {}
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_SETTER);
+  Expect.equals(1, compiler.warnings.length);
+  Expect.isTrue(
+      compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_SETTER);
+}
+
+testPatchNoSetter() {
+  var compiler = applyPatch(
+      """
+      external get foo;
+      """,
+      """
+      patch set foo(var value) {}
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NO_SETTER);
+  Expect.equals(1, compiler.warnings.length);
+  Expect.isTrue(
+      compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_SETTER);
+}
+
+testPatchNonFunction() {
+  var compiler = applyPatch(
+      """
+      external get foo;
+      """,
+      """
+      patch void foo() {}
+      """);
+  print('testPatchNonClass.errors:${compiler.errors}');
+  print('testPatchNonClass.warnings:${compiler.warnings}');
+  Expect.equals(1, compiler.errors.length);
+  Expect.isTrue(
+      compiler.errors[0].message.kind == MessageKind.PATCH_NON_FUNCTION);
+  Expect.equals(1, compiler.warnings.length);
+  Expect.isTrue(
+      compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_FUNCTION);
+}
+
 main() {
+  testPatchConstructor();
   testPatchFunction();
   testPatchMember();
   testPatchGetter();
@@ -427,4 +708,19 @@
 
   testExternalWithoutImplementationTopLevel();
   testExternalWithoutImplementationMember();
+
+  testIsSubclass();
+
+  testPatchNonExistingTopLevel();
+  testPatchNonExistingMember();
+  testPatchNonPatchablePatch();
+  testPatchNonPatchableOrigin();
+  testPatchNonExternalTopLevel();
+  testPatchNonExternalMember();
+  testPatchNonClass();
+  testPatchNonGetter();
+  testPatchNoGetter();
+  testPatchNonSetter();
+  testPatchNoSetter();
+  testPatchNonFunction();
 }
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index a2e3742..a8b08ed 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -35,7 +35,7 @@
     }
   }
   var definitions = new NodeList(null, new Link.fromList(locals), null, null);
-  return new VariableDefinitions(null, Modifiers.EMPTY, definitions, null);
+  return new VariableDefinitions(null, Modifiers.EMPTY, definitions);
 }
 
 testLocals(List variables) {
diff --git a/tests/compiler/dart2js/size_test.dart b/tests/compiler/dart2js/size_test.dart
new file mode 100644
index 0000000..d25c4b1
--- /dev/null
+++ b/tests/compiler/dart2js/size_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "mock_compiler.dart";
+import "compiler_helper.dart";
+
+const String TEST = "main() => [];";
+
+const String DEFAULT_CORELIB_WITH_LIST = r'''
+  class Object {}
+  class bool {}
+  abstract class List {}
+  class num {}
+  class int {}
+  class double {}
+  class String {}
+  class Function {}
+  class Type {}
+  class Map {}
+''';
+
+main() {
+  String generated = compileAll(TEST, coreSource: DEFAULT_CORELIB_WITH_LIST);
+  MockCompiler compiler = new MockCompiler();
+  var backend = compiler.backend;
+
+  // Make sure no class is emitted.
+  Expect.isFalse(generated.contains(backend.emitter.defineClassName));
+}
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index e51a50f..f69acf9 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -195,6 +195,73 @@
   analyze("${header}c.intTwoArgumentMethod(1, 2, 3); }",
           MessageKind.ADDITIONAL_ARGUMENT);
   // analyze("${header}c.untypedField(); }");
+
+  analyze("${header}c.intOneArgumentOneOptionalMethod(); }",
+          [MessageKind.MISSING_ARGUMENT]);
+  analyze("${header}c.intOneArgumentOneOptionalMethod(0); }");
+  analyze("${header}c.intOneArgumentOneOptionalMethod(0, 1); }");
+  analyze("${header}c.intOneArgumentOneOptionalMethod(0, 1, 2); }",
+          [MessageKind.ADDITIONAL_ARGUMENT]);
+  analyze("${header}c.intOneArgumentOneOptionalMethod(0, 1, c: 2); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+  analyze("${header}c.intOneArgumentOneOptionalMethod(0, b: 1); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+  analyze("${header}c.intOneArgumentOneOptionalMethod(a: 0, b: 1); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+           MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+           MessageKind.MISSING_ARGUMENT]);
+
+  analyze("${header}c.intTwoOptionalMethod(); }");
+  analyze("${header}c.intTwoOptionalMethod(0); }");
+  analyze("${header}c.intTwoOptionalMethod(0, 1); }");
+  analyze("${header}c.intTwoOptionalMethod(0, 1, 2); }",
+          [MessageKind.ADDITIONAL_ARGUMENT]);
+  analyze("${header}c.intTwoOptionalMethod(a: 0); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+  analyze("${header}c.intTwoOptionalMethod(0, b: 1); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+
+  analyze("${header}c.intOneArgumentOneNamedMethod(); }",
+          [MessageKind.MISSING_ARGUMENT]);
+  analyze("${header}c.intOneArgumentOneNamedMethod(0); }");
+  analyze("${header}c.intOneArgumentOneNamedMethod(0, b: 1); }");
+  analyze("${header}c.intOneArgumentOneNamedMethod(b: 1); }",
+          [MessageKind.MISSING_ARGUMENT]);
+  analyze("${header}c.intOneArgumentOneNamedMethod(0, b: 1, c: 2); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+  analyze("${header}c.intOneArgumentOneNamedMethod(0, 1); }",
+          [MessageKind.ADDITIONAL_ARGUMENT]);
+  analyze("${header}c.intOneArgumentOneNamedMethod(0, 1, c: 2); }",
+          [MessageKind.ADDITIONAL_ARGUMENT,
+           MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+  analyze("${header}c.intOneArgumentOneNamedMethod(a: 1, b: 1); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+           MessageKind.MISSING_ARGUMENT]);
+
+  analyze("${header}c.intTwoNamedMethod(); }");
+  analyze("${header}c.intTwoNamedMethod(a: 0); }");
+  analyze("${header}c.intTwoNamedMethod(b: 1); }");
+  analyze("${header}c.intTwoNamedMethod(a: 0, b: 1); }");
+  analyze("${header}c.intTwoNamedMethod(b: 1, a: 0); }");
+  analyze("${header}c.intTwoNamedMethod(0); }",
+          [MessageKind.ADDITIONAL_ARGUMENT]);
+  analyze("${header}c.intTwoNamedMethod(c: 2); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+  analyze("${header}c.intTwoNamedMethod(a: 0, c: 2); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+  analyze("${header}c.intTwoNamedMethod(a: 0, b: 1, c: 2); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+  analyze("${header}c.intTwoNamedMethod(c: 2, b: 1, a: 0); }",
+          [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+  analyze("${header}c.intTwoNamedMethod(0, b: 1); }",
+          [MessageKind.ADDITIONAL_ARGUMENT]);
+  analyze("${header}c.intTwoNamedMethod(0, 1); }",
+          [MessageKind.ADDITIONAL_ARGUMENT,
+           MessageKind.ADDITIONAL_ARGUMENT]);
+  analyze("${header}c.intTwoNamedMethod(0, c: 2); }",
+          [MessageKind.ADDITIONAL_ARGUMENT,
+           MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+
 }
 
 void testMethodInvocations() {
@@ -514,6 +581,11 @@
   int intOneArgumentMethod(int argument) {}
   int intTwoArgumentMethod(int argument1, int argument2) {}
 
+  void intOneArgumentOneOptionalMethod(int a, [int b]) {}
+  void intTwoOptionalMethod([int a, int b]) {}
+  void intOneArgumentOneNamedMethod(int a, {int b}) {}
+  void intTwoNamedMethod({int a, int b}) {}
+
   Function functionField;
   var untypedField;
   int intField;
diff --git a/tests/compiler/dart2js/unparser_test.dart b/tests/compiler/dart2js/unparser_test.dart
index cecb766..ee7b710 100644
--- a/tests/compiler/dart2js/unparser_test.dart
+++ b/tests/compiler/dart2js/unparser_test.dart
@@ -304,6 +304,43 @@
   testUnparseTopLevelWithMetadata('typedef C = S with M1,M2<A,B>;');
 }
 
+testUnparseParameters(List<String> variableDeclarations) {
+  var sb = new StringBuffer();
+  sb.add('Constructor(');
+  int index = 0;
+  for (String variableDeclaration in variableDeclarations) {
+    if (index != 0) {
+      sb.add(', ');
+    }
+    sb.add(variableDeclaration);
+    index++;
+  }
+  sb.add(');');
+
+  FunctionExpression node = parseMember(sb.toString());
+  index = 0;
+  for (VariableDefinitions parameter in node.parameters.nodes) {
+    Expect.equals(variableDeclarations[index], unparse(parameter));
+    index++;
+  }
+
+}
+
+testParameters() {
+  testUnparseParameters(
+      ["foo", "bar=0", "int baz", "int boz=0"]);
+  testUnparseParameters(
+      ["this.foo", "this.bar=0", "int this.baz", "int this.boz=0"]);
+  testUnparseParameters(
+      ["foo()", "void bar()", "int baz(a)", "int boz(int a,int b)=null"]);
+  testUnparseParameters(
+      ["this.foo()",
+       //"void this.bar()", // Commented out due to Issue 7852
+       //"int this.baz(a)", // Commented out due to Issue 7852
+       //"int this.boz(int a,int b)=null" // Commented out due to Issue 7852
+       ]);
+}
+
 main() {
   testSignedConstants();
   testGenericTypes();
@@ -324,4 +361,5 @@
   testRedirectingFactoryConstructors();
   testClassDeclarations();
   testMixinApplications();
+  testParameters();
 }
diff --git a/tests/corelib/hidden_library2_test.dart b/tests/corelib/hidden_library2_test.dart
new file mode 100644
index 0000000..d47aca7
--- /dev/null
+++ b/tests/corelib/hidden_library2_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test that the internal hidden library doesn't make problems with taking
+// stack-traces.
+
+main() {
+  print(['x'].where((_) {
+    // We actually don't really care for the successful case. We just want to
+    // make sure that the test doesn't crash when it is negative.
+    throw 'fisk';  /// 1: runtime error
+    return true;
+  }));
+}
diff --git a/tests/corelib/iterable_expand_test.dart b/tests/corelib/iterable_expand_test.dart
new file mode 100644
index 0000000..67aaf5b
--- /dev/null
+++ b/tests/corelib/iterable_expand_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+main() {
+  test(expectation, iterable) {
+    Expect.listEquals(expectation, iterable.toList());
+  }
+
+  // Function not called on empty iterable.
+  test([], [].expand((x) { throw "not called"; }));
+
+  // Creating the iterable doesn't call the function.
+  [1].expand((x) { throw "not called"; });
+
+  test([1], [1].expand((x) => [x]));
+  test([1, 2, 3], [1, 2, 3].expand((x) => [x]));
+
+  test([], [1].expand((x) => []));
+  test([], [1, 2, 3].expand((x) => []));
+  test([2], [1, 2, 3].expand((x) => x == 2 ? [2] : []));
+
+  test([1, 1, 2, 2, 3, 3], [1, 2, 3].expand((x) => [x, x]));
+  test([1, 1, 2], [1, 2, 3].expand((x) => [x, x, x].skip(x)));
+
+  // if function throws, iteration is stopped.
+  Iterable iterable = [1, 2, 3].expand((x) {
+    if (x == 2) throw "FAIL";
+    return [x, x];
+  });
+  Iterator it = iterable.iterator;
+  Expect.isTrue(it.moveNext());
+  Expect.equals(1, it.current);
+  Expect.isTrue(it.moveNext());
+  Expect.equals(1, it.current);
+  Expect.throws(it.moveNext, (e) => e == "FAIL");
+  // After throwing, iteration is ended.
+  Expect.equals(null, it.current);
+  Expect.isFalse(it.moveNext());
+}
diff --git a/tests/corelib/stopwatch_test.dart b/tests/corelib/stopwatch_test.dart
index b688ab3..2b9c1a6 100644
--- a/tests/corelib/stopwatch_test.dart
+++ b/tests/corelib/stopwatch_test.dart
@@ -8,7 +8,9 @@
 
 class StopwatchTest {
   static bool checkTicking(Stopwatch sw) {
+    Expect.isFalse(sw.isRunning);
     sw.start();
+    Expect.isTrue(sw.isRunning);
     for (int i = 0; i < 10000; i++) {
       int.parse(i.toString());
       if (sw.elapsedTicks > 0) {
@@ -20,10 +22,12 @@
 
   static bool checkStopping(Stopwatch sw) {
     sw.stop();
+    Expect.isFalse(sw.isRunning);
     int v1 = sw.elapsedTicks;
     Expect.isTrue(v1 > 0);  // Expect a non-zero elapsed time.
     Stopwatch sw2 = new Stopwatch();  // Used for verification.
     sw2.start();
+    Expect.isTrue(sw2.isRunning);
     int sw2LastElapsed = 0;
     for (int i = 0; i < 100000; i++) {
       int.parse(i.toString());
@@ -46,7 +50,9 @@
 
   static checkRestart() {
     Stopwatch sw = new Stopwatch();
+    Expect.isFalse(sw.isRunning);
     sw.start();
+    Expect.isTrue(sw.isRunning);
     for (int i = 0; i < 100000; i++) {
       int.parse(i.toString());
       if (sw.elapsedTicks > 0) {
@@ -54,8 +60,10 @@
       }
     }
     sw.stop();
+    Expect.isFalse(sw.isRunning);
     int initial = sw.elapsedTicks;
     sw.start();
+    Expect.isTrue(sw.isRunning);
     for (int i = 0; i < 100000; i++) {
       int.parse(i.toString());
       if (sw.elapsedTicks > initial) {
@@ -63,12 +71,15 @@
       }
     }
     sw.stop();
+    Expect.isFalse(sw.isRunning);
     Expect.isTrue(sw.elapsedTicks > initial);
   }
 
   static checkReset() {
     Stopwatch sw = new Stopwatch();
+    Expect.isFalse(sw.isRunning);
     sw.start();
+    Expect.isTrue(sw.isRunning);
     for (int i = 0; i < 100000; i++) {
       int.parse(i.toString());
       if (sw.elapsedTicks > 0) {
@@ -76,9 +87,12 @@
       }
     }
     sw.stop();
+    Expect.isFalse(sw.isRunning);
     sw.reset();
+    Expect.isFalse(sw.isRunning);
     Expect.equals(0, sw.elapsedTicks);
     sw.start();
+    Expect.isTrue(sw.isRunning);
     for (int i = 0; i < 100000; i++) {
       int.parse(i.toString());
       if (sw.elapsedTicks > 0) {
@@ -86,6 +100,7 @@
       }
     }
     sw.reset();
+    Expect.isTrue(sw.isRunning);
     for (int i = 0; i < 100000; i++) {
       int.parse(i.toString());
       if (sw.elapsedTicks > 0) {
@@ -93,6 +108,7 @@
       }
     }
     sw.stop();
+    Expect.isFalse(sw.isRunning);
     Expect.isTrue(sw.elapsedTicks > 0);
   }
 
diff --git a/tests/html/cdata_test.dart b/tests/html/cdata_test.dart
new file mode 100644
index 0000000..b23a397
--- /dev/null
+++ b/tests/html/cdata_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+library cdata_test;
+import '../../pkg/unittest/lib/unittest.dart';
+import '../../pkg/unittest/lib/html_config.dart';
+import 'dart:html';
+
+
+main() {
+  useHtmlConfiguration();
+
+  test('remove', () {
+    var div = new Element.html('<div>content</div>');
+    var cdata = div.nodes[0];
+    expect(cdata is CharacterData, true);
+    expect(cdata, isNotNull);
+    expect(div.innerHtml, 'content');
+
+    cdata.remove();
+    expect(div.innerHtml, '');
+  });
+}
diff --git a/tests/html/indexeddb_1_test.dart b/tests/html/indexeddb_1_test.dart
index 92eef20..eac993f 100644
--- a/tests/html/indexeddb_1_test.dart
+++ b/tests/html/indexeddb_1_test.dart
@@ -39,8 +39,9 @@
   step1() {
     var transaction = db.transaction([storeName], 'readwrite');
     var request = transaction.objectStore(storeName).put(value, key);
-    request.onSuccess.listen(expectAsync1(step2));
     request.onError.listen(fail);
+
+    transaction.onComplete.listen(expectAsync1(step2));
   }
 
   initDb(e) {
@@ -115,8 +116,9 @@
   step1() {
     idb.Transaction transaction = db.transaction([storeName], 'readwrite');
     idb.Request request = transaction.objectStore(storeName).put(value, key);
-    request.onSuccess.listen(expectAsync1(step2));
     request.onError.listen(fail);
+
+    transaction.onComplete.listen(expectAsync1(step2));
   }
 
   initDb(e) {
diff --git a/tests/html/indexeddb_2_test.dart b/tests/html/indexeddb_2_test.dart
index 66fef6c..b5053c9 100644
--- a/tests/html/indexeddb_2_test.dart
+++ b/tests/html/indexeddb_2_test.dart
@@ -43,8 +43,9 @@
   step1() {
     var transaction = db.transaction([storeName], 'readwrite');
     var request = transaction.objectStore(storeName).put(value, key);
-    request.onSuccess.listen(expectAsync1(step2));
     request.onError.listen(fail);
+
+    transaction.onComplete.listen(expectAsync1(step2));
   }
 
   initDb(e) {
diff --git a/tests/isolate/count_test.dart b/tests/isolate/count_test.dart
index 7ad82d6..2010c88 100644
--- a/tests/isolate/count_test.dart
+++ b/tests/isolate/count_test.dart
@@ -46,7 +46,7 @@
       if (count == 10) {
         remote.send(-1, reply);
       }
-    }, 11));
+    }, count: 11));
     remote.send(count++, reply);
   });
 }
diff --git a/tests/language/import_private_test.dart b/tests/language/import_private_test.dart
new file mode 100644
index 0000000..e269c7a
--- /dev/null
+++ b/tests/language/import_private_test.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Check that private dart:_ libraries cannot be imported.
+
+import "dart:_collection-dev";  /// 01: compile-time error
+
+main() {
+  print("Done.");
+}
diff --git a/tests/language/invocation_mirror_invoke_on2_test.dart b/tests/language/invocation_mirror_invoke_on2_test.dart
new file mode 100644
index 0000000..b8bec8a
--- /dev/null
+++ b/tests/language/invocation_mirror_invoke_on2_test.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Proxy {
+  final proxied;
+  Proxy(this.proxied);
+  noSuchMethod(mirror) => mirror.invokeOn(proxied);
+}
+
+main() {
+  testList();
+  testString();
+  testInt();
+  testDouble();
+}
+
+testList() {
+  var list = [];
+  var proxy = new Proxy(list);
+
+  Expect.isTrue(proxy.isEmpty);
+  Expect.isTrue(list.isEmpty);
+
+  proxy.add(42);
+
+  Expect.isFalse(proxy.isEmpty);
+  Expect.equals(1, proxy.length);
+  Expect.equals(42, proxy[0]);
+
+  Expect.isFalse(list.isEmpty);
+  Expect.equals(1, list.length);
+  Expect.equals(42, list[0]);
+
+  proxy.add(87);
+
+  Expect.equals(2, proxy.length);
+  Expect.equals(87, proxy[1]);
+
+  Expect.equals(2, list.length);
+  Expect.equals(87, list[1]);
+
+  Expect.throws(() => proxy.funky(), (e) => e is NoSuchMethodError);
+  Expect.throws(() => list.funky(), (e) => e is NoSuchMethodError);
+}
+
+testString() {
+  var string = "funky";
+  var proxy = new Proxy(string);
+
+  Expect.equals(string.charCodeAt(0), proxy.charCodeAt(0));
+  Expect.equals(string.length, proxy.length);
+
+  Expect.throws(() => proxy.funky(), (e) => e is NoSuchMethodError);
+  Expect.throws(() => string.funky(), (e) => e is NoSuchMethodError);
+}
+
+testInt() {
+  var number = 42;
+  var proxy = new Proxy(number);
+
+  Expect.equals(number + 87, proxy + 87);
+  Expect.equals(number.toDouble(), proxy.toDouble());
+
+  Expect.throws(() => proxy.funky(), (e) => e is NoSuchMethodError);
+  Expect.throws(() => number.funky(), (e) => e is NoSuchMethodError);
+}
+
+testDouble() {
+  var number = 42.99;
+  var proxy = new Proxy(number);
+
+  Expect.equals(number + 87, proxy + 87);
+  Expect.equals(number.toInt(), proxy.toInt());
+
+  Expect.throws(() => proxy.funky(), (e) => e is NoSuchMethodError);
+  Expect.throws(() => number.funky(), (e) => e is NoSuchMethodError);
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 85b14a8..9ffdffd 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -104,6 +104,7 @@
 
 [ $compiler == dartc ]
 class_literal_test/none : Fail # Issue 7630.
+import_private_test/01: Fail # Issue 8365.
 
 # test issue 7749
 list_literal1_negative_test: Fail
diff --git a/tests/language/null_no_such_method_test.dart b/tests/language/null_no_such_method_test.dart
new file mode 100644
index 0000000..adfab89
--- /dev/null
+++ b/tests/language/null_no_such_method_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+var array = [1];
+
+main() {
+  Expect.throws(() => -null, (e) => e is NoSuchMethodError);
+  // Make sure we have an untyped call to operator-.
+  print(-array[0]);
+}
diff --git a/tests/language/private_selector_lib.dart b/tests/language/private_selector_lib.dart
new file mode 100644
index 0000000..c9a11c9
--- /dev/null
+++ b/tests/language/private_selector_lib.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library private_selector_lib;
+
+import 'private_selector_test.dart';
+
+bool executed = false;
+
+class A {
+  public() {
+    new B()._private();
+  }
+
+  _private() {
+    executed = true;
+  }
+}
diff --git a/tests/language/private_selector_test.dart b/tests/language/private_selector_test.dart
new file mode 100644
index 0000000..53dca839
--- /dev/null
+++ b/tests/language/private_selector_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library private_selector_test;
+
+import 'private_selector_lib.dart';
+
+class B extends A {
+}
+
+main() {
+  new A().public();
+  Expect.isTrue(executed);
+}
diff --git a/tests/language/reg_exp3_test.dart b/tests/language/reg_exp3_test.dart
index 0ac8064..b0410ed 100644
--- a/tests/language/reg_exp3_test.dart
+++ b/tests/language/reg_exp3_test.dart
@@ -9,7 +9,7 @@
     try {
       RegExp exp = new RegExp("[");
       i = 100;  // Should not reach here.
-    } on IllegalJSRegExpException catch (e) {
+    } on FormatException catch (e) {
       i = 0;
     }
     Expect.equals(0, i);
diff --git a/tests/lib/async/event_helper.dart b/tests/lib/async/event_helper.dart
index e6816e6..c8a3cb2 100644
--- a/tests/lib/async/event_helper.dart
+++ b/tests/lib/async/event_helper.dart
@@ -72,7 +72,7 @@
   factory Events.capture(Stream stream,
                          { bool unsubscribeOnError: false }) = CaptureEvents;
 
-  // Sink interface.
+  // StreamSink interface.
   add(var value) { events.add(new DataEvent(value)); }
 
   void signalError(AsyncError error) {
diff --git a/tests/lib/async/stream_transform_test.dart b/tests/lib/async/stream_transform_test.dart
new file mode 100644
index 0000000..436c229
--- /dev/null
+++ b/tests/lib/async/stream_transform_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2011, 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 stream_transform_test;
+
+import 'dart:async';
+import '../../../pkg/unittest/lib/unittest.dart';
+import 'event_helper.dart';
+
+
+main() {
+  // Regression tests for http://dartbug.com/8311
+
+  test("simpleDone", () {
+    StreamController c = new StreamController();
+    Stream out = c.stream.handleError((x){}).handleError((x){});
+    out.listen((v){}, onDone: expectAsync0(() {}));
+    // Should not throw.
+    c.close();
+  });
+
+  test("with events", () {
+    StreamController c = new StreamController();
+    Events expected = new Events.fromIterable([10, 12]);
+    Events input = new Events.fromIterable([1, 2, 3, 4, 5, 6, 7]);
+    Events actual = new Events.capture(
+        c.stream.map((x) => x * 2).where((x) => x > 5).skip(2).take(2));
+    actual.onDone(expectAsync0(() {
+      Expect.listEquals(expected.events, actual.events);
+    }));
+    input.replay(c);
+  });
+
+  test("paused events", () {
+    StreamController c = new StreamController();
+    Events expected = new Events.fromIterable([10, 12]);
+    Events input = new Events.fromIterable([1, 2, 3, 4, 5, 6, 7]);
+    Events actual = new Events.capture(
+        c.stream.map((x) => x * 2).where((x) => x > 5).skip(2).take(2));
+    actual.onDone(expectAsync0(() {
+      Expect.listEquals(expected.events, actual.events);
+    }));
+    actual.pause();
+    input.replay(c);
+    actual.resume();
+  });
+}
diff --git a/tests/standalone/pow_test.dart b/tests/standalone/pow_test.dart
new file mode 100644
index 0000000..02ad5a3
--- /dev/null
+++ b/tests/standalone/pow_test.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Dart test program for testing math's pow.
+
+library pow_test;
+
+import 'dart:math';
+
+var expectedResults =
+[
+  1,
+  2,
+  4,
+  8,
+  16,
+  32,
+  64,
+  128,
+  256,
+  512,
+  1024,
+  2048,
+  4096,
+  8192,
+  16384,
+  32768,
+  65536,
+  131072,
+  262144,
+  524288,
+  1048576,
+  2097152,
+  4194304,
+  8388608,
+  16777216,
+  33554432,
+  67108864,
+  134217728,
+  268435456,
+  536870912,
+  1073741824,
+  2147483648,
+  4294967296,
+  8589934592,
+  17179869184,
+  34359738368,
+  68719476736,
+  137438953472,
+  274877906944,
+  549755813888,
+  1099511627776,
+  2199023255552,
+  4398046511104,
+  8796093022208,
+  17592186044416,
+  35184372088832,
+  70368744177664,
+  140737488355328,
+  281474976710656,
+  562949953421312,
+  1125899906842624,
+  2251799813685248,
+  4503599627370496,
+  9007199254740992,
+  18014398509481984,
+  36028797018963968,
+  72057594037927936,
+  144115188075855872,
+  288230376151711744,
+  576460752303423488,
+  1152921504606846976,
+  2305843009213693952,
+  4611686018427387904,
+  9223372036854775808,
+  18446744073709551616,
+  36893488147419103232,
+  73786976294838206464,
+  147573952589676412928
+];
+
+
+void main() {
+  int exp = 0;
+  for (int val in expectedResults) {
+    Expect.equals(val, pow(2, exp++));
+  }
+  // Optimize it.
+  for (int i = 0; i < 8888; i++) {
+    pow(2, 3);
+  }
+  exp = 0;
+  for (int val in expectedResults) {
+    Expect.equals(val, pow(2, exp++));
+  }
+}
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart
index 5bd9dce..696713c 100644
--- a/tests/utils/dummy_compiler_test.dart
+++ b/tests/utils/dummy_compiler_test.dart
@@ -48,6 +48,7 @@
                     var length;
                     var split;
                     var concat;
+                    var toString;
                   }
                   class JSFunction {}
                   class JSInt {}
diff --git a/tools/VERSION b/tools/VERSION
index 6e24da0..da7071a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 3
-BUILD 4
+BUILD 5
 PATCH 0
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 28882b9..a8df879 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -25,7 +25,7 @@
 # ......_internal/
 # ......async/
 # ......collection/
-# ......collection_dev/
+# ......_collection_dev/
 # ......core/
 # ......crypto/
 # ......html/
@@ -199,7 +199,7 @@
   #
 
   os.makedirs(join(LIB, 'html'))
-  for library in ['_internal', 'async', 'collection', 'collection_dev', 'core',
+  for library in ['_internal', 'async', 'collection', '_collection_dev', 'core',
                   'crypto', 'io', 'isolate',
                   join('chrome', 'dart2js'), join('chrome', 'dartium'),
                   join('html', 'dart2js'), join('html', 'dartium'),
diff --git a/tools/dom/scripts/htmleventgenerator.py b/tools/dom/scripts/htmleventgenerator.py
index 4fd609b..a05dd1b 100644
--- a/tools/dom/scripts/htmleventgenerator.py
+++ b/tools/dom/scripts/htmleventgenerator.py
@@ -301,7 +301,7 @@
   'HTMLMediaElement.webkitkeyerror': ('keyError', 'MediaKeyEvent'),
   'HTMLMediaElement.webkitkeymessage': ('keyMessage', 'MediaKeyEvent'),
   'HTMLMediaElement.webkitneedkey': ('needKey', 'MediaKeyEvent'),
-  'IDBDatabase.versionchange': ('versionChange', 'UpgradeNeededEvent'),
+  'IDBDatabase.versionchange': ('versionChange', 'VersionChangeEvent'),
   'IDBOpenDBRequest.blocked': ('blocked', 'Event'),
   'IDBOpenDBRequest.upgradeneeded': ('upgradeNeeded', 'VersionChangeEvent'),
   'IDBRequest.success': ('success', 'Event'),
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 69b90af..bdc24fe 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -31,7 +31,6 @@
     'WebKitCSSMatrix': 'CssMatrix',
     'WebKitCSSTransformValue': 'CssTransformValue',
     'WebKitPoint': 'DomPoint',
-    'WebKitTransitionEvent': 'TransitionEvent',
     'XMLHttpRequest': 'HttpRequest',
     'XMLHttpRequestException': 'HttpRequestException',
     'XMLHttpRequestProgressEvent': 'HttpRequestProgressEvent',
@@ -231,6 +230,7 @@
     'CanvasRenderingContext2D.setMiterLimit',
     'CanvasRenderingContext2D.setShadow',
     'CanvasRenderingContext2D.setStrokeColor',
+    'CharacterData.remove',
     'DOMWindow.call:blur',
     'DOMWindow.clientInformation',
     'DOMWindow.call:focus',
diff --git a/tools/dom/src/CssClassSet.dart b/tools/dom/src/CssClassSet.dart
index c688181..d018108 100644
--- a/tools/dom/src/CssClassSet.dart
+++ b/tools/dom/src/CssClassSet.dart
@@ -50,13 +50,15 @@
 
   Iterable<String> where(bool f(String element)) => readClasses().where(f);
 
+  Iterable expand(Iterable f(String element)) => readClasses.expand(f);
+
   bool every(bool f(String element)) => readClasses().every(f);
 
   bool any(bool f(String element)) => readClasses().any(f);
 
   bool get isEmpty => readClasses().isEmpty;
 
-  int get length =>readClasses().length;
+  int get length => readClasses().length;
 
   dynamic reduce(dynamic initialValue,
       dynamic combine(dynamic previousValue, String element)) {
diff --git a/tools/dom/templates/html/impl/impl_DOMException.darttemplate b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
index 593fd4c..caba0d2 100644
--- a/tools/dom/templates/html/impl/impl_DOMException.darttemplate
+++ b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
@@ -4,8 +4,7 @@
 
 part of $LIBRARYNAME;
 
-/// @domName $DOMNAME
-class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
 
   static const String INDEX_SIZE = 'IndexSizeError';
   static const String HIERARCHY_REQUEST = 'HierarchyRequestError';
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index c47ffe1..890938e 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -73,6 +73,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(Element element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   bool get isEmpty {
     return _element.$dom_firstElementChild == null;
   }
@@ -290,6 +294,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(Element element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   bool every(bool f(Element element)) {
     for(Element element in this) {
       if (!f(element)) {
diff --git a/tools/dom/templates/html/impl/impl_MediaStream.darttemplate b/tools/dom/templates/html/impl/impl_MediaStream.darttemplate
index 9691338..7b62c0c 100644
--- a/tools/dom/templates/html/impl/impl_MediaStream.darttemplate
+++ b/tools/dom/templates/html/impl/impl_MediaStream.darttemplate
@@ -4,8 +4,7 @@
 
 part of $LIBRARYNAME;
 
-/// @domName $DOMNAME; @docsEditable true$ANNOTATIONS
-class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
 $!MEMBERS
 
   /**
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate
index 63d0e49..5f3a0c9 100644
--- a/tools/dom/templates/html/impl/impl_Node.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -150,6 +150,10 @@
     return IterableMixinWorkaround.where(this, f);
   }
 
+  Iterable expand(Iterable f(Node element)) {
+    return IterableMixinWorkaround.expand(this, f);
+  }
+
   bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
diff --git a/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate b/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate
index 078d873..1b75464 100644
--- a/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate
+++ b/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate
@@ -69,6 +69,11 @@
    * * The `Access-Control-Allow-Credentials` header of `url` must be set to true.
    * * If `Access-Control-Expose-Headers` has not been set to true, only a subset of all the response headers will be returned when calling [getAllRequestHeaders].
    *
+   * Note that requests for file:// URIs are only supported by Chrome extensions
+   * with appropriate permissions in their manifest. Requests to file:// URIs
+   * will also never fail- the Future will always complete successfully, even
+   * when the file cannot be found.
+   *
    * See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access_authentication).
    */
   static Future<HttpRequest> request(String url,
@@ -95,8 +100,9 @@
     }
 
     xhr.onLoad.listen((e) {
-      if (xhr.status >= 200 && xhr.status < 300 ||
-          xhr.status == 304 ) {
+      // Note: file:// URIs have status of 0.
+      if ((xhr.status >= 200 && xhr.status < 300) ||
+          xhr.status == 0 || xhr.status == 304) {
         completer.complete(xhr);
       } else {
         completer.completeError(e);
diff --git a/tools/dom/templates/immutable_list_mixin.darttemplate b/tools/dom/templates/immutable_list_mixin.darttemplate
index 77fdd0d..2c8bf68 100644
--- a/tools/dom/templates/immutable_list_mixin.darttemplate
+++ b/tools/dom/templates/immutable_list_mixin.darttemplate
@@ -38,6 +38,9 @@
   Iterable<$E> where(bool f($E element)) =>
       IterableMixinWorkaround.where(this, f);
 
+  Iterable expand(Iterable f($E element)) =>
+      IterableMixinWorkaround.expand(this, f);
+
   bool every(bool f($E element)) => IterableMixinWorkaround.every(this, f);
 
   bool any(bool f($E element)) => IterableMixinWorkaround.any(this, f);
diff --git a/tools/html_json_doc/bin/html_json_doc.dart b/tools/html_json_doc/bin/html_json_doc.dart
deleted file mode 100644
index c37d302..0000000
--- a/tools/html_json_doc/bin/html_json_doc.dart
+++ /dev/null
@@ -1,69 +0,0 @@
-// 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.
-
-/**
- * TODO(amouravski): Document stuff here.
- */
-
-import 'dart:io';
-
-import '../lib/html_to_json.dart' as html_to_json;
-import '../lib/json_to_html.dart' as json_to_html;
-import '../../../pkg/args/lib/args.dart';
-
-// Need this because ArgParser.getUsage doesn't show command invocation.
-const USAGE = 'Usage htmlJsonDoc [options] --mode=<mode> <HTML.dart directory> '
-    '<json path>\n[options] include:';
-final argParser = new ArgParser();
-
-main() {
-  final args = new Options().arguments;
-
-  if (args.isEmpty) {
-    printUsage('No arguments provided.');
-    return;
-  }
-
-  var mode;
-  argParser.addOption('mode', abbr: 'm',
-      help: '(Required) Convert from HTML docs to JSON or vice versa.',
-      allowed: ['html-to-json', 'json-to-html'], allowedHelp: {
-        'html-to-json': 'Processes all HTML .dart files at given\n'
-          'location and outputs JSON.',
-          'json-to-html': 'Takes JSON file at location and inserts docs into\n'
-      'HTML .dart files.'},
-      callback: (m) => mode = m
-  );
-
-  final argResults = argParser.parse(args);
-
-  if (mode == null) {
-    printUsage('Mode is a required option.');
-    return;
-  } else if (argResults.rest.length < 2) {
-    printUsage('Insufficient arguments.');
-    return;
-  }
-
-  var htmlPath = new Path(argResults.rest[0]);
-  var jsonPath = new Path(argResults.rest[1]);
-
-  var convertFuture;
-  if (mode == 'html-to-json') {
-    convertFuture = html_to_json.convert(htmlPath, jsonPath);
-  } else {
-    convertFuture = json_to_html.convert(htmlPath, jsonPath);
-  }
-
-  convertFuture.then((anyErrors) {
-    print('Completed ${anyErrors ? "with" : "without"} errors.');
-  });
-}
-
-/// Prints the usage of the tool. [message] is printed if provided.
-void printUsage([String message]) {
-  print(message);
-  print(USAGE);
-  print(argParser.getUsage());
-}
diff --git a/tools/html_json_doc/lib/html_to_json.dart b/tools/html_json_doc/lib/html_to_json.dart
deleted file mode 100644
index 2013640..0000000
--- a/tools/html_json_doc/lib/html_to_json.dart
+++ /dev/null
@@ -1,318 +0,0 @@
-// 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 for extracting the documentation comments from files generated by
- * the HTML library. The comments are stored in a JSON file.
- *
- * Comments must be in either the block style with leading *s:
- *
- *     /**
- *      * Comment here.
- *      */
- *
- * Or the triple-slash style:
- *
- *     /// Docs go here.
- *     /// And here.
- *
- * Each member that is to be documented should be preceeded by a meta-comment
- * containing the string `@docsEditable` such as:
- *
- *     /// @docsEditable
- */
-library html_to_json;
-
-import 'dart:json';
-import 'dart:io';
-import 'dart:async';
-
-
-/// True if any errors were triggered through the conversion.
-bool _anyErrors = false;
-
-
-/**
- * Convert files on [htmlPath] and write JSON to [jsonPath].
- */
-Future<bool> convert(Path htmlPath, Path jsonPath) {
-  var completer = new Completer();
-
-  // TODO(amouravski): make this transform once I know what I want this file to
-  // return.
-  _convertFiles(htmlPath).then((convertedJson) {
-    final jsonFile = new File.fromPath(jsonPath);
-    var writeJson = convertedJson;
-
-    if (jsonFile.existsSync()) {
-      writeJson = _mergeJsonAndFile(convertedJson, jsonFile);
-    }
-
-    var outputStream = jsonFile.openOutputStream();
-    outputStream.writeString(prettyPrintJson(writeJson));
-
-    outputStream.onNoPendingWrites = () {
-      completer.complete(_anyErrors);
-    };
-
-    outputStream.onClosed = () {
-      completer.complete(_anyErrors);
-    };
-
-    outputStream.onError = completer.completeError;
-  });
-
-  return completer.future;
-}
-
-
-/**
- * Convert all files on [htmlPath].
- *
- * Returns a future that completes to the converted JSON object.
- */
-Future<Object> _convertFiles(Path htmlPath) {
-  var completer = new Completer();
-
-  List<Future> fileFutures = [];
-
-  // Get a list of all HTML dart files.
-  // TODO(amouravski): discriminate .dart files.
-  final htmlDir = new Directory.fromPath(htmlPath);
-  final lister = htmlDir.list(recursive: false);
-
-  lister.onFile = (String path) {
-    final name = new Path(path).filename;
-
-    // Ignore private classes.
-    if (name.startsWith('_')) return;
-
-    // Ignore non-dart files.
-    if (!name.endsWith('.dart')) return;
-
-    File file = new File(path);
-
-    // TODO(amouravski): Handle missing file.
-    if (!file.existsSync()) {
-      print('ERROR: cannot find file $path');
-      _anyErrors = true;
-      return;
-    }
-
-    fileFutures.add(_convertFile(file));
-  };
-
-
-  // Combine all JSON objects
-  lister.onDone = (_) {
-    Futures.wait(fileFutures).then((jsonList) {
-      var convertedJson = {};
-      jsonList.forEach((json) {
-        final k = json.keys[0];
-        convertedJson.putIfAbsent(k, () => json[k]);
-      });
-      completer.complete(convertedJson);
-    });
-  };
-
-  // TODO(amouravski): add more error handling.
-
-  return completer.future;
-}
-
-
-/**
- * Convert a single file to JSON docs.
- *
- * Returns a map with one entry whose key is the file name and whose value is
- * the list of comment lines.
- */
-Future<Map> _convertFile(File file) {
-  var completer = new Completer();
-
-  var comments = {};
-
-  // Find all /// @docsEditable annotations.
-  InputStream file_stream = file.openInputStream();
-  StringInputStream inputLines = new StringInputStream(file_stream);
-
-  // TODO(amouravski): Re-write as file.readAsLine().thin((lines) {...}
-  inputLines.onLine = () {
-    var comment = <String>[];
-
-    var docCommentFound = false;
-    String line;
-    while ((line = inputLines.readLine()) != null) {
-      var trimmedLine = line.trim();
-
-      // Sentinel found. Process the comment block.
-      if (trimmedLine.startsWith('///') &&
-          trimmedLine.contains('@docsEditable')) {
-        if (docCommentFound == true) {
-          var nextLine = inputLines.readLine();
-
-          if (nextLine == null) return false;
-
-          var lineObject = {};
-
-          if (comments[nextLine] != null) {
-            print('WARNING: duplicate line ${nextLine} found in'
-                '${new Path(file.fullPathSync()).filename}');
-          }
-          comments.putIfAbsent(nextLine, () => comment);
-        }
-
-        // Reset.
-        docCommentFound = false;
-        comment = <String>[];
-      } else if ( // Start a comment block.
-          trimmedLine.startsWith('/**') ||
-          trimmedLine.startsWith('///')) {
-        docCommentFound = true;
-        comment.add(line);
-      } else if (docCommentFound &&
-          // TODO(amouravski): This will barf on:
-          // /// blah
-          // *
-          (trimmedLine.startsWith('*') || trimmedLine.startsWith('///'))) {
-        comment.add(line);
-      } else {
-        // Reset if we're not in a comment.
-        docCommentFound = false;
-        comment = <String>[];
-      }
-    }
-  };
-
-  inputLines.onClosed = () {
-    var jsonObject = {};
-    jsonObject[new Path(file.fullPathSync()).filename] = comments;
-    completer.complete(jsonObject);
-  };
-
-  // TODO(amouravski): better error handling.
-
-  return completer.future;
-}
-
-
-/**
- * Merge the new JSON object and the existing file.
- */
-Object _mergeJsonAndFile(Object json, File file) {
-  var completer = new Completer();
-
-  var fileJson = {};
-  var jsonRead = file.readAsStringSync();
-
-  if (jsonRead == '') {
-    print('WARNING: no data read from '
-        '${new Path(file.fullPathSync()).filename}');
-    _anyErrors = true;
-  } else {
-    fileJson = JSON.parse(jsonRead);
-  }
-  return _mergeJson(json, fileJson);
-}
-
-
-/**
- * Merge two JSON objects, such that the returned JSON object is the
- * union of both.
- *
- * Each JSON must be a map, with each value being a map.
- */
-Object _mergeJson(Object json1, Object json2) {
-  if (json1 is Map && json2 is Map) {
-    // Then check if [json2] contains any key form [json1], in which case
-    // add all of the values from [json2] to the values of [json1].
-    json2.forEach((k, v) {
-      if (json1.containsKey(k)) {
-        v.forEach((vk, vv) {
-          if (json1[k].containsKey(vk) &&
-              !_listsEqual(json1[k][vk],vv)) {
-            // Assume that json1 is more current and take its data as opposed
-            // to json2's.
-            // TODO(amouravski): add better warning message and only if there's
-            // a conflict.
-            print('INFO: duplicate keys.');
-            _anyErrors = false;
-          } else {
-            json1[k].putIfAbsent(vk, () => vv);
-          }
-        });
-      } else {
-        json1.putIfAbsent(k, () => v);
-      }
-    });
-  } else {
-    throw new ArgumentError('JSON objects must both be Maps');
-  }
-
-  // TODO(amouravski): more error handling.
-
-  return json1;
-}
-
-
-/**
- * Tests for equality between two lists.
- *
- * This checks the first level of depth, so does not work for nested lists.
- */
-bool _listsEqual(List list1, List list2) {
-  return list1.every((e) => list2.contains(e)) &&
-      list2.every((e) => list1.contains(e));
-}
-
-
-/**
- * Print JSON in a much nicer format.
- *
- * For example:
- *
- *     {"foo":["bar","baz"],"boo":{"far:"faz"}}
- *
- * becomes:
- *
- *     {
- *       "foo":
- *         [
- *           "bar",
- *           "baz"
- *         ],
- *       "boo":
- *         {
- *           "far":
- *             "faz"
- *         }
- *     }
- */
-String prettyPrintJson(Object json, [String indentation = '']) {
-  var output;
-
-  if (json is List) {
-    var recursiveOutput =
-        Strings.join(json.map((e) =>
-            prettyPrintJson(e, '$indentation  ')), ',\n');
-    output = '$indentation[\n'
-      '$recursiveOutput'
-      '\n$indentation]';
-  } else if (json is Map) {
-    var keys = json.keys
-      ..sort();
-
-    // TODO(amouravski): No newline after :
-    var mapList = keys.map((key) =>
-        '$indentation${JSON.stringify(key)}:\n'
-        '${prettyPrintJson(json[key], '$indentation  ')}');
-    var recursiveOutput = Strings.join(mapList, ',\n');
-    output = '$indentation{\n'
-      '$recursiveOutput'
-      '\n$indentation}';
-  } else {
-    output = '$indentation${JSON.stringify(json)}';
-  }
-  return output;
-}
diff --git a/tools/html_json_doc/lib/json_to_html.dart b/tools/html_json_doc/lib/json_to_html.dart
deleted file mode 100644
index 1b56111..0000000
--- a/tools/html_json_doc/lib/json_to_html.dart
+++ /dev/null
@@ -1,155 +0,0 @@
-// 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 for taking a JSON file and putting the comments located within into
- * the HTML files the comments are associated with.
- *
- * The format of the JSON file is:
- *
- *     {
- *       "$filename":
- *         {
- *           "$lineInHtml":
- *             [
- *               "lines of comment",
- *               "here"
- *             ]
- *          },
- *       ...
- *     }
- */
-library json_to_html;
-
-import 'dart:json' as JSON;
-import 'dart:io';
-import 'dart:async';
-
-/// True if any errors were triggered through the conversion.
-bool _anyErrors = false;
-
-
-/**
- * Take comments from [jsonPath] and apply them to all the files found in
- * [htmlPath]. This will overwrite the files in htmlPath.
- */
-Future<bool> convert(Path htmlPath, Path jsonPath) {
-  final completer = new Completer();
-
-  final jsonFile = new File.fromPath(jsonPath);
-  final htmlDir = new Directory.fromPath(htmlPath);
-
-  if (!jsonFile.existsSync()) {
-    print("ERROR: No JSON file found at: ${jsonPath}");
-    _anyErrors = true;
-    completer.complete(false);
-  } else if (!htmlDir.existsSync()) {
-    print("ERROR: No HTML directory found at: ${htmlPath}");
-    _anyErrors = true;
-    completer.complete(false);
-  }
-
-
-  var fileJson = {};
-  var jsonRead = jsonFile.readAsStringSync();
-
-  if (jsonRead == '') {
-    print('WARNING: no data read from ${jsonPath.filename}');
-    _anyErrors = true;
-    completer.complete(false);
-  } else {
-    fileJson = JSON.parse(jsonRead);
-  }
-
-  // TODO(amouravski): Refactor to not duplicate code here and in html-to-json.
-  // Find html files. (lister)
-  final lister = htmlDir.list(recursive: false);
-
-  lister.onFile = (String path) {
-    final name = new Path(path).filename;
-
-    // Ignore private classes.
-    if (name.startsWith('_')) return;
-
-    // Ignore non-dart files.
-    if (!name.endsWith('.dart')) return;
-
-    File file = new File(path);
-
-    // TODO(amouravski): Handle missing file.
-    if (!file.existsSync()) {
-      print('ERROR: cannot find file: $path');
-      _anyErrors = true;
-      return;
-    }
-
-    if (!fileJson.containsKey(name)) {
-      print('WARNING: file found that is not in JSON: $path');
-      _anyErrors = true;
-      return;
-    }
-
-    var comments = fileJson[name];
-
-    _convertFile(file, comments);
-
-    fileJson.remove(name);
-  };
-
-  lister.onDone = (_) {
-
-    fileJson.forEach((key, _) {
-      print('WARNING: the following filename was found in the JSON but not in '
-          '${htmlDir.path}:\n"$key"');
-      _anyErrors = true;
-    });
-
-    completer.complete(_anyErrors);
-  };
-
-  return completer.future;
-}
-
-
-/**
- * Inserts the comments from JSON into a single file.
- */
-void _convertFile(File file, Map<String, List<String>> comments) {
-  var fileLines = file.readAsLinesSync();
-
-  var unusedComments = {};
-
-  comments.forEach((key, comments) {
-    var index = fileLines.indexOf(key);
-    // If the key is found in any line past the first one.
-    if (index > 0 && fileLines[index - 1].trim().startsWith('///') &&
-      fileLines[index - 1].contains('@docsEditable')) {
-
-      // Add comments.
-      fileLines.insertRange(index - 1, comments.length);
-      fileLines.setRange(index - 1, comments.length, comments);
-    } else {
-      unusedComments.putIfAbsent(key, () => comments);
-    }
-  });
-
-  unusedComments.forEach((String key, _) {
-    print('WARNING: the following key was found in the JSON but not in '
-        '${new Path(file.fullPathSync()).filename}:\n"$key"');
-    _anyErrors = true;
-  });
-
-  for (var i = 0; i < fileLines.length; ++i) {
-    fileLines[i] = fileLines[i].replaceAll(new RegExp(r'\s+$'), '');
-  }
-
-  // TODO(amouravski): file.writeAsStringSync('${Strings.join(fileLines, '\n')}\n');
-  var outputStream = file.openOutputStream();
-  outputStream.writeString(Strings.join(fileLines, '\n'));
-  outputStream.writeString('\n');
-
-  outputStream.onNoPendingWrites = () {
-    outputStream.close();
-  };
-}
diff --git a/tools/html_json_doc/test/html_json_doc_test.dart b/tools/html_json_doc/test/html_json_doc_test.dart
deleted file mode 100644
index 352d2aa8..0000000
--- a/tools/html_json_doc/test/html_json_doc_test.dart
+++ /dev/null
@@ -1,103 +0,0 @@
-import '../../../pkg/unittest/lib/unittest.dart';
-import '../lib/html_to_json.dart' as html_to_json;
-import '../lib/json_to_html.dart' as json_to_html;
-import 'dart:json';
-import 'dart:io';
-
-void main() {
-  var scriptPath = new Path(new Options().script).directoryPath.toString();
-
-  test('HTML Doc to JSON', () {
-    var htmlPath = new Path('$scriptPath/test_data/html_to_json');
-    var jsonPath = new Path('$scriptPath/test_output/html_to_json_test.json');
-
-    var convertFuture = html_to_json.convert(htmlPath, jsonPath);
-
-    convertFuture.then(expectAsync1((anyErrors) {
-      var output = new File.fromPath(jsonPath);
-
-      var goldenFile = new File(
-          '$scriptPath/test_data/html_to_json/'
-          'html_to_json_test_golden_output.json');
-
-      expect(anyErrors, false, reason:'The conversion completed with errors.');
-      expect(output.readAsStringSync(), goldenFile.readAsStringSync());
-    }));
-  });
-
-  test('JSON to HTML Doc', () {
-    var preHtmlPath = new Path('$scriptPath/test_data/json_to_html');
-    var goldenHtmlPath = new Path('$scriptPath/test_data/html_to_json');
-    var htmlPath = new Path('$scriptPath/test_output');
-    var jsonPath = new Path('$scriptPath/test_output/html_to_json_test.json');
-
-    var copyFuture = _copyFiles(preHtmlPath, htmlPath);
-
-    copyFuture.then(expectAsync1((_) {
-      var convertFuture = json_to_html.convert(htmlPath, jsonPath);
-
-      convertFuture.then((anyErrors) {
-        expect(anyErrors, false,
-            reason:'The conversion completed with errors.');
-
-        _compareFilesInDirectories(goldenHtmlPath, htmlPath);
-
-      });
-    }));
-  });
-}
-
-void _compareFilesInDirectories(Path path1, Path path2) {
-  final dir1 = new Directory.fromPath(path1);
-  final dir2 = new Directory.fromPath(path2);
-  final lister1 = dir1.list(recursive: false);
-  final lister2 = dir2.list(recursive: false);
-
-  // True once one of the listers is finished.
-  var oneFinished = false;
-
-  var list1 = <String, File>{};
-
-  lister1.onFile = (String path) {
-    if (path.endsWith('.dart')) {
-      list1.putIfAbsent(new Path(path).filename, () => new File(path));
-    }
-  };
-
-  lister1.onDone = (_) {
-    lister2.onFile = (String path) {
-      if (path.endsWith('.dart')) {
-        expect(list1[new Path(path).filename].readAsStringSync(),
-            new File(path).readAsStringSync());
-      }
-    };
-  };
-}
-
-Future _copyFiles(Path fromDir, Path toDir) {
-  // First copy the files into a new place to keep the old files.
-  final completer = new Completer();
-  final htmlDir = new Directory.fromPath(fromDir);
-  final lister = htmlDir.list(recursive: false);
-
-  lister.onFile = (String path) {
-    final name = new Path(path).filename;
-
-    // Ignore private classes.
-    if (name.startsWith('_')) return;
-
-    // Ignore non-dart files.
-    if (!name.endsWith('.dart')) return;
-
-    File file = new File(path);
-    File newFile = new File.fromPath(toDir.append(name));
-
-    var outputStream = newFile.openOutputStream();
-    outputStream.writeString(file.readAsStringSync());
-  };
-
-  lister.onDone = (_) {
-    completer.complete(null);
-  };
-  return completer.future;
-}
diff --git a/tools/html_json_doc/test/test_data/html_to_json/html_to_json_test_golden_output.json b/tools/html_json_doc/test/test_data/html_to_json/html_to_json_test_golden_output.json
deleted file mode 100644
index 8495eed..0000000
--- a/tools/html_json_doc/test/test_data/html_to_json/html_to_json_test_golden_output.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
-"test_html_input2.dart":
-  {
-  "class InputTestCase1 {":
-    [
-      "/**",
-      " * This is a multi-line dartdoc comment.",
-      " * This is one line.",
-      " * And it keeps going to this line, too.",
-      " */"
-    ],
-  "class InputTestCase2 extends InputTestCase1 {":
-    [
-      "/// This is a single line dartdoc comment."
-    ],
-  "class InputTestCase3 extends InputTestCase2 {":
-    [
-      "/// This is a multi-line dartdoc comment.",
-      "/// It happens to use multiple single line dartdoc comments."
-    ],
-  "  var InputTestCase8;":
-    [
-      "  /**",
-      "   * This is a multi-line comment on a member.",
-      "   */"
-    ],
-  "  var InputTestCase9;":
-    [
-      "  /// This is a single line dartdoc comment on a member."
-    ],
-  "  var InputTestCase10;":
-    [
-      "  /// This is a multi-line dartdoc comment on a member.",
-      "  /// It is split over two lines."
-    ]
-  },
-"test_html_input.dart":
-  {
-  "library testInput;":
-    [
-      "/**",
-      " * YES. This is a library level dartdoc comment.",
-      " * This should show up correctly in the JSON.",
-      " */"
-    ],
-  "class InputTestCase1 {":
-    [
-      "/**",
-      " * YES. This is a multi-line dartdoc comment.",
-      " * This is one line.",
-      " * And it keeps going to this line, too.",
-      " */"
-    ],
-  "class InputTestCase2 extends InputTestCase1 {":
-    [
-      "/// YES. This is a single line dartdoc comment."
-    ],
-  "class InputTestCase3 extends InputTestCase2 {":
-    [
-      "/// YES. This is a multi-line dartdoc comment.",
-      "/// It happens to use multiple single line dartdoc comments."
-    ],
-  "  var InputTestCase8;":
-    [
-      "  /**",
-      "   * YES. This is a multi-line comment on a member.",
-      "   */"
-    ],
-  "  var InputTestCase9;":
-    [
-      "  /// YES. This is a single line dartdoc comment on a member."
-    ],
-  "  var InputTestCase10;":
-    [
-      "  /// YES. This is a multi-line dartdoc comment on a member.",
-      "  /// It is split over two lines."
-    ]
-  }
-}
\ No newline at end of file
diff --git a/tools/html_json_doc/test/test_data/html_to_json/test_html_input.dart b/tools/html_json_doc/test/test_data/html_to_json/test_html_input.dart
deleted file mode 100644
index 291d0dd..0000000
--- a/tools/html_json_doc/test/test_data/html_to_json/test_html_input.dart
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * YES. This is a library level dartdoc comment.
- * This should show up correctly in the JSON.
- */
-/// @docsEditable
-library testInput;
-
-/**
- * YES. This is a multi-line dartdoc comment.
- * This is one line.
- * And it keeps going to this line, too.
- */
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// YES. This is a single line dartdoc comment.
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// YES. This is a multi-line dartdoc comment.
-/// It happens to use multiple single line dartdoc comments.
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * NO. This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * NO. This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// NO. This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// NO. This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
-  /**
-   * YES. This is a multi-line comment on a member.
-   */
-  /// @docsEditable
-  var InputTestCase8;
-
-  /// YES. This is a single line dartdoc comment on a member.
-  /// @docsEditable
-  var InputTestCase9;
-
-  /// YES. This is a multi-line dartdoc comment on a member.
-  /// It is split over two lines.
-  /// @docsEditable
-  var InputTestCase10;
-
-  /**
-   * NO.This multi-line comment on a member is ignored.
-   */
-  var InputTestCase11;
-
-  /// NO. This single line dartdoc comment on a member is ignored.
-  var InputTestCase12;
-}
diff --git a/tools/html_json_doc/test/test_data/html_to_json/test_html_input2.dart b/tools/html_json_doc/test/test_data/html_to_json/test_html_input2.dart
deleted file mode 100644
index 1f9615b..0000000
--- a/tools/html_json_doc/test/test_data/html_to_json/test_html_input2.dart
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * This is a library level dartdoc comment.
- * This should be ignored.
- */
-library testInput2;
-
-/**
- * This is a multi-line dartdoc comment.
- * This is one line.
- * And it keeps going to this line, too.
- */
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// This is a single line dartdoc comment.
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// This is a multi-line dartdoc comment.
-/// It happens to use multiple single line dartdoc comments.
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
-  /**
-   * This is a multi-line comment on a member.
-   */
-  /// @docsEditable
-  var InputTestCase8;
-
-  /// This is a single line dartdoc comment on a member.
-  /// @docsEditable
-  var InputTestCase9;
-
-  /// This is a multi-line dartdoc comment on a member.
-  /// It is split over two lines.
-  /// @docsEditable
-  var InputTestCase10;
-
-  /**
-   * This multi-line comment on a member is ignored.
-   */
-  var InputTestCase11;
-
-  /// This single line dartdoc comment on a member is ignored.
-  var InputTestCase12;
-}
diff --git a/tools/html_json_doc/test/test_data/json_to_html/test_html_input.dart b/tools/html_json_doc/test/test_data/json_to_html/test_html_input.dart
deleted file mode 100644
index 70b6041..0000000
--- a/tools/html_json_doc/test/test_data/json_to_html/test_html_input.dart
+++ /dev/null
@@ -1,62 +0,0 @@
-/// @docsEditable
-library testInput;
-
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * NO. This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * NO. This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// NO. This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// NO. This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
-  /// @docsEditable
-  var InputTestCase8;
-
-  /// @docsEditable
-  var InputTestCase9;
-
-  /// @docsEditable
-  var InputTestCase10;
-
-  /**
-   * NO.This multi-line comment on a member is ignored.
-   */
-  var InputTestCase11;
-
-  /// NO. This single line dartdoc comment on a member is ignored.
-  var InputTestCase12;
-}
diff --git a/tools/html_json_doc/test/test_data/json_to_html/test_html_input2.dart b/tools/html_json_doc/test/test_data/json_to_html/test_html_input2.dart
deleted file mode 100644
index a6b286d..0000000
--- a/tools/html_json_doc/test/test_data/json_to_html/test_html_input2.dart
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * This is a library level dartdoc comment.
- * This should be ignored.
- */
-library testInput2;
-
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
-  /// @docsEditable
-  var InputTestCase8;
-
-  /// @docsEditable
-  var InputTestCase9;
-
-  /// @docsEditable
-  var InputTestCase10;
-
-  /**
-   * This multi-line comment on a member is ignored.
-   */
-  var InputTestCase11;
-
-  /// This single line dartdoc comment on a member is ignored.
-  var InputTestCase12;
-}
diff --git a/tools/html_json_doc/test/test_output/html_to_json_test.json b/tools/html_json_doc/test/test_output/html_to_json_test.json
deleted file mode 100644
index 8495eed..0000000
--- a/tools/html_json_doc/test/test_output/html_to_json_test.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
-"test_html_input2.dart":
-  {
-  "class InputTestCase1 {":
-    [
-      "/**",
-      " * This is a multi-line dartdoc comment.",
-      " * This is one line.",
-      " * And it keeps going to this line, too.",
-      " */"
-    ],
-  "class InputTestCase2 extends InputTestCase1 {":
-    [
-      "/// This is a single line dartdoc comment."
-    ],
-  "class InputTestCase3 extends InputTestCase2 {":
-    [
-      "/// This is a multi-line dartdoc comment.",
-      "/// It happens to use multiple single line dartdoc comments."
-    ],
-  "  var InputTestCase8;":
-    [
-      "  /**",
-      "   * This is a multi-line comment on a member.",
-      "   */"
-    ],
-  "  var InputTestCase9;":
-    [
-      "  /// This is a single line dartdoc comment on a member."
-    ],
-  "  var InputTestCase10;":
-    [
-      "  /// This is a multi-line dartdoc comment on a member.",
-      "  /// It is split over two lines."
-    ]
-  },
-"test_html_input.dart":
-  {
-  "library testInput;":
-    [
-      "/**",
-      " * YES. This is a library level dartdoc comment.",
-      " * This should show up correctly in the JSON.",
-      " */"
-    ],
-  "class InputTestCase1 {":
-    [
-      "/**",
-      " * YES. This is a multi-line dartdoc comment.",
-      " * This is one line.",
-      " * And it keeps going to this line, too.",
-      " */"
-    ],
-  "class InputTestCase2 extends InputTestCase1 {":
-    [
-      "/// YES. This is a single line dartdoc comment."
-    ],
-  "class InputTestCase3 extends InputTestCase2 {":
-    [
-      "/// YES. This is a multi-line dartdoc comment.",
-      "/// It happens to use multiple single line dartdoc comments."
-    ],
-  "  var InputTestCase8;":
-    [
-      "  /**",
-      "   * YES. This is a multi-line comment on a member.",
-      "   */"
-    ],
-  "  var InputTestCase9;":
-    [
-      "  /// YES. This is a single line dartdoc comment on a member."
-    ],
-  "  var InputTestCase10;":
-    [
-      "  /// YES. This is a multi-line dartdoc comment on a member.",
-      "  /// It is split over two lines."
-    ]
-  }
-}
\ No newline at end of file
diff --git a/tools/html_json_doc/test/test_output/test_html_input.dart b/tools/html_json_doc/test/test_output/test_html_input.dart
deleted file mode 100644
index 291d0dd..0000000
--- a/tools/html_json_doc/test/test_output/test_html_input.dart
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * YES. This is a library level dartdoc comment.
- * This should show up correctly in the JSON.
- */
-/// @docsEditable
-library testInput;
-
-/**
- * YES. This is a multi-line dartdoc comment.
- * This is one line.
- * And it keeps going to this line, too.
- */
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// YES. This is a single line dartdoc comment.
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// YES. This is a multi-line dartdoc comment.
-/// It happens to use multiple single line dartdoc comments.
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * NO. This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * NO. This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// NO. This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// NO. This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
-  /**
-   * YES. This is a multi-line comment on a member.
-   */
-  /// @docsEditable
-  var InputTestCase8;
-
-  /// YES. This is a single line dartdoc comment on a member.
-  /// @docsEditable
-  var InputTestCase9;
-
-  /// YES. This is a multi-line dartdoc comment on a member.
-  /// It is split over two lines.
-  /// @docsEditable
-  var InputTestCase10;
-
-  /**
-   * NO.This multi-line comment on a member is ignored.
-   */
-  var InputTestCase11;
-
-  /// NO. This single line dartdoc comment on a member is ignored.
-  var InputTestCase12;
-}
diff --git a/tools/html_json_doc/test/test_output/test_html_input2.dart b/tools/html_json_doc/test/test_output/test_html_input2.dart
deleted file mode 100644
index 1f9615b..0000000
--- a/tools/html_json_doc/test/test_output/test_html_input2.dart
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * This is a library level dartdoc comment.
- * This should be ignored.
- */
-library testInput2;
-
-/**
- * This is a multi-line dartdoc comment.
- * This is one line.
- * And it keeps going to this line, too.
- */
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// This is a single line dartdoc comment.
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// This is a multi-line dartdoc comment.
-/// It happens to use multiple single line dartdoc comments.
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
-  /**
-   * This is a multi-line comment on a member.
-   */
-  /// @docsEditable
-  var InputTestCase8;
-
-  /// This is a single line dartdoc comment on a member.
-  /// @docsEditable
-  var InputTestCase9;
-
-  /// This is a multi-line dartdoc comment on a member.
-  /// It is split over two lines.
-  /// @docsEditable
-  var InputTestCase10;
-
-  /**
-   * This multi-line comment on a member is ignored.
-   */
-  var InputTestCase11;
-
-  /// This single line dartdoc comment on a member is ignored.
-  var InputTestCase12;
-}
diff --git a/tools/publish_all_pkgs.py b/tools/publish_all_pkgs.py
index c20ed29..5ddeb20 100644
--- a/tools/publish_all_pkgs.py
+++ b/tools/publish_all_pkgs.py
@@ -4,7 +4,7 @@
 # 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.
 #
-# Upload all packages in pkg/ (other than a few that should be explicitly 
+# Upload all packages in pkg/ (other than a few that should be explicitly
 # excluded), plus sdk/lib/_internal/compiler .
 #
 # Usage: publish_all_pkgs.py
@@ -21,15 +21,14 @@
   pkgs_to_publish = []
   for name in os.listdir('pkg'):
     if os.path.isdir(os.path.join('pkg', name)):
-      if (name != '.svn' and name != 'fixnum' and
-          not name.endswith('-experimental')):
+      if name != '.svn' and name != 'fixnum':
         pkgs_to_publish.append(os.path.join('pkg', name))
 
   # Publish dart2js as an "unsupported" package.
   pkgs_to_publish.append(
     os.path.join('sdk', 'lib', '_internal', 'compiler'))
 
-  for pkg in pkgs_to_publish: 
+  for pkg in pkgs_to_publish:
     print "Publishing " + pkg
     subprocess.call(['python', 'tools/publish_pkg.py', pkg])
 
diff --git a/tools/publish_pkg.py b/tools/publish_pkg.py
index 9861a8d..d1629c9 100755
--- a/tools/publish_pkg.py
+++ b/tools/publish_pkg.py
@@ -58,11 +58,12 @@
     version = '%d.%d.%d' % (major, minor, build)
 
   tmpDir = tempfile.mkdtemp()
-  pkgName = argv[1].split('/').pop()
+  pkgName = os.path.basename(os.path.normpath(argv[1]))
 
   pubspec = os.path.join(tmpDir, pkgName, 'pubspec.yaml')
 
-  replaceInFiles = []
+  replaceInDart = []
+  replaceInPubspec = []
 
   if os.path.exists(os.path.join(HOME, argv[1], 'pubspec.yaml')):
     #
@@ -126,7 +127,7 @@
       shutil.copy(libpath, os.path.join(tmpDir, pkgName, 'lib/libraries.dart'))
 
       # Replace '../../libraries.dart' with '../libraries.dart'
-      replaceInFiles.append(
+      replaceInDart.append(
         (r'(import|part)(\s+)(\'|")\.\./(\.\./)*libraries.dart',
          r'\1\2\3\4libraries.dart'))
 
@@ -159,7 +160,13 @@
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ''');
 
-  replaceInFiles.append(
+  # TODO(jmesserly): this is a hack to make analyzer-experimental work.
+  if pkgName.endswith('-experimental'):
+    pkgReplace = (pkgName, pkgName.replace('-', '_'))
+    replaceInDart.append(pkgReplace)
+    replaceInPubspec.append(pkgReplace)
+
+  replaceInDart.append(
     (r'(import|part)(\s+)(\'|")(\.\./)+pkg/([^/]+/)lib/', r'\1\2\3package:\5'))
 
   # Replace '../*/pkg' imports and parts.
@@ -169,7 +176,9 @@
       shutil.rmtree(os.path.join(root, '.svn'))
     for name in files:
       if name.endswith('.dart'):
-        ReplaceInFiles([os.path.join(root, name)], replaceInFiles)
+        ReplaceInFiles([os.path.join(root, name)], replaceInDart)
+      elif name == 'pubspec.yaml':
+        ReplaceInFiles([os.path.join(root, name)], replaceInPubspec)
 
   print 'publishing version ' + version + ' of ' + argv[1] + ' to pub.\n'
   subprocess.call(['pub', 'publish'], cwd=os.path.join(tmpDir, pkgName))
diff --git a/tools/test-runtime.dart b/tools/test-runtime.dart
index 036c861..2077a06 100755
--- a/tools/test-runtime.dart
+++ b/tools/test-runtime.dart
@@ -73,6 +73,8 @@
   }
 
   var testSuites = new List<TestSuite>();
+  TestingServerRunner.setBuildDir(firstConf);
+  TestingServerRunner.setPackageRootDir(firstConf);
   for (var conf in configurations) {
     if (selectors.containsKey('co19')) {
       testSuites.add(new Co19TestSuite(conf));
diff --git a/tools/test.dart b/tools/test.dart
index 12cff10..da3a85e 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -126,6 +126,10 @@
   }
 
   var testSuites = new List<TestSuite>();
+  // FIXME(kustermann,ricow): This is boken and should be fixed ASAP.
+  // Issue: 8366
+  TestingServerRunner.setBuildDir(firstConf);
+  TestingServerRunner.setPackageRootDir(firstConf);
   var maxBrowserProcesses = maxProcesses;
   for (var conf in configurations) {
     // There should not be more than one InternetExplorerDriver instance
@@ -134,7 +138,6 @@
     if (conf['runtime'].startsWith('ie')) {
       maxBrowserProcesses = 1;
     }
-    TestingServerRunner.setPackageRootDir(conf);
     for (String key in selectors.keys) {
       if (key == 'co19') {
         testSuites.add(new Co19TestSuite(conf));
diff --git a/tools/testing/dart/browser_test.dart b/tools/testing/dart/browser_test.dart
index 6bfc93a..ad9f972 100644
--- a/tools/testing/dart/browser_test.dart
+++ b/tools/testing/dart/browser_test.dart
@@ -5,8 +5,6 @@
 part of test_suite;
 
 String getHtmlContents(String title,
-                       Path controllerScript,
-                       Path dartJsScript,
                        String scriptType,
                        Path sourceScript) =>
 """
@@ -24,10 +22,11 @@
 </head>
 <body>
   <h1> Running $title </h1>
-  <script type="text/javascript" src="$controllerScript"></script>
+  <script type="text/javascript" src="/pkg/unittest/lib/test_controller.js">
+  </script>
   <script type="$scriptType" src="$sourceScript" onerror="externalError(null)">
   </script>
-  <script type="text/javascript" src="$dartJsScript"></script>
+  <script type="text/javascript" src="/pkg/browser/lib/dart.js"></script>
 </body>
 </html>
 """;
@@ -48,37 +47,27 @@
 </html>
 """;
 
-String wrapDartTestInLibrary(Path test, String testPath) =>
+String wrapDartTestInLibrary(Path testRelativeToDart) =>
 """
 library libraryWrapper;
-part '${pathLib.relative(test.toNativePath(),
-    from: pathLib.dirname(testPath)).replaceAll('\\', '\\\\')}';
+part '/$testRelativeToDart';
 """;
 
-String dartTestWrapper(Path dartHome, String testPath, Path library) {
-  var testPathDir = pathLib.dirname(testPath);
-  var dartHomePath = dartHome.toNativePath();
-  // TODO(efortuna): Unify path libraries used in test.dart.
-  var unitTest = pathLib.relative(pathLib.join(dartHomePath,
-    'pkg/unittest/lib'), from: testPathDir).replaceAll('\\', '\\\\');
-
-  var libString = library.toNativePath();
-  if (!pathLib.isAbsolute(libString)) {
-    libString = pathLib.join(dartHome.toNativePath(), libString);
-  }
+String dartTestWrapper(bool usePackageImport, String libraryPathComponent) {
   // Tests inside "pkg" import unittest using "package:". All others use a
   // relative path. The imports need to agree, so use a matching form here.
-  if (pathLib.split(pathLib.relative(libString,
-      from: dartHome.toNativePath())).contains("pkg")) {
+  var unitTest;
+  if (usePackageImport) {
     unitTest = 'package:unittest';
+  } else {
+    unitTest = '/pkg/unittest/lib';
   }
   return """
 library test;
 
 import '$unitTest/unittest.dart' as unittest;
 import '$unitTest/html_config.dart' as config;
-import '${pathLib.relative(libString, from: testPathDir).replaceAll(
-    '\\', '\\\\')}' as Test;
+import '$libraryPathComponent' as Test;
 
 main() {
   config.useHtmlConfiguration();
diff --git a/tools/testing/dart/http_server.dart b/tools/testing/dart/http_server.dart
index 84a5b77..6966ab3 100644
--- a/tools/testing/dart/http_server.dart
+++ b/tools/testing/dart/http_server.dart
@@ -40,7 +40,11 @@
         .join(new Path('../../test.dart'))
         .canonicalize()
         .toNativePath();
+    // Note: args['package-root'] is always the build directory. We have the
+    // implicit assumption that it contains the 'packages' subdirectory.
+    // TODO: We should probably rename 'package-root' to 'build-directory'.
     TestingServerRunner._packageRootDir = new Path(args['package-root']);
+    TestingServerRunner._buildDirectory = new Path(args['package-root']);
     TestingServerRunner.startHttpServer('127.0.0.1',
         port: int.parse(args['port']));
     print('Server listening on port '
@@ -59,16 +63,22 @@
 class TestingServerRunner {
   static List serverList = [];
   static Path _packageRootDir = null;
+  static Path _buildDirectory = null;
 
   // Added as a getter so that the function will be called again each time the
   // default request handler closure is executed.
   static Path get packageRootDir => _packageRootDir;
+  static Path get buildDirectory => _buildDirectory;
 
   static setPackageRootDir(Map configuration) {
     _packageRootDir = TestUtils.currentWorkingDirectory.join(
         new Path(TestUtils.buildDir(configuration)));
   }
 
+  static setBuildDir(Map configuration) {
+    _buildDirectory = new Path(TestUtils.buildDir(configuration));
+  }
+
   static startHttpServer(String host, {int allowedPort:-1, int port: 0}) {
     var basePath = TestUtils.dartDir();
     var httpServer = new HttpServer();
@@ -78,10 +88,23 @@
       print('Test http server error: $e');
     };
     httpServer.defaultRequestHandler = (request, resp) {
+      // TODO(kustermann,ricow): We could change this to the following scheme:
+      // http://host:port/root_dart/X     -> $DartDir/X
+      // http://host:port/root_build/X    -> $BuildDir/X
+      // http://host:port/root_packages/X -> $BuildDir/packages/X
+      // Issue: 8368
+
       var requestPath = new Path(request.path.substring(1)).canonicalize();
       var path = basePath.join(requestPath);
       var file = new File(path.toNativePath());
-
+      // Since the build directory may not be located directly beneath the dart
+      // root directory (if we pass it in, e.g., for dartium testing) we serve
+      // files from the build directory explicitly. Please note that if
+      // buildDirectory has the same name as a directory inside the dart repo
+      // we will server files from the buildDirectory.
+      if (requestPath.toString().startsWith(buildDirectory.toString())) {
+        file = new File(requestPath.toNativePath());
+      }
       if (requestPath.segments().contains(packagesDirName)) {
         // Essentially implement the packages path rewriting, so we don't have
         // to pass environment variables to the browsers.
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 349a8a6..11b9ef1 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -812,6 +812,77 @@
     };
   }
 
+
+  /**
+   * _createUrlPathFromFile takes a [file], which is either located in the dart
+   * or in the build directory, and will return a String representing
+   * the relative path to either the dart or the build directory.
+   * Thus, the returned [String] will be the path component of the URL
+   * corresponding to [file] (the http server serves files relative to the
+   * dart/build directories).
+   */
+  String _createUrlPathFromFile(Path file) {
+    file = TestUtils.absolutePath(file);
+    var fileString = file.toString();
+    
+    var relativeBuildDir = new Path(TestUtils.buildDir(configuration));
+    var buildDir = TestUtils.absolutePath(relativeBuildDir);
+    var dartDir = TestUtils.dartDir();
+
+    var pathComponent;
+    if (fileString.startsWith(buildDir.toString())) {
+      var fileRelativeToBuildDir = file.relativeTo(buildDir);
+      pathComponent = "$relativeBuildDir/$fileRelativeToBuildDir";
+    } else if (fileString.startsWith(dartDir.toString())) {
+      pathComponent = file.relativeTo(dartDir);
+    } else {
+      // Unreachable
+      Except.isTrue(false);
+    }
+    return "/$pathComponent";
+  }
+
+  void _getUriForBrowserTest(TestInformation info,
+                            String pathComponent,
+                            subtestNames,
+                            subtestIndex) {
+    // Note: If we run test.py with the "--list" option, no http servers
+    // will be started. Therefore serverList is an empty list in this
+    // case. So we use PORT/CROSS_ORIGIN_PORT instead of real ports.
+    var serverPort = "PORT";
+    var crossOriginPort = "CROSS_ORIGIN_PORT";
+    if (!configuration['list']) {
+      serverPort = serverList[0].port.toString();
+      crossOriginPort = serverList[1].port.toString();
+    }
+
+    var url= 'http://127.0.0.1:$serverPort$pathComponent'
+        '?crossOriginPort=$crossOriginPort';
+    if (info.optionsFromFile['isMultiHtmlTest'] && subtestNames.length > 0) {
+      url= '${url}&group=${subtestNames[subtestIndex]}';
+    }
+    return url;
+  }
+
+  void _createWrapperFile(String dartWrapperFilename, dartLibraryFilename) {
+    File file = new File(dartWrapperFilename);
+    RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE);
+
+    var usePackageImport = dartLibraryFilename.segments().contains("pkg");
+    var libraryPathComponent = _createUrlPathFromFile(dartLibraryFilename);
+    dartWrapper.writeStringSync(dartTestWrapper(usePackageImport,
+                                                libraryPathComponent));
+    dartWrapper.closeSync();
+  }
+
+  void _createLibraryWrapperFile(Path dartLibraryFilename, filePath) {
+    File file = new File(dartLibraryFilename.toNativePath());
+    RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE);
+    dartLibrary.writeStringSync(
+        wrapDartTestInLibrary(filePath.relativeTo(TestUtils.dartDir())));
+    dartLibrary.closeSync();
+  }
+
   /**
    * The [StandardTestSuite] has support for tests that
    * compile a test from Dart to JavaScript, and then run the resulting
@@ -867,18 +938,9 @@
         if (!isLibraryDefinition) {
           dartLibraryFilename = new Path(tempDir).append(
               'test_as_library.dart');
-          File file = new File(dartLibraryFilename.toNativePath());
-          RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE);
-          dartLibrary.writeStringSync(
-              wrapDartTestInLibrary(filePath, file.name));
-          dartLibrary.closeSync();
+          _createLibraryWrapperFile(dartLibraryFilename, filePath);
         }
-
-        File file = new File(dartWrapperFilename);
-        RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE);
-        dartWrapper.writeStringSync(
-            dartTestWrapper(dartDir, file.name, dartLibraryFilename));
-        dartWrapper.closeSync();
+        _createWrapperFile(dartWrapperFilename, dartLibraryFilename);
       } else {
         dartWrapperFilename = filename;
         // TODO(whesse): Once test.py is retired, adjust the relative path in
@@ -895,8 +957,10 @@
         }
         htmlPath = '$tempDir/../$htmlFilename';
       }
-      final String scriptPath = (compiler == 'none') ?
+      String scriptPath = (compiler == 'none') ?
           dartWrapperFilename : compiledDartWrapperFilename;
+      scriptPath = _createUrlPathFromFile(new Path(scriptPath));
+
       // Create the HTML file for the test.
       RandomAccessFile htmlTest = new File(htmlPath).openSync(FileMode.WRITE);
       String content = null;
@@ -907,22 +971,13 @@
       Path expectedOutput = null;
       if (new File.fromPath(pngPath).existsSync()) {
         expectedOutput = pngPath;
-        // TODO(efortuna): Unify path libraries in test.dart.
-        content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath,
-            from: pathLib.dirname(htmlPath)));
+        content = getHtmlLayoutContents(scriptType, new Path("$scriptPath"));
       } else if (new File.fromPath(txtPath).existsSync()) {
         expectedOutput = txtPath;
-        content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath,
-            from: pathLib.dirname(htmlPath)));
+        content = getHtmlLayoutContents(scriptType, new Path("$scriptPath"));
       } else {
-        final htmlLocation = new Path(htmlPath);
-        content = getHtmlContents(
-          filename,
-          dartDir.append('pkg/unittest/test_controller.js')
-              .relativeTo(htmlLocation),
-          dartDir.append('pkg/browser/lib/dart.js').relativeTo(htmlLocation),
-          scriptType,
-          new Path(scriptPath).relativeTo(htmlLocation));
+        content = getHtmlContents(filename, scriptType,
+            new Path("$scriptPath"));
       }
       htmlTest.writeStringSync(content);
       htmlTest.closeSync();
@@ -962,35 +1017,11 @@
           commandSet = [];
         }
 
-        List<String> args = <String>[];
-        var basePath = TestUtils.dartDir().toString();
-        if (!htmlPath.startsWith('/') && !htmlPath.startsWith('http')) {
-          htmlPath = '/$htmlPath';
-        }
-        htmlPath = htmlPath.startsWith(basePath) ?
-            htmlPath.substring(basePath.length) : htmlPath;
-        String fullHtmlPath = htmlPath;
-        var searchStr = '?';
-        if (!htmlPath.startsWith('http')) {
-          // Note: If we run test.py with the "--list" option, no http servers
-          // will be started. Therefore serverList is an empty list in this
-          // case. So we use PORT/CROSS_ORIGIN_PORT instead of real ports.
-          var serverPort = "PORT";
-          var crossOriginPort = "CROSS_ORIGIN_PORT";
-          if (!configuration['list']) {
-            serverPort = serverList[0].port.toString();
-            crossOriginPort = serverList[1].port.toString();
-          }
-          fullHtmlPath = 'http://127.0.0.1:$serverPort$htmlPath${searchStr}'
-              'crossOriginPort=$crossOriginPort';
-          searchStr = '&';
-        }
-        if (info.optionsFromFile['isMultiHtmlTest']
-            && subtestNames.length > 0) {
-          fullHtmlPath = '${fullHtmlPath}${searchStr}group='
-              '${subtestNames[subtestIndex]}';
-        }
+        var htmlPath_subtest = _createUrlPathFromFile(new Path(htmlPath));
+        var fullHtmlPath = _getUriForBrowserTest(info, htmlPath_subtest,
+                                                 subtestNames, subtestIndex);
 
+        List<String> args = <String>[];
         if (TestUtils.usesWebDriver(runtime)) {
           args = [
               dartDir.append('tools/testing/run_selenium.py').toNativePath(),
@@ -1125,8 +1156,7 @@
     var minified = configuration['minified'] ? '-minified' : '';
     var dirName = "${configuration['compiler']}-${configuration['runtime']}"
                   "$checked$minified";
-    Path generatedTestPath = new Path(dartDir.toNativePath())
-        .append(buildDir)
+    Path generatedTestPath = new Path(buildDir)
         .append('generated_tests')
         .append(dirName)
         .append(testUniqueName);
@@ -1816,6 +1846,10 @@
       const ['d8', 'jsshell'].contains(runtime);
 
   static String buildDir(Map configuration) {
+    // FIXME(kustermann,ricow): Our code assumes that the returned 'buildDir'
+    // is relative to the current working directory.
+    // Thus, if we pass in an absolute path (e.g. '--build-directory=/tmp/out')
+    // we get into trouble.
     if (configuration['build_directory'] != '') {
       return configuration['build_directory'];
     }
diff --git a/utils/apidoc/apidoc.dart b/utils/apidoc/apidoc.dart
index bf6324f..36ef96b 100644
--- a/utils/apidoc/apidoc.dart
+++ b/utils/apidoc/apidoc.dart
@@ -258,16 +258,6 @@
     super.docLibrary(library);
   }
 
-  /** Override definition from parent class to strip out annotation tags. */
-  doc.DocComment createDocComment(String text,
-                                  [ClassMirror inheritedFrom]) {
-    String strippedText =
-        text.replaceAll(new RegExp("@([a-zA-Z]+) ([^;]+)(?:;|\$)"),
-                        '').trim();
-    if (strippedText.isEmpty) return null;
-    return super.createDocComment(strippedText, inheritedFrom);
-  }
-
   doc.DocComment getLibraryComment(LibraryMirror library) {
     return super.getLibraryComment(library);
   }
diff --git a/utils/apidoc/html_diff.dart b/utils/apidoc/html_diff.dart
index c9aaf84..d6a5067 100644
--- a/utils/apidoc/html_diff.dart
+++ b/utils/apidoc/html_diff.dart
@@ -156,8 +156,8 @@
     final domNameMetadata = findMetadata(htmlType.metadata, 'DomName');
     if (domNameMetadata != null) {
       var domNames = <String>[];
-      var tags = deprecatedFutureValue(domNameMetadata.getField('name'));
-      for (var s in tags.reflectee.split(',')) {
+      var names = deprecatedFutureValue(domNameMetadata.getField('name'));
+      for (var s in names.reflectee.split(',')) {
         domNames.add(s.trim());
       }
 
@@ -180,8 +180,8 @@
     final domNameMetadata = findMetadata(htmlMember.metadata, 'DomName');
     if (domNameMetadata != null) {
       var domNames = <String>[];
-      var tags = deprecatedFutureValue(domNameMetadata.getField('name'));
-      for (var s in tags.reflectee.split(',')) {
+      var names = deprecatedFutureValue(domNameMetadata.getField('name'));
+      for (var s in names.reflectee.split(',')) {
         domNames.add(s.trim());
       }
 
diff --git a/utils/pub/entrypoint.dart b/utils/pub/entrypoint.dart
index 843d41d..6d7ffe0 100644
--- a/utils/pub/entrypoint.dart
+++ b/utils/pub/entrypoint.dart
@@ -157,13 +157,19 @@
           var id = lockFile.packages[ref.name];
 
           visited.add(ref.name);
-          var future = cache.describe(id);
+          var future;
+          if (ref.name == root.name) {
+            future = new Future<Pubspec>.immediate(root.pubspec);
+          } else {
+            future = cache.describe(id);
+          }
           group.add(future.then(visitPackage));
         }
 
         return pubspec;
       }
 
+      visited.add(root.name);
       visitPackage(root.pubspec);
       return group.future;
     });
diff --git a/utils/pub/hosted_source.dart b/utils/pub/hosted_source.dart
index 2db9cc8..ef56462 100644
--- a/utils/pub/hosted_source.dart
+++ b/utils/pub/hosted_source.dart
@@ -62,31 +62,29 @@
 
   /// Downloads a package from the site and unpacks it.
   Future<bool> install(PackageId id, String destPath) {
-    var parsedDescription = _parseDescription(id.description);
-    var name = parsedDescription.first;
-    var url = parsedDescription.last;
+    return defer(() {
+      var parsedDescription = _parseDescription(id.description);
+      var name = parsedDescription.first;
+      var url = parsedDescription.last;
 
-    var fullUrl = "$url/packages/$name/versions/${id.version}.tar.gz";
+      var fullUrl = "$url/packages/$name/versions/${id.version}.tar.gz";
 
-    log.message('Downloading $id...');
+      log.message('Downloading $id...');
 
-    // Download and extract the archive to a temp directory.
-    var tempDir;
-    return Future.wait([
-      httpClient.send(new http.Request("GET", Uri.parse(fullUrl)))
-          .then((response) => response.stream),
-      systemCache.createTempDir()
-    ]).then((args) {
-      var stream = args[0];
-      tempDir = args[1];
-      return timeout(extractTarGz(stream, tempDir), HTTP_TIMEOUT,
-          'fetching URL "$fullUrl"');
-    }).then((_) {
-      // Now that the install has succeeded, move it to the real location in
-      // the cache. This ensures that we don't leave half-busted ghost
-      // directories in the user's pub cache if an install fails.
-      return renameDir(tempDir, destPath);
-    }).then((_) => true);
+      // Download and extract the archive to a temp directory.
+      var tempDir = systemCache.createTempDir();
+      return httpClient.send(new http.Request("GET", Uri.parse(fullUrl)))
+          .then((response) => response.stream)
+          .then((stream) {
+        return timeout(extractTarGz(stream, tempDir), HTTP_TIMEOUT,
+            'fetching URL "$fullUrl"');
+      }).then((_) {
+        // Now that the install has succeeded, move it to the real location in
+        // the cache. This ensures that we don't leave half-busted ghost
+        // directories in the user's pub cache if an install fails.
+        return renameDir(tempDir, destPath);
+      }).then((_) => true);
+    });
   }
 
   /// The system cache directory for the hosted source contains subdirectories
diff --git a/utils/pub/io.dart b/utils/pub/io.dart
index 60f6d77..d3fa00bb 100644
--- a/utils/pub/io.dart
+++ b/utils/pub/io.dart
@@ -157,10 +157,10 @@
 /// suffix appended to it. If [dir] is not provided, a temp directory will be
 /// created in a platform-dependent temporary location. Returns a [Future] that
 /// completes when the directory is created.
-Future<Directory> createTempDir([dir = '']) {
-  dir = _getDirectory(dir);
-  return log.ioAsync("create temp directory ${dir.path}",
-      dir.createTemp());
+Directory createTempDir([dir = '']) {
+  var tempDir = _getDirectory(dir).createTempSync();
+  log.io("Created temp directory ${tempDir.path}");
+  return tempDir;
 }
 
 /// Asynchronously recursively deletes [dir], which can be a [String] or a
@@ -425,6 +425,21 @@
       .then((line) => new RegExp(r"^[yY]").hasMatch(line));
 }
 
+/// Reads and discards all output from [inputStream]. Returns a [Future] that
+/// completes when the stream is closed.
+Future drainInputStream(InputStream inputStream) {
+  var completer = new Completer();
+  if (inputStream.closed) {
+    completer.complete();
+    return completer.future;
+  }
+
+  inputStream.onClosed = () => completer.complete();
+  inputStream.onData = inputStream.read;
+  inputStream.onError = (error) => completer.completeError(error);
+  return completer.future;
+}
+
 /// Wraps [stream] in a single-subscription [Stream] that emits the same data.
 ByteStream wrapInputStream(InputStream stream) {
   var controller = new StreamController();
@@ -707,14 +722,15 @@
 /// Creates a temporary directory and passes its path to [fn]. Once the [Future]
 /// returned by [fn] completes, the temporary directory and all its contents
 /// will be deleted.
+///
+/// Returns a future that completes to the value that the future returned from
+/// [fn] completes to.
 Future withTempDir(Future fn(String path)) {
-  var tempDir;
-  return createTempDir().then((dir) {
-    tempDir = dir;
-    return fn(tempDir.path);
-  }).whenComplete(() {
-    log.fine('Cleaning up temp directory ${tempDir.path}.');
-    return deleteDir(tempDir);
+  return defer(() {
+    var tempDir = createTempDir();
+    return fn(tempDir.path).whenComplete(() {
+      return deleteDir(tempDir);
+    });
   });
 }
 
@@ -764,51 +780,44 @@
   var pathTo7zip = '../../third_party/7zip/7za.exe';
   var command = relativeToPub(pathTo7zip);
 
-  var tempDir;
-
-  // TODO(rnystrom): Use withTempDir().
-  return createTempDir().then((temp) {
+  return withTempDir((tempDir) {
     // Write the archive to a temp file.
-    tempDir = temp;
-    return createFileFromStream(stream, join(tempDir, 'data.tar.gz'));
-  }).then((_) {
-    // 7zip can't unarchive from gzip -> tar -> destination all in one step
-    // first we un-gzip it to a tar file.
-    // Note: Setting the working directory instead of passing in a full file
-    // path because 7zip says "A full path is not allowed here."
-    return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir);
-  }).then((result) {
-    if (result.exitCode != 0) {
-      throw 'Could not un-gzip (exit code ${result.exitCode}). Error:\n'
-          '${Strings.join(result.stdout, "\n")}\n'
-          '${Strings.join(result.stderr, "\n")}';
-    }
-    // Find the tar file we just created since we don't know its name.
-    return listDir(tempDir);
-  }).then((files) {
-    var tarFile;
-    for (var file in files) {
-      if (path.extension(file) == '.tar') {
-        tarFile = file;
-        break;
+    return createFileFromStream(stream, join(tempDir, 'data.tar.gz')).then((_) {
+      // 7zip can't unarchive from gzip -> tar -> destination all in one step
+      // first we un-gzip it to a tar file.
+      // Note: Setting the working directory instead of passing in a full file
+      // path because 7zip says "A full path is not allowed here."
+      return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir);
+    }).then((result) {
+      if (result.exitCode != 0) {
+        throw 'Could not un-gzip (exit code ${result.exitCode}). Error:\n'
+            '${Strings.join(result.stdout, "\n")}\n'
+            '${Strings.join(result.stderr, "\n")}';
       }
-    }
+      // Find the tar file we just created since we don't know its name.
+      return listDir(tempDir);
+    }).then((files) {
+      var tarFile;
+      for (var file in files) {
+        if (path.extension(file) == '.tar') {
+          tarFile = file;
+          break;
+        }
+      }
 
-    if (tarFile == null) throw 'The gzip file did not contain a tar file.';
+      if (tarFile == null) throw 'The gzip file did not contain a tar file.';
 
-    // Untar the archive into the destination directory.
-    return runProcess(command, ['x', tarFile], workingDir: destination);
-  }).then((result) {
-    if (result.exitCode != 0) {
-      throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n'
-          '${Strings.join(result.stdout, "\n")}\n'
-          '${Strings.join(result.stderr, "\n")}';
-    }
-
-    log.fine('Clean up 7zip temp directory ${tempDir.path}.');
-    // TODO(rnystrom): Should also delete this if anything fails.
-    return deleteDir(tempDir);
-  }).then((_) => true);
+      // Untar the archive into the destination directory.
+      return runProcess(command, ['x', tarFile], workingDir: destination);
+    }).then((result) {
+      if (result.exitCode != 0) {
+        throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n'
+            '${Strings.join(result.stdout, "\n")}\n'
+            '${Strings.join(result.stderr, "\n")}';
+      }
+      return true;
+    });
+  });
 }
 
 /// Create a .tar.gz archive from a list of entries. Each entry can be a
diff --git a/utils/pub/log.dart b/utils/pub/log.dart
index 43499ef..06a4748 100644
--- a/utils/pub/log.dart
+++ b/utils/pub/log.dart
@@ -208,7 +208,7 @@
   _logToStream(stderrSink, entry, showLabel: true);
 }
 
-void _logToStream(Sink<List<int>> sink, Entry entry, {bool showLabel}) {
+void _logToStream(StreamSink<List<int>> sink, Entry entry, {bool showLabel}) {
   bool firstLine = true;
   for (var line in entry.lines) {
     if (showLabel) {
diff --git a/utils/pub/pub.dart b/utils/pub/pub.dart
index db628d0..302420f 100644
--- a/utils/pub/pub.dart
+++ b/utils/pub/pub.dart
@@ -121,20 +121,37 @@
     cacheDir = '${Platform.environment['HOME']}/.pub-cache';
   }
 
-  var cache = new SystemCache.withSources(cacheDir);
+  validatePlatform().then((_) {
+    var cache = new SystemCache.withSources(cacheDir);
 
-  // Select the command.
-  var command = pubCommands[globalOptions.rest[0]];
-  if (command == null) {
-    log.error('Could not find a command named "${globalOptions.rest[0]}".');
-    log.error('Run "pub help" to see available commands.');
-    exit(exit_codes.USAGE);
-    return;
-  }
+    // Select the command.
+    var command = pubCommands[globalOptions.rest[0]];
+    if (command == null) {
+      log.error('Could not find a command named "${globalOptions.rest[0]}".');
+      log.error('Run "pub help" to see available commands.');
+      exit(exit_codes.USAGE);
+      return;
+    }
 
-  var commandArgs =
-      globalOptions.rest.getRange(1, globalOptions.rest.length - 1);
-  command.run(cache, globalOptions, commandArgs);
+    var commandArgs =
+        globalOptions.rest.getRange(1, globalOptions.rest.length - 1);
+    command.run(cache, globalOptions, commandArgs);
+  });
+}
+
+/// Checks that pub is running on a supported platform. If it isn't, it prints
+/// an error message and exits. Completes when the validation is done.
+Future validatePlatform() {
+  return defer(() {
+    if (Platform.operatingSystem != 'windows') return;
+
+    return runProcess('ver', []).then((result) {
+      if (result.stdout.join('\n').contains('XP')) {
+        log.error('Sorry, but pub is not supported on Windows XP.');
+        exit(exit_codes.USAGE);
+      }
+    });
+  });
 }
 
 /// Displays usage information for the app.
diff --git a/utils/pub/system_cache.dart b/utils/pub/system_cache.dart
index 4041e40..13e6b8d 100644
--- a/utils/pub/system_cache.dart
+++ b/utils/pub/system_cache.dart
@@ -63,6 +63,8 @@
   /// Gets the package identified by [id]. If the package is already cached,
   /// reads it from the cache. Otherwise, requests it from the source.
   Future<Pubspec> describe(PackageId id) {
+    if (id.isRoot) throw new ArgumentError("Cannot describe the root package.");
+
     // Try to get it from the system cache first.
     if (id.source.shouldCache) {
       return id.systemCacheDirectory.then((packageDir) {
@@ -99,11 +101,9 @@
   /// packages into while installing. It uses this instead of the OS's system
   /// temp directory to ensure that it's on the same volume as the pub system
   /// cache so that it can move the directory from it.
-  Future<Directory> createTempDir() {
-    return defer(() {
-      var temp = ensureDir(tempDir);
-      return io.createTempDir(join(temp, 'dir'));
-    });
+  Directory createTempDir() {
+    var temp = ensureDir(tempDir);
+    return io.createTempDir(join(temp, 'dir'));
   }
 
   /// Delete's the system cache's internal temp directory.
diff --git a/utils/tests/pub/pub_lish_test.dart b/utils/tests/pub/pub_lish_test.dart
index 7101d91..482b616 100644
--- a/utils/tests/pub/pub_lish_test.dart
+++ b/utils/tests/pub/pub_lish_test.dart
@@ -38,7 +38,9 @@
   server.handle('POST', '/upload', (request, response) {
     // TODO(nweiz): Once a multipart/form-data parser in Dart exists, validate
     // that the request body is correctly formatted. See issue 6952.
-    return server.url.then((url) {
+    return drainInputStream(request.inputStream).then((_) {
+      return server.url;
+    }).then((url) {
       response.statusCode = 302;
       response.headers.set('location', url.resolve('/create').toString());
       response.outputStream.close();
@@ -260,11 +262,13 @@
     handleUploadForm(server);
 
     server.handle('POST', '/upload', (request, response) {
-      response.statusCode = 400;
-      response.headers.contentType = new ContentType('application', 'xml');
-      response.outputStream.writeString('<Error><Message>Your request sucked.'
-          '</Message></Error>');
-      response.outputStream.close();
+      return drainInputStream(request.inputStream).then((_) {
+        response.statusCode = 400;
+        response.headers.contentType = new ContentType('application', 'xml');
+        response.outputStream.writeString('<Error><Message>Your request sucked.'
+            '</Message></Error>');
+        response.outputStream.close();
+      });
     });
 
     // TODO(nweiz): This should use the server's error message once the client
@@ -282,8 +286,10 @@
     handleUploadForm(server);
 
     server.handle('POST', '/upload', (request, response) {
-      // don't set the location header
-      response.outputStream.close();
+      return drainInputStream(request.inputStream).then((_) {
+        // Don't set the location header.
+        response.outputStream.close();
+      });
     });
 
     expectLater(pub.nextErrLine(), equals('Failed to upload the package.'));
diff --git a/utils/tests/pub/pub_test.dart b/utils/tests/pub/pub_test.dart
index bbc8e40..3a9db1fd 100644
--- a/utils/tests/pub/pub_test.dart
+++ b/utils/tests/pub/pub_test.dart
@@ -42,6 +42,8 @@
     ''';
 
 main() {
+  initConfig();
+  
   integration('running pub with no command displays usage', () {
     schedulePub(args: [], output: USAGE_STRING);
   });
diff --git a/utils/tests/pub/sdk_constraint_test.dart b/utils/tests/pub/sdk_constraint_test.dart
index 3f934b9..33d4686 100644
--- a/utils/tests/pub/sdk_constraint_test.dart
+++ b/utils/tests/pub/sdk_constraint_test.dart
@@ -117,5 +117,40 @@
             or adding a version constraint to use an older version of a package.
             """);
     });
+
+    integration("handles a circular dependency on the root package", () {
+      // Using an SDK source, but this should be true of all sources.
+      dir(sdkPath, [
+        dir("pkg", [
+          dir("foo", [
+            libPubspec("foo", "0.0.1", sdk: ">3.0.0", deps: [
+              {"sdk": "myapp"}
+            ]),
+            libDir("foo")
+          ])
+        ])
+      ]).scheduleCreate();
+
+      dir(appPath, [
+        pubspec({
+          "name": "myapp",
+          "dependencies": {
+            "foo": { "sdk": "foo" }
+          },
+          "environment": {"sdk": ">2.0.0"}
+        })
+      ]).scheduleCreate();
+
+      schedulePub(args: [command],
+          error:
+            """
+            Some packages are not compatible with your SDK version 0.1.2+3:
+            - 'myapp' requires >2.0.0
+            - 'foo' requires >3.0.0
+
+            You may be able to resolve this by upgrading to the latest Dart SDK
+            or adding a version constraint to use an older version of a package.
+            """);
+    });
   }
 }
diff --git a/utils/tests/pub/test_pub.dart b/utils/tests/pub/test_pub.dart
index c799ce7..63301f4 100644
--- a/utils/tests/pub/test_pub.dart
+++ b/utils/tests/pub/test_pub.dart
@@ -494,24 +494,21 @@
     // Run all of the scheduled tasks. If an error occurs, it will propagate
     // through the futures back up to here where we can hand it off to unittest.
     var asyncDone = expectAsync0(() {});
-    var createdSandboxDir;
-    _setUpSandbox().then((sandboxDir) {
-      createdSandboxDir = sandboxDir;
-      return timeout(_runScheduled(sandboxDir, _scheduled),
-          _TIMEOUT, 'waiting for a test to complete');
-    }).catchError((e) {
-      return _runScheduled(createdSandboxDir, _scheduledOnException).then((_) {
+    var sandboxDir = createTempDir();
+    return timeout(_runScheduled(sandboxDir, _scheduled),
+          _TIMEOUT, 'waiting for a test to complete').catchError((e) {
+      return _runScheduled(sandboxDir, _scheduledOnException).then((_) {
         // Rethrow the original error so it keeps propagating.
         throw e;
       });
     }).whenComplete(() {
       // Clean up after ourselves. Do this first before reporting back to
       // unittest because it will advance to the next test immediately.
-      return _runScheduled(createdSandboxDir, _scheduledCleanup).then((_) {
+      return _runScheduled(sandboxDir, _scheduledCleanup).then((_) {
         _scheduled = null;
         _scheduledCleanup = null;
         _scheduledOnException = null;
-        if (createdSandboxDir != null) return deleteDir(createdSandboxDir);
+        if (sandboxDir != null) return deleteDir(sandboxDir);
       });
     }).then((_) {
       // If we got here, the test completed successfully so tell unittest so.
@@ -680,8 +677,6 @@
   });
 }
 
-Future<Directory> _setUpSandbox() => createTempDir();
-
 Future _runScheduled(Directory parentDir, List<_ScheduledEvent> scheduled) {
   if (scheduled == null) return new Future.immediate(null);
   var iterator = scheduled.iterator;
@@ -1104,17 +1099,13 @@
   /// Creates the files and directories within this tar file, then archives
   /// them, compresses them, and saves the result to [parentDir].
   Future<File> create(parentDir) {
-    // TODO(rnystrom): Use withTempDir().
-    var tempDir;
-    return createTempDir().then((_tempDir) {
-      tempDir = _tempDir;
-      return Future.wait(contents.map((child) => child.create(tempDir)));
-    }).then((createdContents) {
-      return createTarGz(createdContents, baseDir: tempDir).toBytes();
-    }).then((bytes) {
-      return new File(join(parentDir, _stringName)).writeAsBytes(bytes);
-    }).then((file) {
-      return deleteDir(tempDir).then((_) => file);
+    return withTempDir((tempDir) {
+      return Future.wait(contents.map((child) => child.create(tempDir)))
+          .then((createdContents) {
+        return createTarGz(createdContents, baseDir: tempDir).toBytes();
+      }).then((bytes) {
+        return new File(join(parentDir, _stringName)).writeAsBytes(bytes);
+      });
     });
   }
 
@@ -1136,16 +1127,11 @@
     }
 
     var controller = new StreamController<List<int>>();
-    var tempDir;
-    // TODO(rnystrom): Use withTempDir() here.
     // TODO(nweiz): propagate any errors to the return value. See issue 3657.
-    createTempDir().then((_tempDir) {
-      tempDir = _tempDir;
-      return create(tempDir);
-    }).then((tar) {
-      var sourceStream = tar.openInputStream();
-      return store(wrapInputStream(sourceStream), controller).then((_) {
-        tempDir.delete(recursive: true);
+    withTempDir((tempDir) {
+      return create(tempDir).then((tar) {
+        var sourceStream = tar.openInputStream();
+        return store(wrapInputStream(sourceStream), controller);
       });
     });
     return new ByteStream(controller.stream);