Version 0.3.6.2 .

svn merge -r 18445:18527 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@18539 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/dart.gyp b/dart.gyp
index d206fcc..c988d74 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -95,6 +95,17 @@
       ],
     },
     {
+      # This is the target that is built on the dartc bots.
+      # It must depend on anything that is required by dartc
+      # tests.
+      'target_name': 'dartc_bot',
+      'type': 'none',
+      'dependencies': [
+        'create_sdk',
+        'packages',
+      ],
+    },
+    {
       # This is the target that is built on the dart2js build bots.
       # It must depend on anything that is required by the dart2js
       # test suites.
diff --git a/pkg/intl/lib/bidi_utils.dart b/pkg/intl/lib/bidi_utils.dart
index b6bb007..35d62b7 100644
--- a/pkg/intl/lib/bidi_utils.dart
+++ b/pkg/intl/lib/bidi_utils.dart
@@ -353,22 +353,6 @@
   }
 
   /**
-   * Find the first index in [str] of the first closing parenthesis that does
-   * not match an opening parenthesis.
-   */
-  static int _unmatchedParenIndex(String str) {
-    int sum = 0;
-    int index = 0;
-    while (sum >= 0 || index > str.length) {
-      int char = str.charCodeAt(index);
-      if (char == '('.charCodeAt(0))  sum++;
-      else if (char == ')'.charCodeAt(0)) sum--;
-      index++;
-    }
-    return index;
-  }
-
-  /**
    * Replace the double and single quote directly after a Hebrew character in
    * [str] with GERESH and GERSHAYIM. This is most likely the user's intention.
    */
diff --git a/pkg/intl/lib/number_format.dart b/pkg/intl/lib/number_format.dart
index 4f75d63..76f8afa 100644
--- a/pkg/intl/lib/number_format.dart
+++ b/pkg/intl/lib/number_format.dart
@@ -258,10 +258,14 @@
   }
 
   /** Returns the code point for the character '0'. */
-  int get _zero => '0'.charCodes[0];
+  int get _zero => '0'.codeUnits.first;
 
   /** Returns the code point for the locale's zero digit. */
-  int get _localeZero => symbols.ZERO_DIGIT.charCodeAt(0);
+  // Note that there is a slight risk of a locale's zero digit not fitting
+  // into a single code unit, but it seems very unlikely, and if it did,
+  // there's a pretty good chance that our assumptions about being able to do
+  // arithmetic on it would also be invalid.
+  int get _localeZero => symbols.ZERO_DIGIT.codeUnits.first;
 
   /**
    * Returns the prefix for [x] based on whether it's positive or negative.
diff --git a/pkg/oauth2/lib/src/utils.dart b/pkg/oauth2/lib/src/utils.dart
index bcff589..83fe2b7 100644
--- a/pkg/oauth2/lib/src/utils.dart
+++ b/pkg/oauth2/lib/src/utils.dart
@@ -113,4 +113,5 @@
 }
 
 /// Returns a [Future] that asynchronously completes to `null`.
-Future get async => new Future.delayed(0, () => null);
+Future get async => new Future.delayed(const Duration(milliseconds: 0),
+                                       () => null);
diff --git a/pkg/pkg.status b/pkg/pkg.status
index a241322..69fbaee 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -49,7 +49,6 @@
 [ $runtime == vm ]
 intl/test/find_default_locale_browser_test: Skip
 intl/test/date_time_format_http_request_test: Skip
-serialization/test/serialization_test: Pass, Fail # Temporary workaround for flakiness
 
 [ $runtime == vm && $system == windows ]
 intl/test/find_default_locale_standalone_test: Fail # Issue 8110
diff --git a/pkg/serialization/lib/src/format.dart b/pkg/serialization/lib/src/format.dart
index ab602c9..a1726f0 100644
--- a/pkg/serialization/lib/src/format.dart
+++ b/pkg/serialization/lib/src/format.dart
@@ -154,9 +154,15 @@
    * to turn References into a nested List/Map.
    */
   jsonifyEntry(map, Writer w) {
+    // Note, if this is a Map, and the key might be a reference, we need to
+    // bend over backwards to avoid concurrent modifications. Non-string keys
+    // won't actually work if we try to write this to json, but might happen
+    // if e.g. sending between isolates.
+    var updates = new Map();
     keysAndValues(map).forEach((key, value) {
-      if (value is Reference) map[key] = w.stateForReference(value);
+      if (value is Reference) updates[key] = w.stateForReference(value);
     });
+    updates.forEach((k, v) => map[k] = v);
   }
 
   /**
diff --git a/pkg/serialization/test/serialization_test.dart b/pkg/serialization/test/serialization_test.dart
index d45f562..5a9cc49 100644
--- a/pkg/serialization/test/serialization_test.dart
+++ b/pkg/serialization/test/serialization_test.dart
@@ -386,6 +386,20 @@
     expect(a2.city, "Seattle");
   });
 
+  test("Straight JSON format, non-string key", () {
+    // This tests what happens if we have a key that's not a string. That's
+    // not allowed by json, so we don't actually turn it into a json string,
+    // but someone might reasonably convert to a json-able structure without
+    // going through the string representation.
+    var p1 = new Person()..name = 'Alice'..address = a1;
+    var s = new Serialization()
+        ..addRule(new PersonRuleReturningMapWithNonStringKey());
+    var p2 = writeAndReadBack(s,
+        new SimpleJsonFormat(storeRoundTripInfo: true), p1);
+    expect(p2.name, "Alice");
+    expect(p2.address.street, "N 34th");
+  });
+
   test("Root is a Map", () {
     // Note that we can't use the usual round-trip test because it has cycles.
     var p1 = new Person()..name = 'Alice'..address = a1;
@@ -704,3 +718,31 @@
     node.children = state[2];
   }
 }
+
+/**
+ * This is a rather silly rule which stores the address data in a map,
+ * but inverts the keys and values, so we look up values and find the
+ * corresponding key. This will lead to maps that aren't allowed in JSON,
+ * and which have keys that need to be dereferenced.
+ */
+class PersonRuleReturningMapWithNonStringKey extends CustomRule {
+  appliesTo(instance, _) => instance is Person;
+  getState(instance) {
+    return new Map()
+      ..[instance.name] = "name"
+      ..[instance.address] = "address";
+  }
+  create(state) => new Person();
+  setState(Person a, state) {
+    a.name = findValue("name", state);
+    a.address = findValue("address", state);
+  }
+  findValue(String key, Map state) {
+    var answer;
+    for (var each in state.keys) {
+      var value = state[each];
+      if (value == key) return each;
+    }
+    return null;
+  }
+}
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 9d8f6f3..84242c6 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -9,51 +9,75 @@
 
 #include "bin/log.h"
 
-// Forward declaration.
+class PathBuffer {
+ public:
+  PathBuffer() : length(0) { }
+
+  wchar_t data[MAX_PATH + 1];
+  int length;
+
+  bool Add(const wchar_t* name) {
+    size_t written = _snwprintf(data + length,
+                               MAX_PATH - length,
+                               L"%s",
+                               name);
+    data[MAX_PATH] = L'\0';
+    if (written == wcsnlen(name, MAX_PATH + 1)) {
+      length += written;
+      return true;
+    } else {
+      SetLastError(ERROR_BUFFER_OVERFLOW);
+      return false;
+    }
+  }
+
+  void Reset(int new_length) {
+    length = new_length;
+    data[length] = L'\0';
+  }
+};
+
+
+// Forward declarations.
 static bool ListRecursively(const wchar_t* dir_name,
                             bool recursive,
                             DirectoryListing* listing);
 static bool DeleteRecursively(const wchar_t* dir_name);
 
 
+static void PostError(DirectoryListing* listing,
+                      const wchar_t* dir_name) {
+  const char* utf8_path = StringUtils::WideToUtf8(dir_name);
+  listing->HandleError(utf8_path);
+  free(const_cast<char*>(utf8_path));
+}
+
+
 static bool HandleDir(wchar_t* dir_name,
-                      wchar_t* path,
-                      int path_length,
+                      PathBuffer* path,
                       bool recursive,
                       DirectoryListing* listing) {
-  if (wcscmp(dir_name, L".") != 0 &&
-      wcscmp(dir_name, L"..") != 0) {
-    size_t written = _snwprintf(path + path_length,
-                                MAX_PATH - path_length,
-                                L"%s",
-                                dir_name);
-    if (written != wcslen(dir_name)) {
-      return false;
-    }
-    char* utf8_path = StringUtils::WideToUtf8(path);
-    bool ok = listing->HandleDirectory(utf8_path);
-    free(utf8_path);
-    if (!ok) return ok;
-    if (recursive) {
-      return ListRecursively(path, recursive, listing);
-    }
+  if (wcscmp(dir_name, L".") == 0) return true;
+  if (wcscmp(dir_name, L"..") == 0) return true;
+  if (!path->Add(dir_name)) {
+    PostError(listing, path->data);
+    return false;
   }
-  return true;
+  char* utf8_path = StringUtils::WideToUtf8(path->data);
+  bool ok = listing->HandleDirectory(utf8_path);
+  free(utf8_path);
+  return ok && (!recursive || ListRecursively(path->data, recursive, listing));
 }
 
 
 static bool HandleFile(wchar_t* file_name,
-                       wchar_t* path,
-                       int path_length,
+                       PathBuffer* path,
                        DirectoryListing* listing) {
-  size_t written = _snwprintf(path + path_length,
-                              MAX_PATH - path_length,
-                              L"%s",
-                              file_name);
-  if (written != wcslen(file_name)) {
+  if (!path->Add(file_name)) {
+    PostError(listing, path->data);
     return false;
-  };
-  char* utf8_path = StringUtils::WideToUtf8(path);
+  }
+  char* utf8_path = StringUtils::WideToUtf8(path->data);
   bool ok = listing->HandleFile(utf8_path);
   free(utf8_path);
   return ok;
@@ -61,55 +85,42 @@
 
 
 static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data,
-                        wchar_t* path,
-                        int path_length,
+                        PathBuffer* path,
                         bool recursive,
                         DirectoryListing* listing) {
   DWORD attributes = find_file_data->dwFileAttributes;
   if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
     return HandleDir(find_file_data->cFileName,
                      path,
-                     path_length,
                      recursive,
                      listing);
   } else {
-    return HandleFile(find_file_data->cFileName, path, path_length, listing);
+    return HandleFile(find_file_data->cFileName, path, listing);
   }
 }
 
 
-// ComputeFullSearchPath must be called with a path array of size at
-// least MAX_PATH.
-static bool ComputeFullSearchPath(const wchar_t* dir_name,
-                                  wchar_t* path,
-                                  int* path_length) {
+static PathBuffer* ComputeFullSearchPath(const wchar_t* dir_name) {
   // GetFullPathName only works in a multi-threaded environment if
   // SetCurrentDirectory is not used. We currently have no plan for
   // exposing SetCurrentDirectory.
-  size_t written = GetFullPathNameW(dir_name, MAX_PATH, path, NULL);
+  PathBuffer* path = new PathBuffer();
+
+  size_t written = GetFullPathNameW(dir_name, MAX_PATH + 1, path->data, NULL);
   // GetFullPathName only accepts input strings of size less than
   // MAX_PATH and returns 0 to indicate failure for paths longer than
   // that. Therefore the path buffer is always big enough.
   if (written == 0 || written > MAX_PATH) {
-    return false;
+    delete path;
+    return NULL;
   }
-  *path_length = written;
-  written = _snwprintf(path + *path_length,
-                       MAX_PATH - *path_length,
-                       L"%s",
-                       L"\\*");
-  if (written != 2) {
-    return false;
+  path->length = written;
+  if (path->Add(L"\\*")) {
+    return path;
+  } else {
+    delete path;
+    return NULL;
   }
-  *path_length += written;
-  return true;
-}
-
-static void PostError(DirectoryListing* listing,
-                      const wchar_t* dir_name) {
-  const char* utf8_path = StringUtils::WideToUtf8(dir_name);
-  listing->HandleError(utf8_path);
-  free(const_cast<char*>(utf8_path));
 }
 
 
@@ -121,38 +132,35 @@
   // 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.
-  wchar_t* path = static_cast<wchar_t*>(malloc(MAX_PATH * sizeof(wchar_t)));
-  int path_length = 0;
-  bool valid = ComputeFullSearchPath(dir_name, path, &path_length);
-  if (!valid) {
+  PathBuffer* path = ComputeFullSearchPath(dir_name);
+  if (path == NULL) {
     PostError(listing, dir_name);
-    free(path);
+    delete path;
     return false;
   }
 
   WIN32_FIND_DATAW find_file_data;
-  HANDLE find_handle = FindFirstFileW(path, &find_file_data);
+  HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
 
   // Adjust the path by removing the '*' used for the search.
-  path_length -= 1;
-  path[path_length] = '\0';
+  path->Reset(path->length - 1);
 
   if (find_handle == INVALID_HANDLE_VALUE) {
-    PostError(listing, path);
-    free(path);
+    PostError(listing, path->data);
+    delete path;
     return false;
   }
 
+  int path_length = path->length;
   bool success = HandleEntry(&find_file_data,
                              path,
-                             path_length,
                              recursive,
                              listing);
 
   while ((FindNextFileW(find_handle, &find_file_data) != 0)) {
+    path->Reset(path_length);  // HandleEntry adds the entry name to path.
     success = HandleEntry(&find_file_data,
                           path,
-                          path_length,
                           recursive,
                           listing) && success;
   }
@@ -166,24 +174,16 @@
     success = false;
     PostError(listing, dir_name);
   }
-  free(path);
+  delete path;
 
   return success;
 }
 
 
-static bool DeleteFile(wchar_t* file_name,
-                       wchar_t* path,
-                       int path_length) {
-  size_t written = _snwprintf(path + path_length,
-                              MAX_PATH - path_length,
-                              L"%s",
-                              file_name);
-  if (written != wcslen(file_name)) {
-    return false;
-  }
+static bool DeleteFile(wchar_t* file_name, PathBuffer* path) {
+  if (!path->Add(file_name)) return false;
 
-  if (DeleteFileW(path) != 0) {
+  if (DeleteFileW(path->data) != 0) {
     return true;
   }
 
@@ -191,7 +191,7 @@
   // again. This mirrors Linux/Mac where a directory containing read-only files
   // can still be recursively deleted.
   if (GetLastError() == ERROR_ACCESS_DENIED) {
-    DWORD attributes = GetFileAttributesW(path);
+    DWORD attributes = GetFileAttributesW(path->data);
     if (attributes == INVALID_FILE_ATTRIBUTES) {
       return false;
     }
@@ -199,11 +199,11 @@
     if ((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) {
       attributes &= ~FILE_ATTRIBUTE_READONLY;
 
-      if (SetFileAttributesW(path, attributes) == 0) {
+      if (SetFileAttributesW(path->data, attributes) == 0) {
         return false;
       }
 
-      return DeleteFileW(path) != 0;
+      return DeleteFileW(path->data) != 0;
     }
   }
 
@@ -211,33 +211,20 @@
 }
 
 
-static bool DeleteDir(wchar_t* dir_name,
-                      wchar_t* path,
-                      int path_length) {
-  if (wcscmp(dir_name, L".") != 0 &&
-      wcscmp(dir_name, L"..") != 0) {
-    size_t written = _snwprintf(path + path_length,
-                                MAX_PATH - path_length,
-                                L"%s",
-                                dir_name);
-    if (written != wcslen(dir_name)) {
-      return false;
-    }
-    return DeleteRecursively(path);
-  }
-  return true;
+static bool DeleteDir(wchar_t* dir_name, PathBuffer* path) {
+  if (wcscmp(dir_name, L".") == 0) return true;
+  if (wcscmp(dir_name, L"..") == 0) return true;
+  return path->Add(dir_name) && DeleteRecursively(path->data);
 }
 
 
-static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data,
-                        wchar_t* path,
-                        int path_length) {
+static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data, PathBuffer* path) {
   DWORD attributes = find_file_data->dwFileAttributes;
 
   if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
-    return DeleteDir(find_file_data->cFileName, path, path_length);
+    return DeleteDir(find_file_data->cFileName, path);
   } else {
-    return DeleteFile(find_file_data->cFileName, path, path_length);
+    return DeleteFile(find_file_data->cFileName, path);
   }
 }
 
@@ -257,33 +244,29 @@
   // 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.
-  wchar_t* path = static_cast<wchar_t*>(malloc(MAX_PATH * sizeof(wchar_t)));
-  int path_length = 0;
-  bool valid = ComputeFullSearchPath(dir_name, path, &path_length);
-  if (!valid) {
-    free(path);
-    return false;
-  }
+  PathBuffer* path = ComputeFullSearchPath(dir_name);
+  if (path == NULL) return false;
 
   WIN32_FIND_DATAW find_file_data;
-  HANDLE find_handle = FindFirstFileW(path, &find_file_data);
+  HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
 
   // Adjust the path by removing the '*' used for the search.
-  path_length -= 1;
-  path[path_length] = '\0';
+  int path_length = path->length - 1;
+  path->Reset(path_length);
 
   if (find_handle == INVALID_HANDLE_VALUE) {
-    free(path);
+    delete path;
     return false;
   }
 
-  bool success = DeleteEntry(&find_file_data, path, path_length);
+  bool success = DeleteEntry(&find_file_data, path);
 
   while ((FindNextFileW(find_handle, &find_file_data) != 0) && success) {
-    success = success && DeleteEntry(&find_file_data, path, path_length);
+    path->Reset(path_length);  // DeleteEntry adds to the path.
+    success = success && DeleteEntry(&find_file_data, path);
   }
 
-  free(path);
+  delete path;
 
   if ((GetLastError() != ERROR_NO_MORE_FILES) ||
       (FindClose(find_handle) == 0) ||
@@ -362,52 +345,51 @@
   // dir_template.  Creates this directory, with a default security
   // descriptor inherited from its parent directory.
   // The return value must be freed by the caller.
-  wchar_t* path = static_cast<wchar_t*>(malloc(MAX_PATH * sizeof(wchar_t)));
-  int path_length;
+  PathBuffer* path = new PathBuffer();
   if (0 == strncmp(const_template, "", 1)) {
-    path_length = GetTempPathW(MAX_PATH, path);
-    if (path_length == 0) {
-      free(path);
+    path->length = GetTempPathW(MAX_PATH, path->data);
+    if (path->length == 0) {
+      delete path;
       return NULL;
     }
   } else {
     const wchar_t* system_template = StringUtils::Utf8ToWide(const_template);
-    _snwprintf(path, MAX_PATH, L"%s", system_template);
+    path->Add(system_template);
     free(const_cast<wchar_t*>(system_template));
-    path_length = wcslen(path);
   }
   // Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44.
-  if (path_length > MAX_PATH - 44) {
-    free(path);
+  if (path->length > MAX_PATH - 44) {
+    delete path;
     return NULL;
   }
-  if ((path)[path_length - 1] == L'\\') {
+  if ((path->data)[path->length - 1] == L'\\') {
     // No base name for the directory - use "tempdir".
-    _snwprintf(path + path_length, MAX_PATH - path_length, L"tempdir");
-    path_length = wcslen(path);
+    path->Add(L"tempdir");
   }
 
   UUID uuid;
   RPC_STATUS status = UuidCreateSequential(&uuid);
   if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
-    free(path);
+    delete path;
     return NULL;
   }
   RPC_WSTR uuid_string;
   status = UuidToStringW(&uuid, &uuid_string);
   if (status != RPC_S_OK) {
-    free(path);
+    delete path;
     return NULL;
   }
 
-  _snwprintf(path + path_length, MAX_PATH - path_length, L"-%s", uuid_string);
+  path->Add(L"-");
+  // RPC_WSTR is an unsigned short*, so we cast to wchar_t*.
+  path->Add(reinterpret_cast<wchar_t*>(uuid_string));
   RpcStringFreeW(&uuid_string);
-  if (!CreateDirectoryW(path, NULL)) {
-    free(path);
+  if (!CreateDirectoryW(path->data, NULL)) {
+    delete path;
     return NULL;
   }
-  char* result = StringUtils::WideToUtf8(path);
-  free(path);
+  char* result = StringUtils::WideToUtf8(path->data);
+  delete path;
   return result;
 }
 
diff --git a/runtime/lib/string_base.dart b/runtime/lib/string_base.dart
index 2a777c2..8b28aae 100644
--- a/runtime/lib/string_base.dart
+++ b/runtime/lib/string_base.dart
@@ -433,9 +433,7 @@
     return result;
   }
 
-  Iterable<int> get codeUnits {
-    throw new UnimplementedError("String.codeUnits");
-  }
+  Iterable<int> get codeUnits => new CodeUnits(this);
 
   Runes get runes => new Runes(this);
 
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 0e352c6..176246e 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -79,15 +79,47 @@
 #if defined(_M_X64) || defined(__x86_64__)
 #define HOST_ARCH_X64 1
 #define ARCH_IS_64_BIT 1
+#include <xmmintrin.h>  // NOLINT
+#define kFpuRegisterSize 16
+typedef __m128 fpu_register_t;
+typedef __m128 simd_value_t;
+// Unaligned load.
+#define simd_value_safe_load(addr)                                             \
+  _mm_loadu_ps(reinterpret_cast<const float*>(addr))
+// Unaligned store.
+#define simd_value_safe_store(addr, value)                                     \
+  _mm_storeu_ps(reinterpret_cast<float*>(addr), value)
 #elif defined(_M_IX86) || defined(__i386__)
 #define HOST_ARCH_IA32 1
 #define ARCH_IS_32_BIT 1
+#include <xmmintrin.h>  // NOLINT
+#define kFpuRegisterSize 16
+typedef __m128 fpu_register_t;
+typedef __m128 simd_value_t;
+// Unaligned load.
+#define simd_value_safe_load(addr)                                             \
+  _mm_loadu_ps(reinterpret_cast<const float*>(addr))
+// Unaligned store.
+#define simd_value_safe_store(addr, value)                                     \
+  _mm_storeu_ps(reinterpret_cast<float*>(addr), value)
 #elif defined(__ARMEL__)
 #define HOST_ARCH_ARM 1
 #define ARCH_IS_32_BIT 1
+#define kFpuRegisterSize 8
+typedef double fpu_register_t;
+// TODO(johnmccutchan): ARM simd type.
+typedef struct {
+  uint32_t data_[4];
+} simd_value_t;
 #elif defined(__MIPSEL__)
 #define HOST_ARCH_MIPS 1
 #define ARCH_IS_32_BIT 1
+#define kFpuRegisterSize 8
+typedef double fpu_register_t;
+// TODO(johnmccutchan): MIPS simd type.
+typedef struct {
+  uint32_t data_[4];
+} simd_value_t;
 #else
 #error Architecture was not detected as supported by Dart.
 #endif
@@ -169,7 +201,8 @@
 // Byte sizes.
 const int kWordSize = sizeof(word);
 const int kDoubleSize = sizeof(double);  // NOLINT
-const int kFloatSize = sizeof(float); // NOLINT
+const int kFloatSize = sizeof(float);  // NOLINT
+const int kSimd128Size = 16;
 #ifdef ARCH_IS_32_BIT
 const int kWordSizeLog2 = 2;
 const uword kUwordMax = kMaxUint32;
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 1e23316..bef0afb 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -505,6 +505,22 @@
 }
 
 
+void Assembler::movups(XmmRegister dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x10);
+  EmitOperand(dst, src);
+}
+
+
+void Assembler::movups(const Address& dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x11);
+  EmitOperand(src, dst);
+}
+
+
 void Assembler::addsd(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF2);
@@ -523,6 +539,227 @@
 }
 
 
+void Assembler::addps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x58);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::subps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x5C);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::divps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x5E);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::mulps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x59);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::minps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x5D);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::maxps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x5F);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::andps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x54);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::andps(XmmRegister dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x54);
+  EmitOperand(dst, src);
+}
+
+
+void Assembler::orps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x56);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::notps(XmmRegister dst) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } float_not_constant =
+      { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  xorps(dst,
+    Address::Absolute(reinterpret_cast<uword>(&float_not_constant)));
+}
+
+
+void Assembler::negateps(XmmRegister dst) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } float_negate_constant =
+      { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
+  xorps(dst,
+        Address::Absolute(reinterpret_cast<uword>(&float_negate_constant)));
+}
+
+
+void Assembler::absps(XmmRegister dst) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } float_absolute_constant =
+      { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
+  andps(dst,
+        Address::Absolute(reinterpret_cast<uword>(&float_absolute_constant)));
+}
+
+
+void Assembler::zerowps(XmmRegister dst) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } float_zerow_constant =
+      { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+  andps(dst, Address::Absolute(reinterpret_cast<uword>(&float_zerow_constant)));
+}
+
+
+void Assembler::cmppseq(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst, src);
+  EmitUint8(0x0);
+}
+
+
+void Assembler::cmppsneq(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst, src);
+  EmitUint8(0x4);
+}
+
+
+void Assembler::cmppslt(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst, src);
+  EmitUint8(0x1);
+}
+
+
+void Assembler::cmppsle(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst, src);
+  EmitUint8(0x2);
+}
+
+
+void Assembler::cmppsnlt(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst, src);
+  EmitUint8(0x5);
+}
+
+
+void Assembler::cmppsnle(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst, src);
+  EmitUint8(0x6);
+}
+
+
+void Assembler::sqrtps(XmmRegister dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x51);
+  EmitXmmRegisterOperand(dst, dst);
+}
+
+
+void Assembler::rsqrtps(XmmRegister dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x52);
+  EmitXmmRegisterOperand(dst, dst);
+}
+
+
+void Assembler::reciprocalps(XmmRegister dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x53);
+  EmitXmmRegisterOperand(dst, dst);
+}
+
+
+void Assembler::set1ps(XmmRegister dst, Register tmp1, const Immediate& imm) {
+  // Load 32-bit immediate value into tmp1.
+  movl(tmp1, imm);
+  // Move value from tmp1 into dst.
+  movd(dst, tmp1);
+  // Broadcast low lane into other three lanes.
+  shufps(dst, dst, Immediate(0x0));
+}
+
+
+void Assembler::shufps(XmmRegister dst, XmmRegister src, const Immediate& imm) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xC6);
+  EmitXmmRegisterOperand(dst, src);
+  ASSERT(imm.is_uint8());
+  EmitUint8(imm.value());
+}
+
+
 void Assembler::subsd(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF2);
@@ -684,6 +921,14 @@
 }
 
 
+void Assembler::movmskps(Register dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x50);
+  EmitXmmRegisterOperand(dst, src);
+}
+
+
 void Assembler::sqrtsd(XmmRegister dst, XmmRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF2);
@@ -1625,7 +1870,7 @@
 
 
 void Assembler::StoreIntoObject(Register object,
-                                const FieldAddress& dest,
+                                const Address& dest,
                                 Register value) {
   ASSERT(object != value);
   TraceStoreIntoObject(object, dest, value);
@@ -1642,7 +1887,7 @@
 
 
 void Assembler::StoreIntoObjectNoBarrier(Register object,
-                                         const FieldAddress& dest,
+                                         const Address& dest,
                                          Register value) {
   TraceStoreIntoObject(object, dest, value);
   movl(dest, value);
@@ -1659,7 +1904,7 @@
 
 
 void Assembler::StoreIntoObjectNoBarrier(Register object,
-                                         const FieldAddress& dest,
+                                         const Address& dest,
                                          const Object& value) {
   if (value.IsSmi() || value.InVMHeap()) {
     movl(dest, Immediate(reinterpret_cast<int32_t>(value.raw())));
@@ -1676,7 +1921,7 @@
 
 
 void Assembler::TraceStoreIntoObject(Register object,
-                                     const FieldAddress& dest,
+                                     const Address& dest,
                                      Register value) {
   if (HeapTrace::is_enabled()) {
     pushal();
@@ -1816,14 +2061,14 @@
   }
 
   // Preserve all XMM registers except XMM0
-  subl(ESP, Immediate((kNumberOfXmmRegisters - 1) * kDoubleSize));
+  subl(ESP, Immediate((kNumberOfXmmRegisters - 1) * kFpuRegisterSize));
   // Store XMM registers with the lowest register number at the lowest
   // address.
   intptr_t offset = 0;
   for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
     XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
-    movsd(Address(ESP, offset), xmm_reg);
-    offset += kDoubleSize;
+    movups(Address(ESP, offset), xmm_reg);
+    offset += kFpuRegisterSize;
   }
 
   ReserveAlignedFrameSpace(frame_space);
@@ -1836,7 +2081,7 @@
   // We need to restore it before restoring registers.
   const intptr_t kPushedRegistersSize =
       kNumberOfVolatileCpuRegisters * kWordSize +
-      kNumberOfVolatileXmmRegisters * kDoubleSize;
+      kNumberOfVolatileXmmRegisters * kFpuRegisterSize;
   leal(ESP, Address(EBP, -kPushedRegistersSize));
 
   // Restore all XMM registers except XMM0
@@ -1844,8 +2089,8 @@
   intptr_t offset = 0;
   for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
     XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
-    movsd(xmm_reg, Address(ESP, offset));
-    offset += kDoubleSize;
+    movups(xmm_reg, Address(ESP, offset));
+    offset += kFpuRegisterSize;
   }
   addl(ESP, Immediate(offset));
 
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 5c0c1cb..9fb8106 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -377,6 +377,9 @@
 
   void movaps(XmmRegister dst, XmmRegister src);
 
+  void movups(XmmRegister dst, const Address& src);
+  void movups(const Address& dst, XmmRegister src);
+
   void addsd(XmmRegister dst, XmmRegister src);
   void addsd(XmmRegister dst, const Address& src);
   void subsd(XmmRegister dst, XmmRegister src);
@@ -386,6 +389,33 @@
   void divsd(XmmRegister dst, XmmRegister src);
   void divsd(XmmRegister dst, const Address& src);
 
+
+  void addps(XmmRegister dst, XmmRegister src);
+  void subps(XmmRegister dst, XmmRegister src);
+  void divps(XmmRegister dst, XmmRegister src);
+  void mulps(XmmRegister dst, XmmRegister src);
+  void minps(XmmRegister dst, XmmRegister src);
+  void maxps(XmmRegister dst, XmmRegister src);
+  void andps(XmmRegister dst, XmmRegister src);
+  void andps(XmmRegister dst, const Address& src);
+  void orps(XmmRegister dst, XmmRegister src);
+  void notps(XmmRegister dst);
+  void negateps(XmmRegister dst);
+  void absps(XmmRegister dst);
+  void zerowps(XmmRegister dst);
+  void cmppseq(XmmRegister dst, XmmRegister src);
+  void cmppsneq(XmmRegister dst, XmmRegister src);
+  void cmppslt(XmmRegister dst, XmmRegister src);
+  void cmppsle(XmmRegister dst, XmmRegister src);
+  void cmppsnlt(XmmRegister dst, XmmRegister src);
+  void cmppsnle(XmmRegister dst, XmmRegister src);
+  void sqrtps(XmmRegister dst);
+  void rsqrtps(XmmRegister dst);
+  void reciprocalps(XmmRegister dst);
+
+  void set1ps(XmmRegister dst, Register tmp, const Immediate& imm);
+  void shufps(XmmRegister dst, XmmRegister src, const Immediate& mask);
+
   void cvtsi2ss(XmmRegister dst, Register src);
   void cvtsi2sd(XmmRegister dst, Register src);
 
@@ -404,6 +434,7 @@
   void comisd(XmmRegister a, XmmRegister b);
 
   void movmskpd(Register dst, XmmRegister src);
+  void movmskps(Register dst, XmmRegister src);
 
   void sqrtsd(XmmRegister dst, XmmRegister src);
   void sqrtss(XmmRegister dst, XmmRegister src);
@@ -575,18 +606,18 @@
   void LoadDoubleConstant(XmmRegister dst, double value);
 
   void StoreIntoObject(Register object,  // Object we are storing into.
-                       const FieldAddress& dest,  // Where we are storing into.
+                       const Address& dest,  // Where we are storing into.
                        Register value);  // Value we are storing.
 
   void StoreIntoObjectNoBarrier(Register object,
-                                const FieldAddress& dest,
+                                const Address& dest,
                                 Register value);
   void StoreIntoObjectNoBarrier(Register object,
-                                const FieldAddress& dest,
+                                const Address& dest,
                                 const Object& value);
 
   void TraceStoreIntoObject(Register object,
-                            const FieldAddress& dest,
+                            const Address& dest,
                             Register value);
 
   void DoubleNegate(XmmRegister d);
diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc
index 476ebd8..2a2c33d 100644
--- a/runtime/vm/assembler_ia32_test.cc
+++ b/runtime/vm/assembler_ia32_test.cc
@@ -834,6 +834,378 @@
 }
 
 
+ASSEMBLER_TEST_GENERATE(PackedFPOperations, assembler) {
+  __ movl(EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+  __ movd(XMM0, EAX);
+  __ shufps(XMM0, XMM0, Immediate(0x0));
+  __ movl(EAX, Immediate(bit_cast<int32_t, float>(3.4f)));
+  __ movd(XMM1, EAX);
+  __ shufps(XMM1, XMM1, Immediate(0x0));
+  __ addps(XMM0, XMM1);  // 15.7f
+  __ mulps(XMM0, XMM1);  // 53.38f
+  __ subps(XMM0, XMM1);  // 49.98f
+  __ divps(XMM0, XMM1);  // 14.7f
+  __ shufps(XMM0, XMM0, Immediate(0x55));  // Copy second lane into all 4 lanes.
+  __ pushl(EAX);
+  // Copy the low lane at ESP.
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedFPOperations, entry) {
+  typedef float (*PackedFPOperationsCode)();
+  float res = reinterpret_cast<PackedFPOperationsCode>(entry)();
+  EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedFPOperations2, assembler) {
+  __ movl(EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ movd(XMM0, EAX);
+  __ shufps(XMM0, XMM0, Immediate(0x0));
+
+  __ movaps(XMM1, XMM0);  // Copy XMM0
+  __ reciprocalps(XMM1);  // 0.25
+  __ sqrtps(XMM1);  // 0.5
+  __ rsqrtps(XMM0);  // ~0.5
+  __ subps(XMM0, XMM1);  // ~0.0
+  __ shufps(XMM0, XMM0, Immediate(0x00));  // Copy second lane into all 4 lanes.
+  __ pushl(EAX);
+  // Copy the low lane at ESP.
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedFPOperations2, entry) {
+  typedef float (*PackedFPOperations2Code)();
+  float res = reinterpret_cast<PackedFPOperations2Code>(entry)();
+  EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareEQ, assembler) {
+  __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppseq(XMM0, XMM1);
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareEQ, entry) {
+  typedef uint32_t (*PackedCompareEQCode)();
+  uint32_t res = reinterpret_cast<PackedCompareEQCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNEQ, assembler) {
+  __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppsneq(XMM0, XMM1);
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNEQ, entry) {
+  typedef uint32_t (*PackedCompareNEQCode)();
+  uint32_t res = reinterpret_cast<PackedCompareNEQCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareLT, assembler) {
+  __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppslt(XMM0, XMM1);
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareLT, entry) {
+  typedef uint32_t (*PackedCompareLTCode)();
+  uint32_t res = reinterpret_cast<PackedCompareLTCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareLE, assembler) {
+  __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppsle(XMM0, XMM1);
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareLE, entry) {
+  typedef uint32_t (*PackedCompareLECode)();
+  uint32_t res = reinterpret_cast<PackedCompareLECode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNLT, assembler) {
+  __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppsnlt(XMM0, XMM1);
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNLT, entry) {
+  typedef uint32_t (*PackedCompareNLTCode)();
+  uint32_t res = reinterpret_cast<PackedCompareNLTCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNLE, assembler) {
+  __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppsnle(XMM0, XMM1);
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNLE, entry) {
+  typedef uint32_t (*PackedCompareNLECode)();
+  uint32_t res = reinterpret_cast<PackedCompareNLECode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) {
+  __ movl(EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+  __ movd(XMM0, EAX);
+  __ shufps(XMM0, XMM0, Immediate(0x0));
+  __ negateps(XMM0);
+  __ shufps(XMM0, XMM0, Immediate(0xAA));  // Copy third lane into all 4 lanes.
+  __ pushl(EAX);
+  // Copy the low lane at ESP.
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedNegate, entry) {
+  typedef float (*PackedNegateCode)();
+  float res = reinterpret_cast<PackedNegateCode>(entry)();
+  EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) {
+  __ movl(EAX, Immediate(bit_cast<int32_t, float>(-15.3f)));
+  __ movd(XMM0, EAX);
+  __ shufps(XMM0, XMM0, Immediate(0x0));
+  __ absps(XMM0);
+  __ shufps(XMM0, XMM0, Immediate(0xAA));  // Copy third lane into all 4 lanes.
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedAbsolute, entry) {
+  typedef float (*PackedAbsoluteCode)();
+  float res = reinterpret_cast<PackedAbsoluteCode>(entry)();
+  EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) {
+  __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+  __ zerowps(XMM0);
+  __ shufps(XMM0, XMM0, Immediate(0xFF));  // Copy the W lane which is now 0.0.
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedSetWZero, entry) {
+  typedef float (*PackedSetWZeroCode)();
+  float res = reinterpret_cast<PackedSetWZeroCode>(entry)();
+  EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedMin, assembler) {
+  __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ minps(XMM0, XMM1);
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedMin, entry) {
+  typedef float (*PackedMinCode)();
+  float res = reinterpret_cast<PackedMinCode>(entry)();
+  EXPECT_FLOAT_EQ(2.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedMax, assembler) {
+  __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ maxps(XMM0, XMM1);
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedMax, entry) {
+  typedef float (*PackedMaxCode)();
+  float res = reinterpret_cast<PackedMaxCode>(entry)();
+  EXPECT_FLOAT_EQ(4.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalOr, assembler) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } constant1 =
+      { 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0 };
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } constant2 =
+      { 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F };
+  __ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant1)));
+  __ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant2)));
+  __ orps(XMM0, XMM1);
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalOr, entry) {
+  typedef uint32_t (*PackedLogicalOrCode)();
+  uint32_t res = reinterpret_cast<PackedLogicalOrCode>(entry)();
+  EXPECT_EQ(0xFFFFFFFF, res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalAnd, assembler) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } constant1 =
+      { 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0 };
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } constant2 =
+      { 0x0F0FFF0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F };
+  __ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant1)));
+  __ andps(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant2)));
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalAnd, entry) {
+  typedef uint32_t (*PackedLogicalAndCode)();
+  uint32_t res = reinterpret_cast<PackedLogicalAndCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0x0000F000), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalNot, assembler) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } constant1 =
+      { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  __ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant1)));
+  __ notps(XMM0);
+  // Copy the low lane at ESP.
+  __ pushl(EAX);
+  __ movss(Address(ESP, 0), XMM0);
+  __ flds(Address(ESP, 0));
+  __ popl(EAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalNot, entry) {
+  typedef uint32_t (*PackedLogicalNotCode)();
+  uint32_t res = reinterpret_cast<PackedLogicalNotCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
 ASSEMBLER_TEST_GENERATE(SingleFPOperationsStack, assembler) {
   __ movl(EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
   __ movd(XMM0, EAX);
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 1b270aa..8afb003 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -529,6 +529,24 @@
 }
 
 
+void Assembler::movups(XmmRegister dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x10);
+  EmitOperand(dst & 7, src);
+}
+
+
+void Assembler::movups(const Address& dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(src, dst);
+  EmitUint8(0x0F);
+  EmitUint8(0x11);
+  EmitOperand(src & 7, dst);
+}
+
+
 void Assembler::addsd(XmmRegister dst, XmmRegister src) {
   ASSERT(src <= XMM15);
   ASSERT(dst <= XMM15);
@@ -576,6 +594,245 @@
   EmitXmmRegisterOperand(dst & 7, src);
 }
 
+void Assembler::addps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x58);
+  EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::subps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x5C);
+  EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::divps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x5E);
+  EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::mulps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x59);
+  EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::minps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x5D);
+  EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::maxps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x5F);
+  EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::andps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x54);
+  EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::andps(XmmRegister dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x54);
+  EmitOperand(dst & 7, src);
+}
+
+
+void Assembler::orps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x56);
+  EmitXmmRegisterOperand(dst & 7, src);
+}
+
+void Assembler::notps(XmmRegister dst) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } float_not_constant =
+      { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  movq(TMP, Immediate(reinterpret_cast<intptr_t>(&float_not_constant)));
+  xorps(dst, Address(TMP, 0));
+}
+
+
+void Assembler::negateps(XmmRegister dst) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } float_negate_constant =
+      { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
+  movq(TMP, Immediate(reinterpret_cast<intptr_t>(&float_negate_constant)));
+  xorps(dst, Address(TMP, 0));
+}
+
+
+void Assembler::absps(XmmRegister dst) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } float_absolute_constant =
+      { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
+  movq(TMP, Immediate(reinterpret_cast<intptr_t>(&float_absolute_constant)));
+  andps(dst, Address(TMP, 0));
+}
+
+
+void Assembler::zerowps(XmmRegister dst) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } float_zerow_constant =
+      { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+  movq(TMP, Immediate(reinterpret_cast<intptr_t>(&float_zerow_constant)));
+  andps(dst, Address(TMP, 0));
+}
+
+
+void Assembler::cmppseq(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst & 7, src);
+  EmitUint8(0x0);
+}
+
+
+void Assembler::cmppsneq(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst & 7, src);
+  EmitUint8(0x4);
+}
+
+
+void Assembler::cmppslt(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst & 7, src);
+  EmitUint8(0x1);
+}
+
+
+void Assembler::cmppsle(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst & 7, src);
+  EmitUint8(0x2);
+}
+
+
+void Assembler::cmppsnlt(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst & 7, src);
+  EmitUint8(0x5);
+}
+
+
+void Assembler::cmppsnle(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xC2);
+  EmitXmmRegisterOperand(dst & 7, src);
+  EmitUint8(0x6);
+}
+
+
+void Assembler::sqrtps(XmmRegister dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, dst);
+  EmitUint8(0x0F);
+  EmitUint8(0x51);
+  EmitXmmRegisterOperand(dst & 7, dst);
+}
+
+
+void Assembler::rsqrtps(XmmRegister dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, dst);
+  EmitUint8(0x0F);
+  EmitUint8(0x52);
+  EmitXmmRegisterOperand(dst & 7, dst);
+}
+
+
+void Assembler::reciprocalps(XmmRegister dst) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, dst);
+  EmitUint8(0x0F);
+  EmitUint8(0x53);
+  EmitXmmRegisterOperand(dst & 7, dst);
+}
+
+
+void Assembler::set1ps(XmmRegister dst, Register tmp1, const Immediate& imm) {
+  // Load 32-bit immediate value into tmp1.
+  movl(tmp1, imm);
+  // Move value from tmp1 into dst.
+  movd(dst, tmp1);
+  // Broadcast low lane into other three lanes.
+  shufps(dst, dst, Immediate(0x0));
+}
+
+
+void Assembler::shufps(XmmRegister dst, XmmRegister src, const Immediate& imm) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0xC6);
+  EmitXmmRegisterOperand(dst & 7, src);
+  ASSERT(imm.is_uint8());
+  EmitUint8(imm.value());
+}
+
 
 void Assembler::comisd(XmmRegister a, XmmRegister b) {
   ASSERT(a <= XMM15);
@@ -600,6 +857,16 @@
 }
 
 
+void Assembler::movmskps(Register dst, XmmRegister src) {
+  ASSERT(src <= XMM15);
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x50);
+  EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
 void Assembler::sqrtsd(XmmRegister dst, XmmRegister src) {
   ASSERT(dst <= XMM15);
   ASSERT(src <= XMM15);
@@ -635,6 +902,23 @@
 }
 
 
+void Assembler::xorps(XmmRegister dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x57);
+  EmitOperand(dst & 7, src);
+}
+
+
+void Assembler::xorps(XmmRegister dst, XmmRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitREX_RB(dst, src);
+  EmitUint8(0x0F);
+  EmitUint8(0x57);
+  EmitXmmRegisterOperand(dst & 7, src);
+}
+
 void Assembler::andpd(XmmRegister dst, const Address& src) {
   ASSERT(dst <= XMM15);
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
@@ -1744,7 +2028,7 @@
 
 
 void Assembler::StoreIntoObject(Register object,
-                                const FieldAddress& dest,
+                                const Address& dest,
                                 Register value) {
   ASSERT(object != value);
   movq(dest, value);
@@ -1760,7 +2044,7 @@
 
 
 void Assembler::StoreIntoObjectNoBarrier(Register object,
-                                         const FieldAddress& dest,
+                                         const Address& dest,
                                          Register value) {
   movq(dest, value);
 #if defined(DEBUG)
@@ -1923,14 +2207,14 @@
   }
 
   // Preserve all XMM registers except XMM0
-  subq(RSP, Immediate((kNumberOfXmmRegisters - 1) * kDoubleSize));
+  subq(RSP, Immediate((kNumberOfXmmRegisters - 1) * kFpuRegisterSize));
   // Store XMM registers with the lowest register number at the lowest
   // address.
   intptr_t offset = 0;
   for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
     XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
-    movsd(Address(RSP, offset), xmm_reg);
-    offset += kDoubleSize;
+    movups(Address(RSP, offset), xmm_reg);
+    offset += kFpuRegisterSize;
   }
 
   ReserveAlignedFrameSpace(frame_space);
@@ -1943,7 +2227,7 @@
   // We need to restore it before restoring registers.
   const intptr_t kPushedRegistersSize =
       kNumberOfVolatileCpuRegisters * kWordSize +
-      kNumberOfVolatileXmmRegisters * kDoubleSize;
+      kNumberOfVolatileXmmRegisters * kFpuRegisterSize;
   leaq(RSP, Address(RBP, -kPushedRegistersSize));
 
   // Restore all XMM registers except XMM0
@@ -1951,8 +2235,8 @@
   intptr_t offset = 0;
   for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
     XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
-    movsd(xmm_reg, Address(RSP, offset));
-    offset += kDoubleSize;
+    movups(xmm_reg, Address(RSP, offset));
+    offset += kFpuRegisterSize;
   }
   addq(RSP, Immediate(offset));
 
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 8c18c6c..1bfabf2 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -383,11 +383,40 @@
 
   void movaps(XmmRegister dst, XmmRegister src);
 
+  void movups(const Address& dst, XmmRegister src);
+  void movups(XmmRegister dst, const Address& src);
+
   void addsd(XmmRegister dst, XmmRegister src);
   void subsd(XmmRegister dst, XmmRegister src);
   void mulsd(XmmRegister dst, XmmRegister src);
   void divsd(XmmRegister dst, XmmRegister src);
 
+  void addps(XmmRegister dst, XmmRegister src);
+  void subps(XmmRegister dst, XmmRegister src);
+  void divps(XmmRegister dst, XmmRegister src);
+  void mulps(XmmRegister dst, XmmRegister src);
+  void minps(XmmRegister dst, XmmRegister src);
+  void maxps(XmmRegister dst, XmmRegister src);
+  void andps(XmmRegister dst, XmmRegister src);
+  void andps(XmmRegister dst, const Address& src);
+  void orps(XmmRegister dst, XmmRegister src);
+  void notps(XmmRegister dst);
+  void negateps(XmmRegister dst);
+  void absps(XmmRegister dst);
+  void zerowps(XmmRegister dst);
+  void cmppseq(XmmRegister dst, XmmRegister src);
+  void cmppsneq(XmmRegister dst, XmmRegister src);
+  void cmppslt(XmmRegister dst, XmmRegister src);
+  void cmppsle(XmmRegister dst, XmmRegister src);
+  void cmppsnlt(XmmRegister dst, XmmRegister src);
+  void cmppsnle(XmmRegister dst, XmmRegister src);
+  void sqrtps(XmmRegister dst);
+  void rsqrtps(XmmRegister dst);
+  void reciprocalps(XmmRegister dst);
+
+  void set1ps(XmmRegister dst, Register tmp, const Immediate& imm);
+  void shufps(XmmRegister dst, XmmRegister src, const Immediate& mask);
+
   void comisd(XmmRegister a, XmmRegister b);
   void cvtsi2sd(XmmRegister a, Register b);
   void cvttsd2siq(Register dst, XmmRegister src);
@@ -507,12 +536,16 @@
   void ret();
 
   void movmskpd(Register dst, XmmRegister src);
+  void movmskps(Register dst, XmmRegister src);
 
   void sqrtsd(XmmRegister dst, XmmRegister src);
 
   void xorpd(XmmRegister dst, const Address& src);
   void xorpd(XmmRegister dst, XmmRegister src);
 
+  void xorps(XmmRegister dst, const Address& src);
+  void xorps(XmmRegister dst, XmmRegister src);
+
   void andpd(XmmRegister dst, const Address& src);
 
   void fldl(const Address& src);
@@ -594,15 +627,12 @@
 
   // Destroys value.
   void StoreIntoObject(Register object,  // Object we are storing into.
-                       const FieldAddress& dest,  // Where we are storing into.
+                       const Address& dest,  // Where we are storing into.
                        Register value);  // Value we are storing.
 
   void StoreIntoObjectNoBarrier(Register object,
-                                const FieldAddress& dest,
+                                const Address& dest,
                                 Register value);
-  void StoreIntoObjectNoBarrier(Register object,
-                                const FieldAddress& dest,
-                                const Object& value);
 
   void DoubleNegate(XmmRegister d);
   void FloatNegate(XmmRegister f);
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index e6e3940..8e3f62a 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -1388,6 +1388,330 @@
   EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
 }
 
+ASSEMBLER_TEST_GENERATE(PackedFPOperations, assembler) {
+  __ movq(RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+  __ movd(XMM10, RAX);
+  __ shufps(XMM10, XMM10, Immediate(0x0));
+  __ movq(RAX, Immediate(bit_cast<int32_t, float>(3.4f)));
+  __ movd(XMM9, RAX);
+  __ shufps(XMM9, XMM9, Immediate(0x0));
+  __ addps(XMM10, XMM9);  // 15.7f
+  __ mulps(XMM10, XMM9);  // 53.38f
+  __ subps(XMM10, XMM9);  // 49.98f
+  __ divps(XMM10, XMM9);  // 14.7f
+  __ movaps(XMM0, XMM10);
+  __ shufps(XMM0, XMM0, Immediate(0x55));  // Copy second lane into all 4 lanes.
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedFPOperations, entry) {
+  typedef float (*PackedFPOperationsCode)();
+  float res = reinterpret_cast<PackedFPOperationsCode>(entry)();
+  EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedFPOperations2, assembler) {
+  __ movq(RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ movd(XMM0, RAX);
+  __ shufps(XMM0, XMM0, Immediate(0x0));
+
+  __ movaps(XMM11, XMM0);  // Copy XMM0
+  __ reciprocalps(XMM11);  // 0.25
+  __ sqrtps(XMM11);  // 0.5
+  __ rsqrtps(XMM0);  // ~0.5
+  __ subps(XMM0, XMM11);  // ~0.0
+  __ shufps(XMM0, XMM0, Immediate(0x00));  // Copy second lane into all 4 lanes.
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedFPOperations2, entry) {
+  typedef float (*PackedFPOperations2Code)();
+  float res = reinterpret_cast<PackedFPOperations2Code>(entry)();
+  EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareEQ, assembler) {
+  __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppseq(XMM0, XMM1);
+  __ pushq(RAX);
+  __ movss(Address(RSP, 0), XMM0);
+  __ popq(RAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareEQ, entry) {
+  typedef uint32_t (*PackedCompareEQCode)();
+  uint32_t res = reinterpret_cast<PackedCompareEQCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNEQ, assembler) {
+  __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppsneq(XMM0, XMM1);
+  __ pushq(RAX);
+  __ movss(Address(RSP, 0), XMM0);
+  __ popq(RAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNEQ, entry) {
+  typedef uint32_t (*PackedCompareNEQCode)();
+  uint32_t res = reinterpret_cast<PackedCompareNEQCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareLT, assembler) {
+  __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppslt(XMM0, XMM1);
+  __ pushq(RAX);
+  __ movss(Address(RSP, 0), XMM0);
+  __ popq(RAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareLT, entry) {
+  typedef uint32_t (*PackedCompareLTCode)();
+  uint32_t res = reinterpret_cast<PackedCompareLTCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareLE, assembler) {
+  __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppsle(XMM0, XMM1);
+  __ pushq(RAX);
+  __ movss(Address(RSP, 0), XMM0);
+  __ popq(RAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareLE, entry) {
+  typedef uint32_t (*PackedCompareLECode)();
+  uint32_t res = reinterpret_cast<PackedCompareLECode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNLT, assembler) {
+  __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppsnlt(XMM0, XMM1);
+  __ pushq(RAX);
+  __ movss(Address(RSP, 0), XMM0);
+  __ popq(RAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNLT, entry) {
+  typedef uint32_t (*PackedCompareNLTCode)();
+  uint32_t res = reinterpret_cast<PackedCompareNLTCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNLE, assembler) {
+  __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ cmppsnle(XMM0, XMM1);
+  __ pushq(RAX);
+  __ movss(Address(RSP, 0), XMM0);
+  __ popq(RAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNLE, entry) {
+  typedef uint32_t (*PackedCompareNLECode)();
+  uint32_t res = reinterpret_cast<PackedCompareNLECode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) {
+  __ movl(RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+  __ movd(XMM0, RAX);
+  __ shufps(XMM0, XMM0, Immediate(0x0));
+  __ negateps(XMM0);
+  __ shufps(XMM0, XMM0, Immediate(0xAA));  // Copy third lane into all 4 lanes.
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedNegate, entry) {
+  typedef float (*PackedNegateCode)();
+  float res = reinterpret_cast<PackedNegateCode>(entry)();
+  EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) {
+  __ movl(RAX, Immediate(bit_cast<int32_t, float>(-15.3f)));
+  __ movd(XMM0, RAX);
+  __ shufps(XMM0, XMM0, Immediate(0x0));
+  __ absps(XMM0);
+  __ shufps(XMM0, XMM0, Immediate(0xAA));  // Copy third lane into all 4 lanes.
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedAbsolute, entry) {
+  typedef float (*PackedAbsoluteCode)();
+  float res = reinterpret_cast<PackedAbsoluteCode>(entry)();
+  EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) {
+  __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+  __ zerowps(XMM0);
+  __ shufps(XMM0, XMM0, Immediate(0xFF));  // Copy the W lane which is now 0.0.
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedSetWZero, entry) {
+  typedef float (*PackedSetWZeroCode)();
+  float res = reinterpret_cast<PackedSetWZeroCode>(entry)();
+  EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedMin, assembler) {
+  __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ minps(XMM0, XMM1);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedMin, entry) {
+  typedef float (*PackedMinCode)();
+  float res = reinterpret_cast<PackedMinCode>(entry)();
+  EXPECT_FLOAT_EQ(2.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedMax, assembler) {
+  __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+  __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+  __ maxps(XMM0, XMM1);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedMax, entry) {
+  typedef float (*PackedMaxCode)();
+  float res = reinterpret_cast<PackedMaxCode>(entry)();
+  EXPECT_FLOAT_EQ(4.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalOr, assembler) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } constant1 =
+      { 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0 };
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } constant2 =
+      { 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F };
+  __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
+  __ movups(XMM0, Address(RAX, 0));
+  __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant2)));
+  __ movups(XMM1, Address(RAX, 0));
+  __ orps(XMM0, XMM1);
+  __ pushq(RAX);
+  __ movss(Address(RSP, 0), XMM0);
+  __ popq(RAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalOr, entry) {
+  typedef uint32_t (*PackedLogicalOrCode)();
+  uint32_t res = reinterpret_cast<PackedLogicalOrCode>(entry)();
+  EXPECT_EQ(0xFFFFFFFF, res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalAnd, assembler) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } constant1 =
+      { 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0 };
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } constant2 =
+      { 0x0F0FFF0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F };
+  __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
+  __ movups(XMM0, Address(RAX, 0));
+  __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant2)));
+  __ andps(XMM0, Address(RAX, 0));
+  __ pushq(RAX);
+  __ movss(Address(RSP, 0), XMM0);
+  __ popq(RAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalAnd, entry) {
+  typedef uint32_t (*PackedLogicalAndCode)();
+  uint32_t res = reinterpret_cast<PackedLogicalAndCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0x0000F000), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalNot, assembler) {
+  static const struct ALIGN16 {
+    uint32_t a;
+    uint32_t b;
+    uint32_t c;
+    uint32_t d;
+  } constant1 =
+      { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
+  __ movups(XMM9, Address(RAX, 0));
+  __ notps(XMM9);
+  __ movaps(XMM0, XMM9);
+  __ pushq(RAX);
+  __ movss(Address(RSP, 0), XMM0);
+  __ popq(RAX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalNot, entry) {
+  typedef uint32_t (*PackedLogicalNotCode)();
+  uint32_t res = reinterpret_cast<PackedLogicalNotCode>(entry)();
+  EXPECT_EQ(static_cast<uword>(0x0), res);
+}
 
 ASSEMBLER_TEST_GENERATE(DoubleFPMoves, assembler) {
   __ movq(RAX, Immediate(bit_cast<int64_t, double>(1024.67)));
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 721de07..07e2314 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -265,17 +265,22 @@
 
 class ArrayNode : public AstNode {
  public:
-  ArrayNode(intptr_t token_pos, const AbstractType& type)
+  ArrayNode(intptr_t token_pos,
+            const AbstractType& type,
+            const LocalVariable& temp)
       : AstNode(token_pos),
         type_(type),
+        temp_local_(temp),
         elements_() {
     CheckFields();
   }
   ArrayNode(intptr_t token_pos,
             const AbstractType& type,
+            const LocalVariable& temp,
             const GrowableArray<AstNode*>& elements)
       : AstNode(token_pos),
         type_(type),
+        temp_local_(temp),
         elements_(elements.length()) {
     CheckFields();
     for (intptr_t i = 0; i < elements.length(); i++) {
@@ -295,10 +300,13 @@
 
   const AbstractType& type() const { return type_; }
 
+  const LocalVariable& temp_local() const { return temp_local_; }
+
   DECLARE_COMMON_NODE_FUNCTIONS(ArrayNode);
 
  private:
   const AbstractType& type_;
+  const LocalVariable& temp_local_;  // Store allocated array while filling it.
   GrowableArray<AstNode*> elements_;
 
   void CheckFields() {
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index d6e85f3..b2253ee 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1098,6 +1098,83 @@
 }
 
 
+void ClassFinalizer::ApplyMixin(const Class& cls) {
+  const Type& mixin_type = Type::Handle(cls.mixin());
+  ASSERT(!mixin_type.IsNull());
+  ASSERT(mixin_type.HasResolvedTypeClass());
+  const Class& mixin_cls = Class::Handle(mixin_type.type_class());
+
+  if (FLAG_trace_class_finalization) {
+    OS::Print("Applying mixin '%s' to '%s'\n",
+              String::Handle(mixin_cls.Name()).ToCString(),
+              cls.ToCString());
+  }
+
+  // Check that the super class of the mixin class is extending
+  // class Object.
+  const Type& mixin_super_type = Type::Handle(mixin_cls.super_type());
+  if (!mixin_super_type.IsObjectType()) {
+    const Script& script = Script::Handle(cls.script());
+    const String& class_name = String::Handle(mixin_cls.Name());
+    ReportError(script, cls.token_pos(),
+                "mixin class %s must extend class Object",
+                class_name.ToCString());
+  }
+
+  const GrowableObjectArray& cloned_funcs =
+      GrowableObjectArray::Handle(GrowableObjectArray::New());
+  Array& functions = Array::Handle();
+  Function& func = Function::Handle();
+  // The parser creates the mixin application class and adds just
+  // one function, the implicit constructor.
+  functions = cls.functions();
+  ASSERT(functions.Length() == 1);
+  func ^= functions.At(0);
+  ASSERT(func.IsImplicitConstructor());
+  cloned_funcs.Add(func);
+  // Now clone the functions from the mixin class.
+  functions = mixin_cls.functions();
+  const intptr_t num_functions = functions.Length();
+  for (int i = 0; i < num_functions; i++) {
+    func ^= functions.At(i);
+    if (func.IsConstructor()) {
+      // A mixin class must not have explicit constructors.
+      if (!func.IsImplicitConstructor()) {
+        const Script& script = Script::Handle(cls.script());
+        ReportError(script, cls.token_pos(),
+                    "mixin class %s must not have constructors\n",
+                    String::Handle(mixin_cls.Name()).ToCString());
+      }
+      continue;  // Skip the implicit constructor.
+    }
+    if (!func.is_static()) {
+      func = func.Clone(cls);
+      cloned_funcs.Add(func);
+    }
+  }
+  functions = Array::MakeArray(cloned_funcs);
+  cls.SetFunctions(functions);
+
+  // Now clone the fields from the mixin class. There should be no
+  // existing fields in the mixin application class.
+  ASSERT(Array::Handle(cls.fields()).Length() == 0);
+  Array& fields = Array::Handle(mixin_cls.fields());
+  Field& field = Field::Handle();
+  const GrowableObjectArray& cloned_fields =
+      GrowableObjectArray::Handle(GrowableObjectArray::New());
+  const intptr_t num_fields = fields.Length();
+  for (int i = 0; i < num_fields; i++) {
+    field ^= fields.At(i);
+    if (!field.is_static()) {
+      field = field.Clone(cls);
+      cloned_fields.Add(field);
+    }
+  }
+  fields = Array::MakeArray(cloned_fields);
+  cls.SetFields(fields);
+}
+
+
 void ClassFinalizer::FinalizeClass(const Class& cls) {
   if (cls.is_finalized()) {
     return;
@@ -1150,6 +1227,12 @@
     FinalizeType(cls, sig_type, kCanonicalizeWellFormed);
     return;
   }
+  if (cls.mixin() != Type::null()) {
+    // Copy instance methods and fields from the mixin class.
+    // This has to happen before the check whether the methods of
+    // the class conflict with inherited methods.
+    ApplyMixin(cls);
+  }
   // Finalize interface types (but not necessarily interface classes).
   Array& interface_types = Array::Handle(cls.interfaces());
   AbstractType& interface_type = AbstractType::Handle();
@@ -1267,16 +1350,23 @@
     }
   }
 
-  // If the class/interface has no explicit super class/interfaces, we are done.
+  // If the class/interface has no explicit super class/interfaces
+  // and is not a mixin application, we are done.
   Type& super_type = Type::Handle(cls.super_type());
+  Type& mixin_type = Type::Handle(cls.mixin());
   Array& super_interfaces = Array::Handle(cls.interfaces());
   if ((super_type.IsNull() || super_type.IsObjectType()) &&
-      (super_interfaces.Length() == 0)) {
+      (super_interfaces.Length() == 0) &&
+      (mixin_type.IsNull())) {
     return;
   }
 
-  // If cls belongs to core lib or to core lib's implementation, restrictions
-  // about allowed interfaces are lifted.
+  if (!mixin_type.IsNull()) {
+    ResolveType(cls, mixin_type, kCanonicalizeWellFormed);
+  }
+
+  // If cls belongs to core lib, restrictions about allowed interfaces
+  // are lifted.
   const bool cls_belongs_to_core_lib = cls.library() == Library::CoreLibrary();
 
   // Resolve and check the super type and interfaces of cls.
@@ -1287,7 +1377,6 @@
   // Resolve super type. Failures lead to a longjmp.
   ResolveType(cls, super_type, kCanonicalizeWellFormed);
 
-  // If cls belongs to core lib or to core lib's implementation, restrictions
   interface_class = super_type.type_class();
   // If cls belongs to core lib or to core lib's implementation, restrictions
   // about allowed interfaces are lifted.
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index c272379..237c40d 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -99,6 +99,7 @@
       const Class& cls,
       const Function& factory,
       const GrowableObjectArray& visited_factories);
+  static void ApplyMixin(const Class& cls);
   static void ResolveSuperTypeAndInterfaces(const Class& cls,
                                             GrowableArray<intptr_t>* visited);
   static void FinalizeTypeParameters(const Class& cls);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index babed80..2efb71d 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -21,6 +21,7 @@
 #include "vm/flow_graph_compiler.h"
 #include "vm/flow_graph_inliner.h"
 #include "vm/flow_graph_optimizer.h"
+#include "vm/flow_graph_type_propagator.h"
 #include "vm/il_printer.h"
 #include "vm/longjump.h"
 #include "vm/object.h"
@@ -53,7 +54,7 @@
 DECLARE_FLAG(bool, print_flow_graph);
 DECLARE_FLAG(bool, print_flow_graph_optimized);
 DECLARE_FLAG(bool, trace_failed_optimization_attempts);
-
+DECLARE_FLAG(bool, trace_type_propagation);
 
 // Compile a function. Should call only if the function has not been compiled.
 //   Arg0: function object.
@@ -190,15 +191,25 @@
         // Use lists are maintained and validated by the inliner.
       }
 
+      if (FLAG_trace_type_propagation) {
+        OS::Print("Before type propagation:\n");
+        FlowGraphPrinter printer(*flow_graph);
+        printer.PrintBlocks();
+      }
+
       // Propagate types and eliminate more type tests.
       if (FLAG_propagate_types) {
         FlowGraphTypePropagator propagator(flow_graph);
-        propagator.PropagateTypes();
+        propagator.Propagate();
       }
 
-      // Propagate sminess from CheckSmi to phis.
+      if (FLAG_trace_type_propagation) {
+        OS::Print("After type propagation:\n");
+        FlowGraphPrinter printer(*flow_graph);
+        printer.PrintBlocks();
+      }
+
       flow_graph->ComputeUseLists();
-      optimizer.PropagateSminess();
 
       // Use propagated class-ids to optimize further.
       optimizer.ApplyClassIds();
@@ -465,10 +476,11 @@
     ParsedFunction* parsed_function = new ParsedFunction(
         Function::ZoneHandle(function.raw()));
     if (FLAG_trace_compiler) {
-      OS::Print("Compiling %sfunction: '%s' @ token %"Pd"\n",
+      OS::Print("Compiling %sfunction: '%s' @ token %"Pd", size %"Pd"\n",
                 (optimized ? "optimized " : ""),
                 function.ToFullyQualifiedCString(),
-                function.token_pos());
+                function.token_pos(),
+                (function.end_token_pos() - function.token_pos()));
     }
     {
       HANDLESCOPE(isolate);
@@ -495,9 +507,10 @@
     per_compile_timer.Stop();
 
     if (FLAG_trace_compiler) {
-      OS::Print("--> '%s' entry: %#"Px" time: %"Pd64" us\n",
+      OS::Print("--> '%s' entry: %#"Px" size: %"Pd" time: %"Pd64" us\n",
                 function.ToFullyQualifiedCString(),
                 Code::Handle(function.CurrentCode()).EntryPoint(),
+                Code::Handle(function.CurrentCode()).Size(),
                 per_compile_timer.TotalElapsedTime());
     }
 
@@ -625,6 +638,9 @@
     parsed_function->set_expression_temp_var(
         ParsedFunction::CreateExpressionTempVar(0));
     fragment->scope()->AddVariable(parsed_function->expression_temp_var());
+    parsed_function->set_array_literal_var(
+        ParsedFunction::CreateArrayLiteralVar(0));
+    fragment->scope()->AddVariable(parsed_function->array_literal_var());
     parsed_function->AllocateVariables();
 
     // Non-optimized code generator.
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index cc08f94..5610b5f 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -237,8 +237,22 @@
     case 0xAD: return "shrd";
     case 0xAB: return "bts";
     case 0xB1: return "cmpxchg";
+    case 0x50: return "movmskps";
+    case 0x51: return "sqrtps";
+    case 0x52: return "rqstps";
+    case 0x53: return "rcpps";
+    case 0x54: return "andps";
+    case 0x56: return "orps";
     case 0x57: return "xorps";
+    case 0x58: return "addps";
+    case 0x59: return "mulps";
+    case 0x5C: return "subps";
+    case 0x5D: return "minps";
+    case 0x5E: return "divps";
+    case 0x5F: return "maxps";
     case 0x28: return "movaps";
+    case 0x10: return "movups";
+    case 0x11: return "movups";
     default: return NULL;
   }
 }
@@ -286,6 +300,7 @@
   void PrintCPURegister(int reg);
   void PrintCPUByteRegister(int reg);
   void PrintXmmRegister(int reg);
+  void PrintXmmComparison(int comparison);
   void PrintAddress(uword addr);
 
   typedef void (X86Decoder::*RegisterNamePrinter)(int reg);
@@ -395,6 +410,15 @@
   Print(xmm_regs[reg]);
 }
 
+void X86Decoder::PrintXmmComparison(int comparison) {
+  ASSERT(0 <= comparison);
+  ASSERT(comparison < 8);
+  static const char* comparisons[8] = {
+    "eq", "lt", "le", "unordered", "not eq", "not lt", "not le", "ordered"
+  };
+  Print(comparisons[comparison]);
+}
+
 
 static const char* ObjectToCStringNoGC(const Object& obj) {
   if (obj.IsSmi() ||
@@ -1337,6 +1361,54 @@
             PrintXmmRegister(regop);
             Print(",");
             data += PrintRightXmmOperand(data);
+          } else if (f0byte == 0x11) {
+            Print("movups ");
+            int mod, regop, rm;
+            GetModRm(*data, &mod, &regop, &rm);
+            data += PrintRightXmmOperand(data);
+            Print(",");
+            PrintXmmRegister(regop);
+          } else if (f0byte == 0x10) {
+            int mod, regop, rm;
+            GetModRm(*data, &mod, &regop, &rm);
+            Print("movups ");
+            PrintXmmRegister(regop);
+            Print(",");
+            data += PrintRightOperand(data);
+          } else if (f0byte == 0x51 || f0byte == 0x52 || f0byte == 0x53 ||
+                     f0byte == 0x54 || f0byte == 0x56 || f0byte == 0x58 ||
+                     f0byte == 0x59 || f0byte == 0x5C || f0byte == 0x5D ||
+                     f0byte == 0x5E || f0byte == 0x5F) {
+            int mod, regop, rm;
+            GetModRm(*data, &mod, &regop, &rm);
+            Print(f0mnem);
+            Print(" ");
+            PrintXmmRegister(regop);
+            Print(",");
+            data += PrintRightXmmOperand(data);
+          } else if (f0byte == 0x50) {
+            Print("movmskpd ");
+            int mod, regop, rm;
+            GetModRm(*data, &mod, &regop, &rm);
+            PrintCPURegister(regop);
+            Print(",");
+            data += PrintRightXmmOperand(data);
+          } else if (f0byte == 0xC2 || f0byte == 0xC6) {
+            if (f0byte == 0xC2)
+              Print("cmpps ");
+            else
+              Print("shufps ");
+            int mod, regop, rm;
+            GetModRm(*data, &mod, &regop, &rm);
+            Print(" ");
+            PrintXmmRegister(regop);
+            Print(",");
+            data += PrintRightXmmOperand(data);
+            int comparison = *data;
+            Print(" [");
+            PrintHex(comparison);
+            Print("]");
+            data++;
           } else {
             UNIMPLEMENTED();
           }
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 4d15072..958c2b7 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -1394,7 +1394,6 @@
     get_modrm(*current, &mod, &regop, &rm);
     AppendToBuffer("movaps %s, ", NameOfXMMRegister(regop));
     current += PrintRightXMMOperand(current);
-
   } else if (opcode == 0x29) {
     // movaps xmm/m128, xmm
     int mod, regop, rm;
@@ -1402,7 +1401,19 @@
     AppendToBuffer("movaps ");
     current += PrintRightXMMOperand(current);
     AppendToBuffer(", %s", NameOfXMMRegister(regop));
-
+  } else if (opcode == 0x11) {
+    // movups xmm/m128, xmm
+    int mod, regop, rm;
+    get_modrm(*current, &mod, &regop, &rm);
+    AppendToBuffer("movups ");
+    current += PrintRightXMMOperand(current);
+    AppendToBuffer(", %s", NameOfXMMRegister(regop));
+  } else if (opcode == 0x10) {
+    // movups xmm, xmm/m128
+    int mod, regop, rm;
+    get_modrm(*current, &mod, &regop, &rm);
+    AppendToBuffer("movups %s, ", NameOfXMMRegister(regop));
+    current += PrintRightXMMOperand(current);
   } else if (opcode == 0xA2 || opcode == 0x31) {
     // RDTSC or CPUID
     AppendToBuffer("%s", mnemonic);
@@ -1414,13 +1425,42 @@
     byte_size_operand_ = idesc.byte_size_operation;
     current += PrintOperands(idesc.mnem, idesc.op_order_, current);
 
-  } else if (opcode == 0x57) {
-    // xorps xmm, xmm/m128
+  } else if (opcode == 0x51 || opcode == 0x52 || opcode == 0x53 ||
+             opcode == 0x54 || opcode == 0x56 || opcode == 0x57 ||
+             opcode == 0x58 || opcode == 0x59 || opcode == 0x5C ||
+             opcode == 0x5D || opcode == 0x5E || opcode == 0x5F) {
+    const char* mnemonic = NULL;
+    switch (opcode) {
+      case 0x51: mnemonic = "sqrtps"; break;
+      case 0x52: mnemonic = "rsqrtps"; break;
+      case 0x53: mnemonic = "rcpps"; break;
+      case 0x54: mnemonic = "andps"; break;
+      case 0x56: mnemonic = "orps"; break;
+      case 0x57: mnemonic = "xorps"; break;
+      case 0x58: mnemonic = "addps"; break;
+      case 0x59: mnemonic = "mulps"; break;
+      case 0x5C: mnemonic = "subps"; break;
+      case 0x5D: mnemonic = "minps"; break;
+      case 0x5E: mnemonic = "divps"; break;
+      case 0x5F: mnemonic = "maxps"; break;
+      default: UNREACHABLE();
+    }
     int mod, regop, rm;
     get_modrm(*current, &mod, &regop, &rm);
-    AppendToBuffer("xorps %s, ", NameOfXMMRegister(regop));
+    AppendToBuffer("%s %s, ", mnemonic, NameOfXMMRegister(regop));
     current += PrintRightXMMOperand(current);
-
+  } else if (opcode == 0xC2 || opcode == 0xC6) {
+    int mod, regop, rm;
+    get_modrm(*current, &mod, &regop, &rm);
+    if (opcode == 0xC2) {
+      AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop));
+    } else {
+      ASSERT(opcode == 0xC6);
+      AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
+    }
+    current += PrintRightXMMOperand(current);
+    AppendToBuffer(" [%x]", *current);
+    current++;
   } else if ((opcode & 0xF0) == 0x80) {
     // Jcc: Conditional jump (branch).
     current = data + JumpConditional(data);
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 236c4d9..909d937 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -762,12 +762,7 @@
     return false;
   }
 
-  // Propagated types are not set yet.
-  // More checks will possibly be eliminated during type propagation.
-  bool is_null, is_instance;
-  const bool eliminated =
-      (value->CanComputeIsNull(&is_null) && is_null) ||
-      (value->CanComputeIsInstanceOf(dst_type, &is_instance) && is_instance);
+  const bool eliminated = value->Type()->IsAssignableTo(dst_type);
   if (FLAG_trace_type_check_elimination) {
     FlowGraphPrinter::PrintTypeCheck(owner()->parsed_function(),
                                      token_pos,
@@ -1661,24 +1656,37 @@
 
 
 void EffectGraphVisitor::VisitArrayNode(ArrayNode* node) {
-  // Translate the array elements and collect their values.
-  ZoneGrowableArray<PushArgumentInstr*>* arguments =
-      new ZoneGrowableArray<PushArgumentInstr*>(node->length());
-  for (int i = 0; i < node->length(); ++i) {
-    ValueGraphVisitor for_value(owner(), temp_index());
-    node->ElementAt(i)->Visit(&for_value);
-    Append(for_value);
-    arguments->Add(PushArgument(for_value.value()));
-  }
   const AbstractTypeArguments& type_args =
       AbstractTypeArguments::ZoneHandle(node->type().arguments());
   Value* element_type = BuildInstantiatedTypeArguments(node->token_pos(),
                                                        type_args);
   CreateArrayInstr* create = new CreateArrayInstr(node->token_pos(),
-                                                  arguments,
+                                                  node->length(),
                                                   node->type(),
                                                   element_type);
-  ReturnDefinition(create);
+  Value* array_val = Bind(create);
+  Definition* store = BuildStoreTemp(node->temp_local(), array_val);
+  Do(store);
+
+  const intptr_t class_id = create->Type()->ToCid();
+  const intptr_t deopt_id = Isolate::kNoDeoptId;
+  for (int i = 0; i < node->length(); ++i) {
+    Value* array = Bind(
+        new LoadLocalInstr(node->temp_local(), owner()->context_level()));
+    Value* index = Bind(new ConstantInstr(Smi::ZoneHandle(Smi::New(i))));
+    ValueGraphVisitor for_value(owner(), temp_index());
+    node->ElementAt(i)->Visit(&for_value);
+    Append(for_value);
+    // No store barrier needed for constants.
+    const bool emit_store_barrier = !for_value.value()->BindsToConstant();
+    StoreIndexedInstr* store = new StoreIndexedInstr(
+        array, index, for_value.value(),
+        emit_store_barrier, class_id, deopt_id);
+    Do(store);
+  }
+
+  ReturnDefinition(
+      new LoadLocalInstr(node->temp_local(), owner()->context_level()));
 }
 
 
@@ -3046,8 +3054,10 @@
   arguments->Add(new LiteralNode(args_pos, args_descriptor));
   // The third argument is an array containing the original method arguments,
   // including the receiver.
-  ArrayNode* args_array =
-      new ArrayNode(args_pos, Type::ZoneHandle(Type::ArrayType()));
+  ArrayNode* args_array = new ArrayNode(
+      args_pos,
+      Type::ZoneHandle(Type::ArrayType()),
+      *owner()->parsed_function().array_literal_var());
   for (intptr_t i = 0; i < method_arguments->length(); i++) {
     args_array->AddElement(method_arguments->NodeAt(i));
   }
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 880b3eb..8319dd5 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -939,6 +939,10 @@
       return OneByteString::data_offset();
     case kTwoByteStringCid:
       return TwoByteString::data_offset();
+    case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
+      // Elements start at offset 0 of the external data.
+      return 0;
     default:
       UNIMPLEMENTED();
       return Array::data_offset();
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index f7d3f34..d0ff1f7 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -210,11 +210,6 @@
   // Bail out of the flow graph compiler. Does not return to the caller.
   void Bailout(const char* reason);
 
-  void LoadDoubleOrSmiToFpu(FpuRegister result,
-                            Register reg,
-                            Register temp,
-                            Label* not_double_or_smi);
-
   // Returns 'true' if code generation for this function is complete, i.e.,
   // no fall-through to regular code is needed.
   bool TryIntrinsify();
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index efb9b7b..72e7d35 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -24,6 +24,7 @@
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, print_ast);
 DECLARE_FLAG(bool, print_scopes);
+DECLARE_FLAG(bool, eliminate_type_checks);
 
 
 FlowGraphCompiler::~FlowGraphCompiler() {
@@ -561,6 +562,16 @@
   __ cmpl(EAX, raw_null);
   __ j(EQUAL, &is_assignable);
 
+  if (!FLAG_eliminate_type_checks) {
+    // If type checks are not eliminated during the graph building then
+    // a transition sentinel can be seen here.
+    const Immediate& raw_transition_sentinel =
+        Immediate(reinterpret_cast<intptr_t>(
+            Object::transition_sentinel().raw()));
+    __ cmpl(EAX, raw_transition_sentinel);
+    __ j(EQUAL, &is_assignable);
+  }
+
   // Generate throw new TypeError() if the type is malformed.
   if (dst_type.IsMalformed()) {
     const Error& error = Error::Handle(dst_type.malformed_error());
@@ -1318,25 +1329,6 @@
 }
 
 
-void FlowGraphCompiler::LoadDoubleOrSmiToFpu(FpuRegister result,
-                                             Register reg,
-                                             Register temp,
-                                             Label* not_double_or_smi) {
-  Label is_smi, done;
-  __ testl(reg, Immediate(kSmiTagMask));
-  __ j(ZERO, &is_smi);
-  __ CompareClassId(reg, kDoubleCid, temp);
-  __ j(NOT_EQUAL, not_double_or_smi);
-  __ movsd(result, FieldAddress(reg, Double::value_offset()));
-  __ jmp(&done);
-  __ Bind(&is_smi);
-  __ movl(temp, reg);
-  __ SmiUntag(temp);
-  __ cvtsi2sd(result, temp);
-  __ Bind(&done);
-}
-
-
 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
   // TODO(vegorov): consider saving only caller save (volatile) registers.
   const intptr_t xmm_regs_count = locs->live_registers()->fpu_regs_count();
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 76e976e..f92c613 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -23,7 +23,7 @@
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, print_ast);
 DECLARE_FLAG(bool, print_scopes);
-DECLARE_FLAG(bool, use_sse41);
+DECLARE_FLAG(bool, eliminate_type_checks);
 
 
 FlowGraphCompiler::~FlowGraphCompiler() {
@@ -561,6 +561,13 @@
   __ cmpq(RAX, raw_null);
   __ j(EQUAL, &is_assignable);
 
+  if (!FLAG_eliminate_type_checks) {
+    // If type checks are not eliminated during the graph building then
+    // a transition sentinel can be seen here.
+    __ CompareObject(RAX, Object::transition_sentinel());
+    __ j(EQUAL, &is_assignable);
+  }
+
   // Generate throw new TypeError() if the type is malformed.
   if (dst_type.IsMalformed()) {
     const Error& error = Error::Handle(dst_type.malformed_error());
@@ -1322,25 +1329,6 @@
 }
 
 
-void FlowGraphCompiler::LoadDoubleOrSmiToFpu(FpuRegister result,
-                                             Register reg,
-                                             Register temp,
-                                             Label* not_double_or_smi) {
-  Label is_smi, done;
-  __ testq(reg, Immediate(kSmiTagMask));
-  __ j(ZERO, &is_smi);
-  __ CompareClassId(reg, kDoubleCid);
-  __ j(NOT_EQUAL, not_double_or_smi);
-  __ movsd(result, FieldAddress(reg, Double::value_offset()));
-  __ jmp(&done);
-  __ Bind(&is_smi);
-  __ movq(temp, reg);
-  __ SmiUntag(temp);
-  __ cvtsi2sd(result, temp);
-  __ Bind(&done);
-}
-
-
 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
   // TODO(vegorov): consider saving only caller save (volatile) registers.
   const intptr_t xmm_regs_count = locs->live_registers()->fpu_regs_count();
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index b1a10b8..c72acf8 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -84,7 +84,7 @@
   GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested());
   ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount());
   for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) {
-    intptr_t cid = call->ArgumentAt(i)->value()->ResultCid();
+    intptr_t cid = call->ArgumentAt(i)->value()->Type()->ToCid();
     class_ids.Add(cid);
   }
   // TODO(srdjan): Test for other class_ids > 1.
@@ -150,7 +150,7 @@
     return;  // Already specialized.
   }
 
-  const intptr_t receiver_cid  = call->ArgumentAt(0)->value()->ResultCid();
+  const intptr_t receiver_cid  = call->ArgumentAt(0)->value()->Type()->ToCid();
   if (receiver_cid == kDynamicCid) {
     return;  // No information about receiver was infered.
   }
@@ -231,7 +231,7 @@
   Definition* converted = NULL;
   if ((from == kTagged) && (to == kUnboxedMint)) {
     ASSERT((deopt_target != NULL) ||
-           (use->definition()->GetPropagatedCid() == kDoubleCid));
+           (use->Type()->ToCid() == kDoubleCid));
     const intptr_t deopt_id = (deopt_target != NULL) ?
         deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
     converted = new UnboxIntegerInstr(new Value(use->definition()), deopt_id);
@@ -251,7 +251,7 @@
     const intptr_t deopt_id = (deopt_target != NULL) ?
         deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
     ASSERT((deopt_target != NULL) ||
-           (use->definition()->GetPropagatedCid() == kDoubleCid));
+           (use->Type()->ToCid() == kDoubleCid));
     ConstantInstr* constant = use->definition()->AsConstant();
     if ((constant != NULL) && constant->value().IsSmi()) {
       const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue();
@@ -313,7 +313,7 @@
       for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) {
         PhiInstr* phi = (*join_entry->phis())[i];
         if (phi == NULL) continue;
-        if (phi->GetPropagatedCid() == kDoubleCid) {
+        if (phi->Type()->ToCid() == kDoubleCid) {
           phi->set_representation(kUnboxedDouble);
         }
       }
@@ -603,6 +603,8 @@
     case kInt8ArrayCid:
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
+    case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
       // Check that value is always smi.
@@ -679,6 +681,8 @@
       case kInt8ArrayCid:
       case kUint8ArrayCid:
       case kUint8ClampedArrayCid:
+      case kExternalUint8ArrayCid:
+      case kExternalUint8ClampedArrayCid:
       case kInt16ArrayCid:
       case kUint16ArrayCid:
       case kInt32ArrayCid:
@@ -1171,13 +1175,17 @@
 
 
 static LoadFieldInstr* BuildLoadStringLength(Value* str) {
-  const bool is_immutable = true;  // String length is immutable.
+  // Treat length loads as mutable (i.e. affected by side effects) to avoid
+  // hoisting them since we can't hoist the preceding class-check. This
+  // is because of externalization of strings that affects their class-id.
+  const bool is_immutable = false;
   LoadFieldInstr* load = new LoadFieldInstr(
       str,
       String::length_offset(),
       Type::ZoneHandle(Type::SmiType()),
       is_immutable);
   load->set_result_cid(kSmiCid);
+  load->set_recognized_kind(MethodRecognizer::kStringBaseLength);
   return load;
 }
 
@@ -1187,7 +1195,6 @@
   AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
 
   LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)->value());
-  load->set_recognized_kind(MethodRecognizer::kStringBaseLength);
   call->ReplaceWith(load, current_iterator());
   RemovePushArguments(call);
 }
@@ -1321,14 +1328,7 @@
   }
   if (!skip_check) {
     // Insert bounds check.
-    const bool is_immutable = true;
-    LoadFieldInstr* length = new LoadFieldInstr(
-        str->Copy(),
-        CheckArrayBoundInstr::LengthOffsetFor(cid),
-        Type::ZoneHandle(Type::SmiType()),
-        is_immutable);
-    length->set_result_cid(kSmiCid);
-    length->set_recognized_kind(MethodRecognizer::kStringBaseLength);
+    LoadFieldInstr* length = BuildLoadStringLength(str->Copy());
     InsertBefore(call, length, NULL, Definition::kValue);
     InsertBefore(call,
                  new CheckArrayBoundInstr(new Value(length),
@@ -1367,6 +1367,8 @@
     case kInt8ArrayCid:
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
+    case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
     case kInt32ArrayCid:
@@ -1965,192 +1967,13 @@
 
   // If one of the input is not a boxable number (Mint, Double, Bigint), no
   // need for number checks.
-  if (!MayBeBoxableNumber(instr->left()->ResultCid()) ||
-      !MayBeBoxableNumber(instr->right()->ResultCid()))  {
+  if (!MayBeBoxableNumber(instr->left()->Type()->ToCid()) ||
+      !MayBeBoxableNumber(instr->right()->Type()->ToCid()))  {
     instr->set_needs_number_check(false);
   }
 }
 
 
-// SminessPropagator ensures that CheckSmis are eliminated across phis.
-class SminessPropagator : public ValueObject {
- public:
-  explicit SminessPropagator(FlowGraph* flow_graph)
-      : flow_graph_(flow_graph),
-        known_smis_(new BitVector(flow_graph_->current_ssa_temp_index())),
-        rollback_checks_(10),
-        in_worklist_(NULL),
-        worklist_(0) { }
-
-  void Propagate();
-
- private:
-  void PropagateSminessRecursive(BlockEntryInstr* block);
-  void AddToWorklist(PhiInstr* phi);
-  PhiInstr* RemoveLastFromWorklist();
-  void ProcessPhis();
-
-  FlowGraph* flow_graph_;
-
-  BitVector* known_smis_;
-  GrowableArray<intptr_t> rollback_checks_;
-
-  BitVector* in_worklist_;
-  GrowableArray<PhiInstr*> worklist_;
-
-  DISALLOW_COPY_AND_ASSIGN(SminessPropagator);
-};
-
-
-void SminessPropagator::AddToWorklist(PhiInstr* phi) {
-  if (in_worklist_ == NULL) {
-    in_worklist_ = new BitVector(flow_graph_->current_ssa_temp_index());
-  }
-  if (!in_worklist_->Contains(phi->ssa_temp_index())) {
-    in_worklist_->Add(phi->ssa_temp_index());
-    worklist_.Add(phi);
-  }
-}
-
-
-PhiInstr* SminessPropagator::RemoveLastFromWorklist() {
-  PhiInstr* phi = worklist_.RemoveLast();
-  ASSERT(in_worklist_->Contains(phi->ssa_temp_index()));
-  in_worklist_->Remove(phi->ssa_temp_index());
-  return phi;
-}
-
-
-static bool IsDefinitelySmiPhi(PhiInstr* phi) {
-  for (intptr_t i = 0; i < phi->InputCount(); i++) {
-    const intptr_t cid = phi->InputAt(i)->ResultCid();
-    if (cid != kSmiCid) {
-      return false;
-    }
-  }
-  return true;
-}
-
-
-static bool IsPossiblySmiPhi(PhiInstr* phi) {
-  for (intptr_t i = 0; i < phi->InputCount(); i++) {
-    const intptr_t cid = phi->InputAt(i)->ResultCid();
-    if ((cid != kSmiCid) && (cid != kDynamicCid)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-
-void SminessPropagator::ProcessPhis() {
-  // First optimistically mark all possible smi-phis: phi is possibly a smi if
-  // its operands are either smis or phis in the worklist.
-  for (intptr_t i = 0; i < worklist_.length(); i++) {
-    PhiInstr* phi = worklist_[i];
-    ASSERT(phi->GetPropagatedCid() == kDynamicCid);
-    phi->SetPropagatedCid(kSmiCid);
-
-    // Append all phis that use this phi and can potentially be smi to the
-    // end of worklist.
-    for (Value* use = phi->input_use_list();
-         use != NULL;
-         use = use->next_use()) {
-      PhiInstr* phi_use = use->instruction()->AsPhi();
-      if ((phi_use != NULL) &&
-          (phi_use->GetPropagatedCid() == kDynamicCid) &&
-          IsPossiblySmiPhi(phi_use)) {
-        AddToWorklist(phi_use);
-      }
-    }
-  }
-
-  // Now unmark phis that are not definitely smi: that is have only
-  // smi operands.
-  while (!worklist_.is_empty()) {
-    PhiInstr* phi = RemoveLastFromWorklist();
-    if (!IsDefinitelySmiPhi(phi)) {
-      // Phi result is not a smi. Propagate this fact to phis that depend on it.
-      phi->SetPropagatedCid(kDynamicCid);
-      for (Value* use = phi->input_use_list();
-           use != NULL;
-           use = use->next_use()) {
-        PhiInstr* phi_use = use->instruction()->AsPhi();
-        if ((phi_use != NULL) && (phi_use->GetPropagatedCid() == kSmiCid)) {
-          AddToWorklist(phi_use);
-        }
-      }
-    }
-  }
-}
-
-
-void SminessPropagator::PropagateSminessRecursive(BlockEntryInstr* block) {
-  const intptr_t rollback_point = rollback_checks_.length();
-
-  for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
-    Instruction* instr = it.Current();
-    if (instr->IsCheckSmi()) {
-      const intptr_t value_ssa_index =
-          instr->InputAt(0)->definition()->ssa_temp_index();
-      if (!known_smis_->Contains(value_ssa_index)) {
-        known_smis_->Add(value_ssa_index);
-        rollback_checks_.Add(value_ssa_index);
-      }
-    } else if (instr->IsBranch()) {
-      for (intptr_t i = 0; i < instr->InputCount(); i++) {
-        Value* use = instr->InputAt(i);
-        if (known_smis_->Contains(use->definition()->ssa_temp_index())) {
-          use->set_reaching_cid(kSmiCid);
-        }
-      }
-    }
-  }
-
-  for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
-    PropagateSminessRecursive(block->dominated_blocks()[i]);
-  }
-
-  if (block->last_instruction()->SuccessorCount() == 1 &&
-      block->last_instruction()->SuccessorAt(0)->IsJoinEntry()) {
-    JoinEntryInstr* join =
-        block->last_instruction()->SuccessorAt(0)->AsJoinEntry();
-    intptr_t pred_index = join->IndexOfPredecessor(block);
-    ASSERT(pred_index >= 0);
-    if (join->phis() != NULL) {
-      for (intptr_t i = 0; i < join->phis()->length(); ++i) {
-        PhiInstr* phi = (*join->phis())[i];
-        if (phi == NULL) continue;
-        Value* use = phi->InputAt(pred_index);
-        const intptr_t value_ssa_index = use->definition()->ssa_temp_index();
-        if (known_smis_->Contains(value_ssa_index) &&
-            (phi->GetPropagatedCid() != kSmiCid)) {
-          use->set_reaching_cid(kSmiCid);
-          AddToWorklist(phi);
-        }
-      }
-    }
-  }
-
-  for (intptr_t i = rollback_point; i < rollback_checks_.length(); i++) {
-    known_smis_->Remove(rollback_checks_[i]);
-  }
-  rollback_checks_.TruncateTo(rollback_point);
-}
-
-
-void SminessPropagator::Propagate() {
-  PropagateSminessRecursive(flow_graph_->graph_entry());
-  ProcessPhis();
-}
-
-
-void FlowGraphOptimizer::PropagateSminess() {
-  SminessPropagator propagator(flow_graph_);
-  propagator.Propagate();
-}
-
-
 // Range analysis for smi values.
 class RangeAnalysis : public ValueObject {
  public:
@@ -2268,7 +2091,7 @@
       Instruction* current = instr_it.Current();
       Definition* defn = current->AsDefinition();
       if (defn != NULL) {
-        if ((defn->GetPropagatedCid() == kSmiCid) &&
+        if ((defn->Type()->ToCid() == kSmiCid) &&
             (defn->ssa_temp_index() != -1)) {
           smi_values_.Add(defn);
         }
@@ -2281,7 +2104,7 @@
     if (join != NULL) {
       for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) {
         PhiInstr* current = phi_it.Current();
-        if (current->GetPropagatedCid() == kSmiCid) {
+        if ((current->Type()->ToCid() == kSmiCid)) {
           smi_values_.Add(current);
         }
       }
@@ -2736,261 +2559,6 @@
 }
 
 
-void FlowGraphTypePropagator::VisitBlocks() {
-  ASSERT(current_iterator_ == NULL);
-  for (intptr_t i = 0; i < block_order_.length(); ++i) {
-    BlockEntryInstr* entry = block_order_[i];
-    entry->Accept(this);
-    ForwardInstructionIterator it(entry);
-    current_iterator_ = &it;
-    for (; !it.Done(); it.Advance()) {
-      Instruction* current = it.Current();
-      // No need to propagate the input types of the instruction, as long as
-      // PhiInstr's are handled as part of JoinEntryInstr.
-
-      // Visit the instruction and possibly eliminate type checks.
-      current->Accept(this);
-      // The instruction may have been removed from the graph.
-      Definition* defn = current->AsDefinition();
-      if ((defn != NULL) &&
-          !defn->IsPushArgument() &&
-          (defn->previous() != NULL)) {
-        // Cache the propagated computation type.
-        AbstractType& type = AbstractType::Handle(defn->CompileType());
-        still_changing_ = defn->SetPropagatedType(type) || still_changing_;
-
-        // Propagate class ids.
-        const intptr_t cid = defn->ResultCid();
-        still_changing_ = defn->SetPropagatedCid(cid) || still_changing_;
-      }
-    }
-    current_iterator_ = NULL;
-  }
-}
-
-
-void FlowGraphTypePropagator::VisitAssertAssignable(
-    AssertAssignableInstr* instr) {
-  bool is_null, is_instance;
-  if (FLAG_eliminate_type_checks &&
-      !instr->is_eliminated() &&
-      ((instr->value()->CanComputeIsNull(&is_null) && is_null) ||
-       (instr->value()->CanComputeIsInstanceOf(instr->dst_type(), &is_instance)
-        && is_instance))) {
-    // TODO(regis): Remove is_eliminated_ field and support.
-    instr->eliminate();
-
-    Value* use = instr->value();
-    ASSERT(use != NULL);
-    Definition* result = use->definition();
-    ASSERT(result != NULL);
-    // Replace uses and remove the current instruction via the iterator.
-    instr->ReplaceUsesWith(result);
-    ASSERT(current_iterator()->Current() == instr);
-    current_iterator()->RemoveCurrentFromGraph();
-    if (FLAG_trace_optimization) {
-      OS::Print("Replacing v%"Pd" with v%"Pd"\n",
-                instr->ssa_temp_index(),
-                result->ssa_temp_index());
-    }
-
-    if (FLAG_trace_type_check_elimination) {
-      FlowGraphPrinter::PrintTypeCheck(parsed_function(),
-                                       instr->token_pos(),
-                                       instr->value(),
-                                       instr->dst_type(),
-                                       instr->dst_name(),
-                                       instr->is_eliminated());
-    }
-  }
-}
-
-
-void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanInstr* instr) {
-  bool is_null, is_bool;
-  if (FLAG_eliminate_type_checks &&
-      !instr->is_eliminated() &&
-      instr->value()->CanComputeIsNull(&is_null) &&
-      !is_null &&
-      instr->value()->CanComputeIsInstanceOf(Type::Handle(Type::BoolType()),
-                                             &is_bool) &&
-      is_bool) {
-    // TODO(regis): Remove is_eliminated_ field and support.
-    instr->eliminate();
-    Value* use = instr->value();
-    Definition* result = use->definition();
-    ASSERT(result != NULL);
-    // Replace uses and remove the current instruction via the iterator.
-    instr->ReplaceUsesWith(result);
-    ASSERT(current_iterator()->Current() == instr);
-    current_iterator()->RemoveCurrentFromGraph();
-    if (FLAG_trace_optimization) {
-      OS::Print("Replacing v%"Pd" with v%"Pd"\n",
-                instr->ssa_temp_index(),
-                result->ssa_temp_index());
-    }
-
-    if (FLAG_trace_type_check_elimination) {
-      FlowGraphPrinter::PrintTypeCheck(parsed_function(),
-                                       instr->token_pos(),
-                                       instr->value(),
-                                       Type::Handle(Type::BoolType()),
-                                       Symbols::BooleanExpression(),
-                                       instr->is_eliminated());
-    }
-  }
-}
-
-
-void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfInstr* instr) {
-  bool is_null;
-  bool is_instance = false;
-  if (FLAG_eliminate_type_checks &&
-      instr->value()->CanComputeIsNull(&is_null) &&
-      (is_null ||
-       instr->value()->CanComputeIsInstanceOf(instr->type(), &is_instance))) {
-    bool val = instr->negate_result() ? !is_instance : is_instance;
-    Definition* result = new ConstantInstr(val ? Bool::True() : Bool::False());
-    result->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
-    result->InsertBefore(instr);
-    // Replace uses and remove the current instruction via the iterator.
-    instr->ReplaceUsesWith(result);
-    ASSERT(current_iterator()->Current() == instr);
-    current_iterator()->RemoveCurrentFromGraph();
-    if (FLAG_trace_optimization) {
-      OS::Print("Replacing v%"Pd" with v%"Pd"\n",
-                instr->ssa_temp_index(),
-                result->ssa_temp_index());
-    }
-
-    if (FLAG_trace_type_check_elimination) {
-      FlowGraphPrinter::PrintTypeCheck(parsed_function(),
-                                       instr->token_pos(),
-                                       instr->value(),
-                                       instr->type(),
-                                       Symbols::InstanceOf(),
-                                       /* eliminated = */ true);
-    }
-  }
-}
-
-
-void FlowGraphTypePropagator::VisitGraphEntry(GraphEntryInstr* graph_entry) {
-  // Visit incoming parameters.
-  for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) {
-    ParameterInstr* param =
-        (*graph_entry->initial_definitions())[i]->AsParameter();
-    if (param != NULL) VisitParameter(param);
-  }
-}
-
-
-void FlowGraphTypePropagator::VisitJoinEntry(JoinEntryInstr* join_entry) {
-  if (join_entry->phis() != NULL) {
-    for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) {
-      PhiInstr* phi = (*join_entry->phis())[i];
-      if (phi != NULL) {
-        VisitPhi(phi);
-      }
-    }
-  }
-}
-
-
-// TODO(srdjan): Investigate if the propagated cid should be more specific.
-void FlowGraphTypePropagator::VisitPushArgument(PushArgumentInstr* push) {
-  if (!push->has_propagated_cid()) push->SetPropagatedCid(kDynamicCid);
-}
-
-
-void FlowGraphTypePropagator::VisitPhi(PhiInstr* phi) {
-  // We could set the propagated type of the phi to the least upper bound of its
-  // input propagated types. However, keeping all propagated types allows us to
-  // optimize method dispatch.
-  // TODO(regis): Support a set of propagated types. For now, we compute the
-  // least specific of the input propagated types.
-  AbstractType& type = AbstractType::Handle(phi->LeastSpecificInputType());
-  bool changed = phi->SetPropagatedType(type);
-  if (changed) {
-    still_changing_ = true;
-  }
-
-  // Merge class ids: if any two inputs have different class ids then result
-  // is kDynamicCid.
-  intptr_t merged_cid = kIllegalCid;
-  for (intptr_t i = 0; i < phi->InputCount(); i++) {
-    // Result cid of UseVal can be kIllegalCid if the referred definition
-    // has not been visited yet.
-    intptr_t cid = phi->InputAt(i)->ResultCid();
-    if (cid == kIllegalCid) {
-      still_changing_ = true;
-      continue;
-    }
-    if (merged_cid == kIllegalCid) {
-      // First time set.
-      merged_cid = cid;
-    } else if (merged_cid != cid) {
-      merged_cid = kDynamicCid;
-    }
-  }
-  if (merged_cid == kIllegalCid) {
-    merged_cid = kDynamicCid;
-  }
-  changed = phi->SetPropagatedCid(merged_cid);
-  if (changed) {
-    still_changing_ = true;
-  }
-}
-
-
-void FlowGraphTypePropagator::VisitParameter(ParameterInstr* param) {
-  // TODO(regis): Once we inline functions, the propagated type of the formal
-  // parameter will reflect the compile type of the passed-in argument.
-  // For now, we do not know anything about the argument type and therefore set
-  // it to the DynamicType, unless the argument is a compiler generated value,
-  // i.e. the receiver argument or the constructor phase argument.
-  AbstractType& param_type = AbstractType::Handle(Type::DynamicType());
-  param->SetPropagatedCid(kDynamicCid);
-  bool param_type_is_known = false;
-  if (param->index() == 0) {
-    const Function& function = parsed_function().function();
-    if ((function.IsDynamicFunction() || function.IsConstructor())) {
-      // Parameter is the receiver .
-      param_type_is_known = true;
-    }
-  } else if ((param->index() == 1) &&
-      parsed_function().function().IsConstructor()) {
-    // Parameter is the constructor phase.
-    param_type_is_known = true;
-  }
-  if (param_type_is_known) {
-    LocalScope* scope = parsed_function().node_sequence()->scope();
-    param_type = scope->VariableAt(param->index())->type().raw();
-    if (FLAG_use_cha) {
-      const intptr_t cid = Class::Handle(param_type.type_class()).id();
-      if (!CHA::HasSubclasses(cid)) {
-        // Receiver's class has no subclasses.
-        param->SetPropagatedCid(cid);
-      }
-    }
-  }
-  bool changed = param->SetPropagatedType(param_type);
-  if (changed) {
-    still_changing_ = true;
-  }
-}
-
-
-void FlowGraphTypePropagator::PropagateTypes() {
-  // TODO(regis): Is there a way to make this more efficient, e.g. by visiting
-  // only blocks depending on blocks that have changed and not the whole graph.
-  do {
-    still_changing_ = false;
-    VisitBlocks();
-  } while (still_changing_);
-}
-
-
 static BlockEntryInstr* FindPreHeader(BlockEntryInstr* header) {
   for (intptr_t j = 0; j < header->PredecessorCount(); ++j) {
     BlockEntryInstr* candidate = header->PredecessorAt(j);
@@ -3035,7 +2603,7 @@
     return;
   }
 
-  if (phi->GetPropagatedCid() == kSmiCid) {
+  if (phi->Type()->ToCid() == kSmiCid) {
     current->UnuseAllInputs();
     it->RemoveCurrentFromGraph();
     return;
@@ -3047,8 +2615,9 @@
   intptr_t non_smi_input = kNotFound;
   for (intptr_t i = 0; i < phi->InputCount(); ++i) {
     Value* input = phi->InputAt(i);
-    if (input->ResultCid() != kSmiCid) {
-      if ((non_smi_input != kNotFound) || (input->ResultCid() != kDynamicCid)) {
+    if (input->Type()->ToCid() != kSmiCid) {
+      if ((non_smi_input != kNotFound) ||
+          (input->Type()->ToCid() != kDynamicCid)) {
         // There are multiple kDynamicCid inputs or there is an input that is
         // known to be non-smi.
         return;
@@ -3072,7 +2641,7 @@
   current->value()->set_definition(non_smi_input_defn);
   non_smi_input_defn->AddInputUse(current->value());
 
-  phi->SetPropagatedCid(kSmiCid);
+  phi->Type()->ReplaceWith(CompileType::FromCid(kSmiCid));
 }
 
 
@@ -4118,10 +3687,10 @@
 
   if (IsNonConstant(left) || IsNonConstant(right)) {
     // TODO(vegorov): incorporate nullability information into the lattice.
-    if ((left.IsNull() && (instr->right()->ResultCid() != kDynamicCid)) ||
-        (right.IsNull() && (instr->left()->ResultCid() != kDynamicCid))) {
-      bool result = left.IsNull() ? (instr->right()->ResultCid() == kNullCid)
-                                  : (instr->left()->ResultCid() == kNullCid);
+    if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) ||
+        (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) {
+      bool result = left.IsNull() ? instr->right()->Type()->IsNull()
+                                  : instr->left()->Type()->IsNull();
       if (instr->kind() == Token::kNE_STRICT) result = !result;
       SetValue(instr, result ? Bool::True() : Bool::False());
     } else {
@@ -4274,7 +3843,7 @@
   if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) &&
       (instr->value()->definition()->IsCreateArray())) {
     const intptr_t length =
-        instr->value()->definition()->AsCreateArray()->ArgumentCount();
+        instr->value()->definition()->AsCreateArray()->num_elements();
     const Object& result = Smi::ZoneHandle(Smi::New(length));
     SetValue(instr, result);
     return;
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index b53054e..a0922ef 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -121,39 +121,6 @@
 class ParsedFunction;
 
 
-class FlowGraphTypePropagator : public FlowGraphVisitor {
- public:
-  explicit FlowGraphTypePropagator(FlowGraph* flow_graph)
-      : FlowGraphVisitor(flow_graph->reverse_postorder()),
-        parsed_function_(flow_graph->parsed_function()),
-        flow_graph_(flow_graph),
-        still_changing_(false) { }
-  virtual ~FlowGraphTypePropagator() { }
-
-  const ParsedFunction& parsed_function() const { return parsed_function_; }
-
-  void PropagateTypes();
-
- private:
-  virtual void VisitBlocks();
-
-  virtual void VisitAssertAssignable(AssertAssignableInstr* instr);
-  virtual void VisitAssertBoolean(AssertBooleanInstr* instr);
-  virtual void VisitInstanceOf(InstanceOfInstr* instr);
-
-  virtual void VisitGraphEntry(GraphEntryInstr* graph_entry);
-  virtual void VisitJoinEntry(JoinEntryInstr* join_entry);
-  virtual void VisitPhi(PhiInstr* phi);
-  virtual void VisitParameter(ParameterInstr* param);
-  virtual void VisitPushArgument(PushArgumentInstr* bind);
-
-  const ParsedFunction& parsed_function_;
-  FlowGraph* flow_graph_;
-  bool still_changing_;
-  DISALLOW_COPY_AND_ASSIGN(FlowGraphTypePropagator);
-};
-
-
 // Loop invariant code motion.
 class LICM : public AllStatic {
  public:
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
new file mode 100644
index 0000000..020172c
--- /dev/null
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -0,0 +1,734 @@
+// 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.
+
+#include "vm/flow_graph_type_propagator.h"
+
+#include "vm/cha.h"
+#include "vm/bit_vector.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool, trace_type_propagation, false,
+            "Trace flow graph type propagation");
+
+DECLARE_FLAG(bool, enable_type_checks);
+DECLARE_FLAG(bool, use_cha);
+
+
+FlowGraphTypePropagator::FlowGraphTypePropagator(FlowGraph* flow_graph)
+    : FlowGraphVisitor(flow_graph->reverse_postorder()),
+      flow_graph_(flow_graph),
+      types_(flow_graph->current_ssa_temp_index()),
+      in_worklist_(new BitVector(flow_graph->current_ssa_temp_index())) {
+  for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
+    types_.Add(NULL);
+  }
+}
+
+
+void FlowGraphTypePropagator::Propagate() {
+  // Walk dominator tree and propagate reaching types to all Values.
+  // Collect all phis for a fix point iteration.
+  PropagateRecursive(flow_graph_->graph_entry());
+
+#ifdef DEBUG
+  // Initially work-list contains only phis.
+  for (intptr_t i = 0; i < worklist_.length(); i++) {
+    ASSERT(worklist_[i]->IsPhi());
+    ASSERT(worklist_[i]->Type()->IsNone());
+  }
+#endif
+
+  // Iterate until fix point is reached updating types of definitions.
+  while (!worklist_.is_empty()) {
+    Definition* def = RemoveLastFromWorklist();
+    if (FLAG_trace_type_propagation) {
+      OS::Print("recomputing type of v%"Pd": %s\n",
+                def->ssa_temp_index(),
+                def->Type()->ToCString());
+    }
+    if (def->RecomputeType()) {
+      if (FLAG_trace_type_propagation) {
+        OS::Print("  ... new type %s\n", def->Type()->ToCString());
+      }
+      for (Value::Iterator it(def->input_use_list());
+           !it.Done();
+           it.Advance()) {
+        Definition* use_defn = it.Current()->instruction()->AsDefinition();
+        if (use_defn != NULL) {
+          AddToWorklist(use_defn);
+        }
+      }
+    }
+  }
+}
+
+
+void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
+  const intptr_t rollback_point = rollback_.length();
+
+  block->Accept(this);
+
+  for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+    Instruction* instr = it.Current();
+
+    for (intptr_t i = 0; i < instr->InputCount(); i++) {
+      VisitValue(instr->InputAt(i));
+    }
+    instr->Accept(this);
+  }
+
+  GotoInstr* goto_instr = block->last_instruction()->AsGoto();
+  if (goto_instr != NULL) {
+    JoinEntryInstr* join = goto_instr->successor();
+    intptr_t pred_index = join->IndexOfPredecessor(block);
+    ASSERT(pred_index >= 0);
+    for (PhiIterator it(join); !it.Done(); it.Advance()) {
+      VisitValue(it.Current()->InputAt(pred_index));
+    }
+  }
+
+  for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
+    PropagateRecursive(block->dominated_blocks()[i]);
+  }
+
+  for (intptr_t i = rollback_.length() - 1; i >= rollback_point; i--) {
+    types_[rollback_[i].index()] = rollback_[i].type();
+  }
+  rollback_.TruncateTo(rollback_point);
+}
+
+
+CompileType* FlowGraphTypePropagator::TypeOf(Definition* def) {
+  const intptr_t index = def->ssa_temp_index();
+
+  CompileType* type = types_[index];
+  if (type == NULL) {
+    type = types_[index] = def->Type();
+    ASSERT(type != NULL);
+  }
+  return type;
+}
+
+
+void FlowGraphTypePropagator::SetTypeOf(Definition* def, CompileType* type) {
+  const intptr_t index = def->ssa_temp_index();
+  rollback_.Add(RollbackEntry(index, types_[index]));
+  types_[index] = type;
+}
+
+
+void FlowGraphTypePropagator::SetCid(Definition* def, intptr_t cid) {
+  CompileType* current = TypeOf(def);
+  if (current->ToCid() == cid) return;
+
+  SetTypeOf(def, CompileType::FromCid(cid));
+}
+
+
+void FlowGraphTypePropagator::VisitValue(Value* value) {
+  CompileType* type = TypeOf(value->definition());
+  value->SetReachingType(type);
+
+  if (FLAG_trace_type_propagation) {
+    OS::Print("reaching type to v%"Pd" for v%"Pd" is %s\n",
+              value->instruction()->IsDefinition() ?
+                  value->instruction()->AsDefinition()->ssa_temp_index() : -1,
+              value->definition()->ssa_temp_index(),
+              type->ToCString());
+  }
+}
+
+
+void FlowGraphTypePropagator::VisitJoinEntry(JoinEntryInstr* join) {
+  for (PhiIterator it(join); !it.Done(); it.Advance()) {
+    if (it.Current()->is_alive()) {
+      worklist_.Add(it.Current());
+    }
+  }
+}
+
+
+void FlowGraphTypePropagator::VisitCheckSmi(CheckSmiInstr* check) {
+  SetCid(check->value()->definition(), kSmiCid);
+}
+
+
+void FlowGraphTypePropagator::VisitCheckClass(CheckClassInstr* check) {
+  if ((check->unary_checks().NumberOfChecks() != 1) ||
+      check->AffectedBySideEffect()) {
+    // TODO(vegorov): If check is affected by side-effect we can still propagate
+    // the type further but not the cid.
+    return;
+  }
+
+  SetCid(check->value()->definition(),
+         check->unary_checks().GetReceiverClassIdAt(0));
+}
+
+
+void FlowGraphTypePropagator::AddToWorklist(Definition* defn) {
+  if (defn->ssa_temp_index() == -1) {
+    return;
+  }
+
+  const intptr_t index = defn->ssa_temp_index();
+  if (!in_worklist_->Contains(index)) {
+    worklist_.Add(defn);
+    in_worklist_->Add(index);
+  }
+}
+
+
+Definition* FlowGraphTypePropagator::RemoveLastFromWorklist() {
+  Definition* defn = worklist_.RemoveLast();
+  ASSERT(defn->ssa_temp_index() != -1);
+  in_worklist_->Remove(defn->ssa_temp_index());
+  return defn;
+}
+
+
+void CompileType::Union(CompileType* other) {
+  if (other->IsNone()) {
+    return;
+  }
+
+  if (IsNone()) {
+    ReplaceWith(other);
+    return;
+  }
+
+  is_nullable_ = is_nullable_ || other->is_nullable_;
+
+  if (ToNullableCid() == kNullCid) {
+    cid_ = other->cid_;
+    type_ = other->type_;
+    return;
+  }
+
+  if (other->ToNullableCid() == kNullCid) {
+    return;
+  }
+
+  if (ToNullableCid() != other->ToNullableCid()) {
+    ASSERT(cid_ != kNullCid);
+    cid_ = kDynamicCid;
+  }
+
+  if (ToAbstractType()->IsMoreSpecificThan(*other->ToAbstractType(), NULL)) {
+    type_ = other->ToAbstractType();
+  } else if (ToAbstractType()->IsMoreSpecificThan(*ToAbstractType(), NULL)) {
+    // Nothing to do.
+  } else {
+    // Can't unify.
+    type_ = &Type::ZoneHandle(Type::DynamicType());
+  }
+}
+
+
+static bool IsNullableCid(intptr_t cid) {
+  ASSERT(cid != kIllegalCid);
+  return cid == kNullCid || cid == kDynamicCid;
+}
+
+
+CompileType* CompileType::New(intptr_t cid, const AbstractType& type) {
+  return new CompileType(IsNullableCid(cid), cid, &type);
+}
+
+
+CompileType* CompileType::FromAbstractType(const AbstractType& type,
+                                           bool is_nullable) {
+  return new CompileType(is_nullable, kIllegalCid, &type);
+}
+
+
+CompileType* CompileType::FromCid(intptr_t cid) {
+  return new CompileType(IsNullableCid(cid), cid, NULL);
+}
+
+
+CompileType* CompileType::Dynamic() {
+  return New(kDynamicCid, Type::ZoneHandle(Type::DynamicType()));
+}
+
+
+CompileType* CompileType::Null() {
+  return New(kNullCid, Type::ZoneHandle(Type::NullType()));
+}
+
+
+CompileType* CompileType::Bool() {
+  return New(kBoolCid, Type::ZoneHandle(Type::BoolType()));
+}
+
+
+CompileType* CompileType::Int() {
+  return FromAbstractType(Type::ZoneHandle(Type::IntType()), kNonNullable);
+}
+
+
+intptr_t CompileType::ToCid() {
+  if ((cid_ == kNullCid) || (cid_ == kDynamicCid)) {
+    return cid_;
+  }
+
+  return is_nullable_ ? static_cast<intptr_t>(kDynamicCid) : ToNullableCid();
+}
+
+
+intptr_t CompileType::ToNullableCid() {
+  if (cid_ == kIllegalCid) {
+    ASSERT(type_ != NULL);
+
+    if (type_->IsMalformed()) {
+      cid_ = kDynamicCid;
+    } else if (type_->IsVoidType()) {
+      cid_ = kNullCid;
+    } else if (FLAG_use_cha && type_->HasResolvedTypeClass()) {
+      const intptr_t cid = Class::Handle(type_->type_class()).id();
+      if (!CHA::HasSubclasses(cid)) {
+        cid_ = cid;
+      }
+    } else {
+      cid_ = kDynamicCid;
+    }
+  }
+
+  return cid_;
+}
+
+
+bool CompileType::HasDecidableNullability() {
+  return !is_nullable_ || IsNull();
+}
+
+
+bool CompileType::IsNull() {
+  return (ToCid() == kNullCid);
+}
+
+
+const AbstractType* CompileType::ToAbstractType() {
+  if (type_ == NULL) {
+    ASSERT(cid_ != kIllegalCid);
+
+    const Class& type_class =
+        Class::Handle(Isolate::Current()->class_table()->At(cid_));
+
+    if (type_class.HasTypeArguments()) {
+      type_ = &Type::ZoneHandle(Type::DynamicType());
+      return type_;
+    }
+
+    type_ = &Type::ZoneHandle(Type::NewNonParameterizedType(type_class));
+  }
+
+  return type_;
+}
+
+
+bool CompileType::CanComputeIsInstanceOf(const AbstractType& type,
+                                         bool is_nullable,
+                                         bool* is_instance) {
+  ASSERT(is_instance != NULL);
+  // We cannot give an answer if the given type is malformed.
+  if (type.IsMalformed()) {
+    return false;
+  }
+
+  if (type.IsDynamicType() || type.IsObjectType()) {
+    *is_instance = true;
+    return true;
+  }
+
+  if (IsNone()) {
+    return false;
+  }
+
+  // We should never test for an instance of null.
+  ASSERT(!type.IsNullType());
+
+  // Consider the compile type of the value.
+  const AbstractType& compile_type = *ToAbstractType();
+  if (compile_type.IsMalformed()) {
+    return false;
+  }
+
+  // If the compile type of the value is void, we are type checking the result
+  // of a void function, which was checked to be null at the return statement
+  // inside the function.
+  if (compile_type.IsVoidType()) {
+    ASSERT(FLAG_enable_type_checks);
+    *is_instance = true;
+    return true;
+  }
+
+  // The Null type is only a subtype of Object and of dynamic.
+  // Functions that do not explicitly return a value, implicitly return null,
+  // except generative constructors, which return the object being constructed.
+  // It is therefore acceptable for void functions to return null.
+  if (compile_type.IsNullType()) {
+    *is_instance = is_nullable ||
+        type.IsObjectType() || type.IsDynamicType() || type.IsVoidType();
+    return true;
+  }
+
+  // A non-null value is not an instance of void.
+  if (type.IsVoidType()) {
+    *is_instance = IsNull();
+    return HasDecidableNullability();
+  }
+
+  // If the value can be null then we can't eliminate the
+  // check unless null is allowed.
+  if (is_nullable_ && !is_nullable) {
+    return false;
+  }
+
+  Error& malformed_error = Error::Handle();
+  *is_instance = compile_type.IsMoreSpecificThan(type, &malformed_error);
+  return malformed_error.IsNull() && *is_instance;
+}
+
+
+bool CompileType::IsMoreSpecificThan(const AbstractType& other) {
+  return !IsNone() && ToAbstractType()->IsMoreSpecificThan(other, NULL);
+}
+
+
+CompileType* Value::Type() {
+  if (reaching_type_ == NULL) {
+    reaching_type_ = definition()->Type();
+  }
+  return reaching_type_;
+}
+
+
+CompileType* PhiInstr::ComputeInitialType() const {
+  // Initially type of phis is unknown until type propagation is run
+  // for the first time.
+  return CompileType::None();
+}
+
+
+bool PhiInstr::RecomputeType() {
+  if (!is_alive()) {
+    return false;
+  }
+
+  CompileType* result = CompileType::None();
+
+  for (intptr_t i = 0; i < InputCount(); i++) {
+    if (FLAG_trace_type_propagation) {
+      OS::Print("  phi %"Pd" input %"Pd": v%"Pd" has reaching type %s\n",
+                ssa_temp_index(),
+                i,
+                InputAt(i)->definition()->ssa_temp_index(),
+                InputAt(i)->Type()->ToCString());
+    }
+    result->Union(InputAt(i)->Type());
+  }
+
+  if (result->IsNone()) {
+    ASSERT(Type()->IsNone());
+    return false;
+  }
+
+  if (Type()->IsNone() || !Type()->IsEqualTo(result)) {
+    Type()->ReplaceWith(result);
+    return true;
+  }
+
+  return false;
+}
+
+
+
+CompileType* ParameterInstr::ComputeInitialType() const {
+  // Note that returning the declared type of the formal parameter would be
+  // incorrect, because ParameterInstr is used as input to the type check
+  // verifying the run time type of the passed-in parameter and this check would
+  // always be wrongly eliminated.
+  return CompileType::Dynamic();
+}
+
+
+CompileType* PushArgumentInstr::ComputeInitialType() const {
+  return CompileType::Dynamic();
+}
+
+
+CompileType* ConstantInstr::ComputeInitialType() const {
+  if (value().IsNull()) {
+    return CompileType::Null();
+  }
+
+  if (value().IsInstance()) {
+    return CompileType::New(
+        Class::Handle(value().clazz()).id(),
+        AbstractType::ZoneHandle(Instance::Cast(value()).GetType()));
+  } else {
+    ASSERT(value().IsAbstractTypeArguments());
+    return CompileType::Dynamic();
+  }
+}
+
+
+CompileType* AssertAssignableInstr::ComputeInitialType() const {
+  CompileType* value_type = value()->Type();
+  if (value_type->IsMoreSpecificThan(dst_type())) {
+    return value_type;
+  }
+  return CompileType::FromAbstractType(dst_type());
+}
+
+
+bool AssertAssignableInstr::RecomputeType() {
+  CompileType* value_type = value()->Type();
+  if (value_type == Type()) {
+    return false;
+  }
+
+  if (value_type->IsMoreSpecificThan(dst_type()) &&
+      !Type()->IsEqualTo(value_type)) {
+    Type()->ReplaceWith(value_type);
+    return true;
+  }
+
+  return false;
+}
+
+
+CompileType* AssertBooleanInstr::ComputeInitialType() const {
+  return CompileType::Bool();
+}
+
+
+CompileType* ArgumentDefinitionTestInstr::ComputeInitialType() const {
+  return CompileType::Bool();
+}
+
+
+CompileType* BooleanNegateInstr::ComputeInitialType() const {
+  return CompileType::Bool();
+}
+
+
+CompileType* InstanceOfInstr::ComputeInitialType() const {
+  return CompileType::Bool();
+}
+
+
+CompileType* StrictCompareInstr::ComputeInitialType() const {
+  return CompileType::Bool();
+}
+
+
+CompileType* EqualityCompareInstr::ComputeInitialType() const {
+  return IsInlinedNumericComparison() ? CompileType::Bool()
+                                      : CompileType::Dynamic();
+}
+
+
+CompileType* RelationalOpInstr::ComputeInitialType() const {
+  return IsInlinedNumericComparison() ? CompileType::Bool()
+                                      : CompileType::Dynamic();
+}
+
+
+CompileType* CurrentContextInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kContextCid);
+}
+
+
+CompileType* CloneContextInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kContextCid);
+}
+
+
+CompileType* AllocateContextInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kContextCid);
+}
+
+
+CompileType* StaticCallInstr::ComputeInitialType() const {
+  if (result_cid_ != kDynamicCid) {
+    return CompileType::FromCid(result_cid_);
+  }
+
+  if (FLAG_enable_type_checks) {
+    return CompileType::FromAbstractType(
+        AbstractType::ZoneHandle(function().result_type()));
+  }
+
+  return CompileType::Dynamic();
+}
+
+
+CompileType* LoadLocalInstr::ComputeInitialType() const {
+  if (FLAG_enable_type_checks) {
+    return CompileType::FromAbstractType(local().type());
+  }
+  return CompileType::Dynamic();
+}
+
+
+CompileType* StoreLocalInstr::ComputeInitialType() const {
+  // Returns stored value.
+  return value()->Type();
+}
+
+
+CompileType* StringFromCharCodeInstr::ComputeInitialType() const {
+  return CompileType::FromCid(cid_);
+}
+
+
+CompileType* StoreInstanceFieldInstr::ComputeInitialType() const {
+  return value()->Type();
+}
+
+
+CompileType* LoadStaticFieldInstr::ComputeInitialType() const {
+  if (FLAG_enable_type_checks) {
+    return CompileType::FromAbstractType(
+        AbstractType::ZoneHandle(field().type()));
+  }
+  return CompileType::Dynamic();
+}
+
+
+CompileType* StoreStaticFieldInstr::ComputeInitialType() const {
+  return value()->Type();
+}
+
+
+CompileType* CreateArrayInstr::ComputeInitialType() const {
+  return CompileType::FromAbstractType(type(), CompileType::kNonNullable);
+}
+
+
+CompileType* CreateClosureInstr::ComputeInitialType() const {
+  const Function& fun = function();
+  const Class& signature_class = Class::Handle(fun.signature_class());
+  return CompileType::FromAbstractType(
+      Type::ZoneHandle(signature_class.SignatureType()),
+      CompileType::kNonNullable);
+}
+
+
+CompileType* AllocateObjectInstr::ComputeInitialType() const {
+  // TODO(vegorov): Incorporate type arguments into the returned type.
+  return CompileType::FromCid(cid_);
+}
+
+
+CompileType* LoadFieldInstr::ComputeInitialType() const {
+  // Type may be null if the field is a VM field, e.g. context parent.
+  // Keep it as null for debug purposes and do not return dynamic in production
+  // mode, since misuse of the type would remain undetected.
+  if (type().IsNull()) {
+    return CompileType::Dynamic();
+  }
+
+  if (FLAG_enable_type_checks) {
+    return CompileType::FromAbstractType(type());
+  }
+
+  return CompileType::FromCid(result_cid_);
+}
+
+
+CompileType* StoreVMFieldInstr::ComputeInitialType() const {
+  return value()->Type();
+}
+
+
+CompileType* BinarySmiOpInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kSmiCid);
+}
+
+
+CompileType* UnarySmiOpInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kSmiCid);
+}
+
+
+CompileType* DoubleToSmiInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kSmiCid);
+}
+
+
+CompileType* ConstraintInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kSmiCid);
+}
+
+
+CompileType* BinaryMintOpInstr::ComputeInitialType() const {
+  return CompileType::Int();
+}
+
+
+CompileType* ShiftMintOpInstr::ComputeInitialType() const {
+  return CompileType::Int();
+}
+
+
+CompileType* UnaryMintOpInstr::ComputeInitialType() const {
+  return CompileType::Int();
+}
+
+
+CompileType* BoxIntegerInstr::ComputeInitialType() const {
+  return CompileType::Int();
+}
+
+
+CompileType* UnboxIntegerInstr::ComputeInitialType() const {
+  return CompileType::Int();
+}
+
+
+CompileType* DoubleToIntegerInstr::ComputeInitialType() const {
+  return CompileType::Int();
+}
+
+
+CompileType* BinaryDoubleOpInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* MathSqrtInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* UnboxDoubleInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* BoxDoubleInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* SmiToDoubleInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* DoubleToDoubleInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* InvokeMathCFunctionInstr::ComputeInitialType() const {
+  return CompileType::FromCid(kDoubleCid);
+}
+
+
+}  // namespace dart
diff --git a/runtime/vm/flow_graph_type_propagator.h b/runtime/vm/flow_graph_type_propagator.h
new file mode 100644
index 0000000..fafd1b6
--- /dev/null
+++ b/runtime/vm/flow_graph_type_propagator.h
@@ -0,0 +1,77 @@
+// 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.
+
+#ifndef VM_FLOW_GRAPH_TYPE_PROPAGATOR_H_
+#define VM_FLOW_GRAPH_TYPE_PROPAGATOR_H_
+
+#include "vm/flow_graph.h"
+#include "vm/intermediate_language.h"
+
+namespace dart {
+
+class FlowGraphTypePropagator : public FlowGraphVisitor {
+ public:
+  explicit FlowGraphTypePropagator(FlowGraph* flow_graph);
+
+  void Propagate();
+
+ private:
+  void PropagateRecursive(BlockEntryInstr* block);
+
+  void VisitValue(Value* value);
+
+  virtual void VisitJoinEntry(JoinEntryInstr* instr);
+  virtual void VisitCheckSmi(CheckSmiInstr* instr);
+  virtual void VisitCheckClass(CheckClassInstr* instr);
+
+  // Current reaching type of the definition. Valid only during dominator tree
+  // traversal.
+  CompileType* TypeOf(Definition* def);
+
+  // Mark definition as having given compile type in all dominated instructions.
+  void SetTypeOf(Definition* def, CompileType* type);
+
+  // Mark definition as having given class id in all dominated instructions.
+  void SetCid(Definition* value, intptr_t cid);
+
+  void AddToWorklist(Definition* defn);
+  Definition* RemoveLastFromWorklist();
+
+  FlowGraph* flow_graph_;
+
+  // Mapping between SSA values and their current reaching types. Valid
+  // only during dominator tree traversal.
+  GrowableArray<CompileType*> types_;
+
+  // Worklist for fixpoint computation.
+  GrowableArray<Definition*> worklist_;
+  BitVector* in_worklist_;
+
+  // RollbackEntry is used to track and rollback changed in the types_ array
+  // done during dominator tree traversal.
+  class RollbackEntry {
+   public:
+    // Default constructor needed for the container.
+    RollbackEntry()
+        : index_(), type_() {
+    }
+
+    RollbackEntry(intptr_t index, CompileType* type)
+        : index_(index), type_(type) {
+    }
+
+    intptr_t index() const { return index_; }
+    CompileType* type() const { return type_; }
+
+   private:
+    intptr_t index_;
+    CompileType* type_;
+  };
+
+  GrowableArray<RollbackEntry> rollback_;
+};
+
+}  // namespace dart
+
+#endif  // VM_FLOW_GRAPH_TYPE_PROPAGATOR_H_
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index bd501ac..02db6e23 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -88,17 +88,12 @@
                                       const AbstractType& dst_type,
                                       const String& dst_name,
                                       bool eliminated) {
-    const Script& script = Script::Handle(parsed_function.function().script());
     const char* compile_type_name = "unknown";
     if (value != NULL) {
-      const AbstractType& type = AbstractType::Handle(value->CompileType());
-      if (!type.IsNull()) {
-        compile_type_name = String::Handle(type.Name()).ToCString();
-      }
+      compile_type_name = value->Type()->ToCString();
     }
-    Parser::PrintMessage(script, token_pos, "",
-                         "%s type check: compile type '%s' is %s specific than "
-                         "type '%s' of '%s'.",
+    OS::Print("%s type check: compile type %s is %s specific than "
+              "type '%s' of '%s'.\n",
                          eliminated ? "Eliminated" : "Generated",
                          compile_type_name,
                          eliminated ? "more" : "not more",
@@ -107,6 +102,31 @@
 }
 
 
+void CompileType::PrintTo(BufferFormatter* f) const {
+  f->Print("T{");
+  f->Print("%s, ", is_nullable_ ? "null" : "not-null");
+  if (cid_ != kIllegalCid) {
+    const Class& cls =
+      Class::Handle(Isolate::Current()->class_table()->At(cid_));
+    f->Print("%s, ", String::Handle(cls.Name()).ToCString());
+  } else {
+    f->Print("?, ");
+  }
+  f->Print("%s}", (type_ != NULL) ? String::Handle(type_->Name()).ToCString()
+                                  : "?");
+}
+
+
+const char* CompileType::ToCString() const {
+  char buffer[1024];
+  BufferFormatter f(buffer, sizeof(buffer));
+  PrintTo(&f);
+  return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
+}
+
+
+
+
 static void PrintICData(BufferFormatter* f, const ICData& ic_data) {
   f->Print(" IC[%"Pd": ", ic_data.NumberOfChecks());
   Function& target = Function::Handle();
@@ -134,20 +154,6 @@
 }
 
 
-static void PrintPropagatedType(BufferFormatter* f, const Definition& def) {
-  if (def.HasPropagatedType()) {
-    String& name = String::Handle();
-    name = AbstractType::Handle(def.PropagatedType()).Name();
-    f->Print(" {PT: %s}", name.ToCString());
-  }
-  if (def.has_propagated_cid()) {
-    const Class& cls = Class::Handle(
-        Isolate::Current()->class_table()->At(def.propagated_cid()));
-    f->Print(" {PCid: %s}", String::Handle(cls.Name()).ToCString());
-  }
-}
-
-
 static void PrintUse(BufferFormatter* f, const Definition& definition) {
   if (definition.is_used()) {
     if (definition.HasSSATemp()) {
@@ -182,11 +188,15 @@
   f->Print("%s:%"Pd"(", DebugName(), GetDeoptId());
   PrintOperandsTo(f);
   f->Print(")");
-  PrintPropagatedType(f, *this);
   if (range_ != NULL) {
     f->Print(" ");
     range_->PrintTo(f);
   }
+
+  if (type_ != NULL) {
+    f->Print(" ");
+    type_->PrintTo(f);
+  }
 }
 
 
@@ -200,6 +210,11 @@
 
 void Value::PrintTo(BufferFormatter* f) const {
   PrintUse(f, *definition());
+  if ((reaching_type_ != NULL) &&
+      (reaching_type_ != definition()->Type())) {
+    f->Print(" ");
+    reaching_type_->PrintTo(f);
+  }
 }
 
 
@@ -276,10 +291,9 @@
 
 void AssertAssignableInstr::PrintOperandsTo(BufferFormatter* f) const {
   value()->PrintTo(f);
-  f->Print(", %s, '%s'%s",
-           String::Handle(dst_type().Name()).ToCString(),
-           dst_name().ToCString(),
-           is_eliminated() ? " eliminated" : "");
+  f->Print(", %s, '%s'",
+           dst_type().ToCString(),
+           dst_name().ToCString());
   f->Print(" instantiator(");
   instantiator()->PrintTo(f);
   f->Print(")");
@@ -291,7 +305,6 @@
 
 void AssertBooleanInstr::PrintOperandsTo(BufferFormatter* f) const {
   value()->PrintTo(f);
-  f->Print("%s", is_eliminated() ? " eliminated" : "");
 }
 
 
@@ -607,7 +620,6 @@
     if (i < inputs_.length() - 1) f->Print(", ");
   }
   f->Print(")");
-  PrintPropagatedType(f, *this);
   if (is_alive()) {
     f->Print(" alive");
   } else {
@@ -617,6 +629,10 @@
     f->Print(" ");
     range_->PrintTo(f);
   }
+  if (type_ != NULL) {
+    f->Print(" ");
+    type_->PrintTo(f);
+  }
 }
 
 
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 48edba3..9e92536 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -25,15 +25,15 @@
 DEFINE_FLAG(bool, propagate_ic_data, true,
     "Propagate IC data from unoptimized to optimized IC calls.");
 DECLARE_FLAG(bool, enable_type_checks);
+DECLARE_FLAG(bool, eliminate_type_checks);
 DECLARE_FLAG(int, max_polymorphic_checks);
 DECLARE_FLAG(bool, trace_optimization);
 
 Definition::Definition()
     : range_(NULL),
+      type_(NULL),
       temp_index_(-1),
       ssa_temp_index_(-1),
-      propagated_type_(AbstractType::Handle()),
-      propagated_cid_(kIllegalCid),
       input_use_list_(NULL),
       env_use_list_(NULL),
       use_kind_(kValue),  // Phis and parameters rely on this default.
@@ -146,10 +146,7 @@
   LoadFieldInstr* other_load = other->AsLoadField();
   ASSERT(other_load != NULL);
   ASSERT((offset_in_bytes() != other_load->offset_in_bytes()) ||
-         ((immutable_ == other_load->immutable_) &&
-          ((ResultCid() == other_load->ResultCid()) ||
-           (ResultCid() == kDynamicCid) ||
-           (other_load->ResultCid() == kDynamicCid))));
+         ((immutable_ == other_load->immutable_)));
   return offset_in_bytes() == other_load->offset_in_bytes();
 }
 
@@ -407,178 +404,17 @@
 }
 
 
-// TODO(regis): Support a set of compile types for the given value.
-bool Value::CanComputeIsNull(bool* is_null) const {
-  ASSERT(is_null != NULL);
-  // For now, we can only return a meaningful result if the value is constant.
-  if (!BindsToConstant()) {
+bool Value::NeedsStoreBuffer() {
+  if (Type()->IsNull() ||
+      (Type()->ToNullableCid() == kSmiCid) ||
+      (Type()->ToNullableCid() == kBoolCid)) {
     return false;
   }
 
-  // Return true if the constant value is Object::null.
-  if (BindsToConstantNull()) {
-    *is_null = true;
-    return true;
-  }
-
-  // Consider the compile type of the value to check for sentinels, which are
-  // also treated as null.
-  const AbstractType& compile_type = AbstractType::Handle(CompileType());
-  ASSERT(!compile_type.IsMalformed());
-  ASSERT(!compile_type.IsVoidType());
-
-  // There are only three instances that can be of type Null:
-  // Object::null(), Object::sentinel(), and Object::transition_sentinel().
-  // The inline code and run time code performing the type check will only
-  // encounter the 2 sentinel values if type check elimination was disabled.
-  // Otherwise, the type check of a sentinel value will be eliminated here,
-  // because these sentinel values can only be encountered as constants, never
-  // as actual value of a heap object being type checked.
-  if (compile_type.IsNullType()) {
-    *is_null = true;
-    return true;
-  }
-
-  return false;
-}
-
-
-// TODO(regis): Support a set of compile types for the given value.
-bool Value::CanComputeIsInstanceOf(const AbstractType& type,
-                                   bool* is_instance) const {
-  ASSERT(is_instance != NULL);
-  // We cannot give an answer if the given type is malformed.
-  if (type.IsMalformed()) {
-    return false;
-  }
-
-  // We should never test for an instance of null.
-  ASSERT(!type.IsNullType());
-
-  // Consider the compile type of the value.
-  const AbstractType& compile_type = AbstractType::Handle(CompileType());
-  if (compile_type.IsMalformed()) {
-    return false;
-  }
-
-  // If the compile type of the value is void, we are type checking the result
-  // of a void function, which was checked to be null at the return statement
-  // inside the function.
-  if (compile_type.IsVoidType()) {
-    ASSERT(FLAG_enable_type_checks);
-    *is_instance = true;
-    return true;
-  }
-
-  // The Null type is only a subtype of Object and of dynamic.
-  // Functions that do not explicitly return a value, implicitly return null,
-  // except generative constructors, which return the object being constructed.
-  // It is therefore acceptable for void functions to return null.
-  if (compile_type.IsNullType()) {
-    *is_instance =
-        type.IsObjectType() || type.IsDynamicType() || type.IsVoidType();
-    return true;
-  }
-
-  // Until we support a set of compile types, we can only give answers for
-  // constant values. Indeed, a variable of the proper compile time type may
-  // still hold null at run time and therefore fail the test.
-  if (!BindsToConstant()) {
-    return false;
-  }
-
-  // A non-null constant is not an instance of void.
-  if (type.IsVoidType()) {
-    *is_instance = false;
-    return true;
-  }
-
-  // Since the value is a constant, its type is instantiated.
-  ASSERT(compile_type.IsInstantiated());
-
-  // The run time type of the value is guaranteed to be a subtype of the
-  // compile time type of the value. However, establishing here that the
-  // compile time type is a subtype of the given type does not guarantee that
-  // the run time type will also be a subtype of the given type, because the
-  // subtype relation is not transitive when an uninstantiated type is
-  // involved.
-  Error& malformed_error = Error::Handle();
-  if (type.IsInstantiated()) {
-    // Perform the test on the compile-time type and provide the answer, unless
-    // the type test produced a malformed error (e.g. an upper bound error).
-    *is_instance = compile_type.IsSubtypeOf(type, &malformed_error);
-  } else {
-    // However, the 'more specific than' relation is transitive and used here.
-    // In other words, if the compile type of the value is more specific than
-    // the given type, the run time type of the value, which is guaranteed to be
-    // a subtype of the compile type, is also guaranteed to be a subtype of the
-    // given type.
-    *is_instance = compile_type.IsMoreSpecificThan(type, &malformed_error);
-  }
-  return malformed_error.IsNull();
-}
-
-
-bool Value::NeedsStoreBuffer() const {
-  const intptr_t cid = ResultCid();
-  if ((cid == kSmiCid) || (cid == kBoolCid) || (cid == kNullCid)) {
-    return false;
-  }
   return !BindsToConstant();
 }
 
 
-RawAbstractType* PhiInstr::CompileType() const {
-  ASSERT(!HasPropagatedType());
-  // Since type propagation has not yet occured, we are reaching this phi via a
-  // back edge phi input. Return null as compile type so that this input is
-  // ignored in the first iteration of type propagation.
-  return AbstractType::null();
-}
-
-
-RawAbstractType* PhiInstr::LeastSpecificInputType() const {
-  AbstractType& least_specific_type = AbstractType::Handle();
-  AbstractType& input_type = AbstractType::Handle();
-  for (intptr_t i = 0; i < InputCount(); i++) {
-    input_type = InputAt(i)->CompileType();
-    if (input_type.IsNull()) {
-      // This input is on a back edge and we are in the first iteration of type
-      // propagation. Ignore it.
-      continue;
-    }
-    ASSERT(!input_type.IsNull());
-    if (least_specific_type.IsNull() ||
-        least_specific_type.IsMoreSpecificThan(input_type, NULL)) {
-      // Type input_type is less specific than the current least_specific_type.
-      least_specific_type = input_type.raw();
-    } else if (input_type.IsMoreSpecificThan(least_specific_type, NULL)) {
-      // Type least_specific_type is less specific than input_type. No change.
-    } else {
-      // The types are unrelated. No need to continue.
-      least_specific_type = Type::ObjectType();
-      break;
-    }
-  }
-  return least_specific_type.raw();
-}
-
-
-RawAbstractType* ParameterInstr::CompileType() const {
-  ASSERT(!HasPropagatedType());
-  // Note that returning the declared type of the formal parameter would be
-  // incorrect, because ParameterInstr is used as input to the type check
-  // verifying the run time type of the passed-in parameter and this check would
-  // always be wrongly eliminated.
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* PushArgumentInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) {
   // Require the predecessors to be sorted by block_id to make managing
   // their corresponding phi inputs simpler.
@@ -727,45 +563,6 @@
 }
 
 
-bool Definition::SetPropagatedCid(intptr_t cid) {
-  if (cid == kIllegalCid) {
-    return false;
-  }
-  if (propagated_cid_ == kIllegalCid) {
-    // First setting, nothing has changed.
-    propagated_cid_ = cid;
-    return false;
-  }
-  bool has_changed = (propagated_cid_ != cid);
-  propagated_cid_ = cid;
-  return has_changed;
-}
-
-
-intptr_t Definition::GetPropagatedCid() {
-  if (has_propagated_cid()) return propagated_cid();
-  intptr_t cid = ResultCid();
-  ASSERT(cid != kIllegalCid);
-  SetPropagatedCid(cid);
-  return cid;
-}
-
-
-intptr_t PhiInstr::GetPropagatedCid() {
-  return propagated_cid();
-}
-
-
-intptr_t ParameterInstr::GetPropagatedCid() {
-  return propagated_cid();
-}
-
-
-intptr_t AssertAssignableInstr::GetPropagatedCid() {
-  return propagated_cid();
-}
-
-
 // ==== Postorder graph traversal.
 static bool IsMarked(BlockEntryInstr* block,
                      GrowableArray<BlockEntryInstr*>* preorder) {
@@ -1027,154 +824,6 @@
 }
 
 
-RawAbstractType* Value::CompileType() const {
-  if (definition()->HasPropagatedType()) {
-    return definition()->PropagatedType();
-  }
-  // The compile type may be requested when building the flow graph, i.e. before
-  // type propagation has occurred. To avoid repeatedly computing the compile
-  // type of the definition, we store it as initial propagated type.
-  AbstractType& type = AbstractType::Handle(definition()->CompileType());
-  definition()->SetPropagatedType(type);
-  return type.raw();
-}
-
-
-intptr_t Value::ResultCid() const {
-  if (reaching_cid() == kIllegalCid) {
-    return definition()->GetPropagatedCid();
-  }
-  return reaching_cid();
-}
-
-
-
-RawAbstractType* ConstantInstr::CompileType() const {
-  if (value().IsNull()) {
-    return Type::NullType();
-  }
-  if (value().IsInstance()) {
-    return Instance::Cast(value()).GetType();
-  } else {
-    ASSERT(value().IsAbstractTypeArguments());
-    return AbstractType::null();
-  }
-}
-
-
-intptr_t ConstantInstr::ResultCid() const {
-  if (value().IsNull()) {
-    return kNullCid;
-  }
-  if (value().IsInstance()) {
-    return Class::Handle(value().clazz()).id();
-  } else {
-    ASSERT(value().IsAbstractTypeArguments());
-    return kDynamicCid;
-  }
-}
-
-
-RawAbstractType* AssertAssignableInstr::CompileType() const {
-  const AbstractType& value_compile_type =
-      AbstractType::Handle(value()->CompileType());
-  if (!value_compile_type.IsNull() &&
-      value_compile_type.IsMoreSpecificThan(dst_type(), NULL)) {
-    return value_compile_type.raw();
-  }
-  return dst_type().raw();
-}
-
-
-RawAbstractType* AssertBooleanInstr::CompileType() const {
-  return Type::BoolType();
-}
-
-
-RawAbstractType* ArgumentDefinitionTestInstr::CompileType() const {
-  return Type::BoolType();
-}
-
-
-RawAbstractType* CurrentContextInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* StoreContextInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* ClosureCallInstr::CompileType() const {
-  // Because of function subtyping rules, the declared return type of a closure
-  // call cannot be relied upon for compile type analysis. For example, a
-  // function returning dynamic can be assigned to a closure variable declared
-  // to return int and may actually return a double at run-time.
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* InstanceCallInstr::CompileType() const {
-  // TODO(regis): Return a more specific type than dynamic for recognized
-  // combinations of receiver type and method name.
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* PolymorphicInstanceCallInstr::CompileType() const {
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* StaticCallInstr::CompileType() const {
-  if (FLAG_enable_type_checks) {
-    return function().result_type();
-  }
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* LoadLocalInstr::CompileType() const {
-  if (FLAG_enable_type_checks) {
-    return local().type().raw();
-  }
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* StoreLocalInstr::CompileType() const {
-  return value()->CompileType();
-}
-
-
-RawAbstractType* StrictCompareInstr::CompileType() const {
-  return Type::BoolType();
-}
-
-
-// Only known == targets return a Boolean.
-RawAbstractType* EqualityCompareInstr::CompileType() const {
-  if ((receiver_class_id() == kSmiCid) ||
-      (receiver_class_id() == kDoubleCid) ||
-      (receiver_class_id() == kNumberCid)) {
-    return Type::BoolType();
-  }
-  return Type::DynamicType();
-}
-
-
-intptr_t EqualityCompareInstr::ResultCid() const {
-  if ((receiver_class_id() == kSmiCid) ||
-      (receiver_class_id() == kDoubleCid) ||
-      (receiver_class_id() == kNumberCid)) {
-    // Known/library equalities that are guaranteed to return Boolean.
-    return kBoolCid;
-  }
-  return kDynamicCid;
-}
-
-
 bool EqualityCompareInstr::IsPolymorphic() const {
   return HasICData() &&
       (ic_data()->NumberOfChecks() > 0) &&
@@ -1182,194 +831,6 @@
 }
 
 
-RawAbstractType* RelationalOpInstr::CompileType() const {
-  if ((operands_class_id() == kSmiCid) ||
-      (operands_class_id() == kDoubleCid) ||
-      (operands_class_id() == kNumberCid)) {
-    // Known/library relational ops that are guaranteed to return Boolean.
-    return Type::BoolType();
-  }
-  return Type::DynamicType();
-}
-
-
-intptr_t RelationalOpInstr::ResultCid() const {
-  if ((operands_class_id() == kSmiCid) ||
-      (operands_class_id() == kDoubleCid) ||
-      (operands_class_id() == kNumberCid)) {
-    // Known/library relational ops that are guaranteed to return Boolean.
-    return kBoolCid;
-  }
-  return kDynamicCid;
-}
-
-
-RawAbstractType* NativeCallInstr::CompileType() const {
-  // The result type of the native function is identical to the result type of
-  // the enclosing native Dart function. However, we prefer to check the type
-  // of the value returned from the native call.
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* StringFromCharCodeInstr::CompileType() const {
-  return Type::StringType();
-}
-
-
-RawAbstractType* LoadIndexedInstr::CompileType() const {
-  switch (class_id_) {
-    case kArrayCid:
-    case kImmutableArrayCid:
-      return Type::DynamicType();
-    case kFloat32ArrayCid :
-    case kFloat64ArrayCid :
-      return Type::Double();
-    case kInt8ArrayCid:
-    case kUint8ArrayCid:
-    case kUint8ClampedArrayCid:
-    case kExternalUint8ArrayCid:
-    case kExternalUint8ClampedArrayCid:
-    case kInt16ArrayCid:
-    case kUint16ArrayCid:
-    case kInt32ArrayCid:
-    case kUint32ArrayCid:
-    case kOneByteStringCid:
-    case kTwoByteStringCid:
-      return Type::IntType();
-    default:
-      UNIMPLEMENTED();
-      return Type::IntType();
-  }
-}
-
-
-RawAbstractType* StoreIndexedInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* StoreInstanceFieldInstr::CompileType() const {
-  return value()->CompileType();
-}
-
-
-RawAbstractType* LoadStaticFieldInstr::CompileType() const {
-  if (FLAG_enable_type_checks) {
-    return field().type();
-  }
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* StoreStaticFieldInstr::CompileType() const {
-  return value()->CompileType();
-}
-
-
-RawAbstractType* BooleanNegateInstr::CompileType() const {
-  return Type::BoolType();
-}
-
-
-RawAbstractType* InstanceOfInstr::CompileType() const {
-  return Type::BoolType();
-}
-
-
-RawAbstractType* CreateArrayInstr::CompileType() const {
-  return type().raw();
-}
-
-
-RawAbstractType* CreateClosureInstr::CompileType() const {
-  const Function& fun = function();
-  const Class& signature_class = Class::Handle(fun.signature_class());
-  return signature_class.SignatureType();
-}
-
-
-RawAbstractType* AllocateObjectInstr::CompileType() const {
-  // TODO(regis): Be more specific.
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* AllocateObjectWithBoundsCheckInstr::CompileType() const {
-  // TODO(regis): Be more specific.
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* LoadFieldInstr::CompileType() const {
-  // Type may be null if the field is a VM field, e.g. context parent.
-  // Keep it as null for debug purposes and do not return dynamic in production
-  // mode, since misuse of the type would remain undetected.
-  if (type().IsNull()) {
-    return AbstractType::null();
-  }
-  if (FLAG_enable_type_checks) {
-    return type().raw();
-  }
-  return Type::DynamicType();
-}
-
-
-RawAbstractType* StoreVMFieldInstr::CompileType() const {
-  return value()->CompileType();
-}
-
-
-RawAbstractType* InstantiateTypeArgumentsInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* ExtractConstructorTypeArgumentsInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* ExtractConstructorInstantiatorInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* AllocateContextInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* ChainContextInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* CloneContextInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* CatchEntryInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* CheckStackOverflowInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* BinarySmiOpInstr::CompileType() const {
-  return Type::SmiType();
-}
-
-
-intptr_t BinarySmiOpInstr::ResultCid() const {
-  return kSmiCid;
-}
-
-
 bool BinarySmiOpInstr::CanDeoptimize() const {
   switch (op_kind()) {
     case Token::kBIT_AND:
@@ -1398,47 +859,6 @@
 }
 
 
-RawAbstractType* BinaryMintOpInstr::CompileType() const {
-  return Type::IntType();
-}
-
-
-intptr_t BinaryMintOpInstr::ResultCid() const {
-  return kDynamicCid;
-}
-
-
-RawAbstractType* ShiftMintOpInstr::CompileType() const {
-  return Type::IntType();
-}
-
-
-intptr_t ShiftMintOpInstr::ResultCid() const {
-  return kDynamicCid;
-}
-
-
-RawAbstractType* UnaryMintOpInstr::CompileType() const {
-  return Type::IntType();
-}
-
-
-intptr_t UnaryMintOpInstr::ResultCid() const {
-  return kDynamicCid;
-}
-
-
-RawAbstractType* BinaryDoubleOpInstr::CompileType() const {
-  return Type::Double();
-}
-
-
-intptr_t BinaryDoubleOpInstr::ResultCid() const {
-  // The output is not an instance but when it is boxed it becomes double.
-  return kDoubleCid;
-}
-
-
 static bool ToIntegerConstant(Value* value, intptr_t* result) {
   if (!value->BindsToConstant()) {
     if (value->definition()->IsUnboxDouble()) {
@@ -1599,96 +1019,6 @@
 }
 
 
-RawAbstractType* MathSqrtInstr::CompileType() const {
-  return Type::Double();
-}
-
-
-RawAbstractType* UnboxDoubleInstr::CompileType() const {
-  return Type::null();
-}
-
-
-intptr_t BoxDoubleInstr::ResultCid() const {
-  return kDoubleCid;
-}
-
-
-RawAbstractType* BoxDoubleInstr::CompileType() const {
-  return Type::Double();
-}
-
-
-intptr_t BoxIntegerInstr::ResultCid() const {
-  return kDynamicCid;
-}
-
-
-RawAbstractType* BoxIntegerInstr::CompileType() const {
-  return Type::IntType();
-}
-
-
-intptr_t UnboxIntegerInstr::ResultCid() const {
-  return kDynamicCid;
-}
-
-
-RawAbstractType* UnboxIntegerInstr::CompileType() const {
-  return Type::null();
-}
-
-
-RawAbstractType* UnarySmiOpInstr::CompileType() const {
-  return Type::SmiType();
-}
-
-
-RawAbstractType* SmiToDoubleInstr::CompileType() const {
-  return Type::Double();
-}
-
-
-RawAbstractType* DoubleToIntegerInstr::CompileType() const {
-  return Type::IntType();
-}
-
-
-RawAbstractType* DoubleToSmiInstr::CompileType() const {
-  return Type::SmiType();
-}
-
-
-RawAbstractType* DoubleToDoubleInstr::CompileType() const {
-  return Type::Double();
-}
-
-
-RawAbstractType* InvokeMathCFunctionInstr::CompileType() const {
-  return Type::Double();
-}
-
-
-RawAbstractType* CheckClassInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* CheckSmiInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* CheckArrayBoundInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
-RawAbstractType* CheckEitherNonSmiInstr::CompileType() const {
-  return AbstractType::null();
-}
-
-
 // Optimizations that eliminate or simplify individual instructions.
 Instruction* Instruction::Canonicalize(FlowGraphOptimizer* optimizer) {
   return this;
@@ -1752,7 +1082,7 @@
   StaticCallInstr* call = value()->definition()->AsStaticCall();
   if (call != NULL &&
       call->is_known_constructor() &&
-      call->ResultCid() == kArrayCid) {
+      (call->Type()->ToCid() == kArrayCid)) {
     return call->ArgumentAt(1)->value()->definition();
   }
   return this;
@@ -1760,33 +1090,18 @@
 
 
 Definition* AssertBooleanInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
-  const intptr_t value_cid = value()->ResultCid();
-  return (value_cid == kBoolCid) ? value()->definition() : this;
+  if (FLAG_eliminate_type_checks && (value()->Type()->ToCid() == kBoolCid)) {
+    return value()->definition();
+  }
+
+  return this;
 }
 
 
 Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
-  // (1) Replace the assert with its input if the input has a known compatible
-  // class-id. The class-ids handled here are those that are known to be
-  // results of IL instructions.
-  intptr_t cid = value()->ResultCid();
-  bool is_redundant = false;
-  if (dst_type().IsIntType()) {
-    is_redundant = (cid == kSmiCid) || (cid == kMintCid);
-  } else if (dst_type().IsDoubleType()) {
-    is_redundant = (cid == kDoubleCid);
-  } else if (dst_type().IsBoolType()) {
-    is_redundant = (cid == kBoolCid);
-  }
-  if (is_redundant) return value()->definition();
-
-  // (2) Replace the assert with its input if the input is the result of a
-  // compatible assert itself.
-  AssertAssignableInstr* check = value()->definition()->AsAssertAssignable();
-  if ((check != NULL) && check->dst_type().Equals(dst_type())) {
-    // TODO(fschneider): Propagate type-assertions across phi-nodes.
-    // TODO(fschneider): Eliminate more asserts with subtype relation.
-    return check;
+  if (FLAG_eliminate_type_checks &&
+      value()->Type()->IsAssignableTo(dst_type())) {
+    return value()->definition();
   }
 
   // (3) For uninstantiated target types: If the instantiator type arguments
@@ -1868,7 +1183,7 @@
   // Handles e === true.
   if ((kind() == Token::kEQ_STRICT) &&
       (right_constant.raw() == Bool::True().raw()) &&
-      (left()->ResultCid() == kBoolCid)) {
+      (left()->Type()->ToCid() == kBoolCid)) {
     // Return left subexpression as the replacement for this instruction.
     return left_defn;
   }
@@ -1877,7 +1192,10 @@
 
 
 Instruction* CheckClassInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
-  const intptr_t value_cid = value()->ResultCid();
+  // TODO(vegorov): Replace class checks with null checks when ToNullableCid
+  // matches.
+
+  const intptr_t value_cid = value()->Type()->ToCid();
   if (value_cid == kDynamicCid) {
     return this;
   }
@@ -1896,14 +1214,14 @@
 
 
 Instruction* CheckSmiInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
-  return (value()->ResultCid() == kSmiCid) ?  NULL : this;
+  return (value()->Type()->ToCid() == kSmiCid) ?  NULL : this;
 }
 
 
 Instruction* CheckEitherNonSmiInstr::Canonicalize(
     FlowGraphOptimizer* optimizer) {
-  if ((left()->ResultCid() == kDoubleCid) ||
-      (right()->ResultCid() == kDoubleCid)) {
+  if ((left()->Type()->ToCid() == kDoubleCid) ||
+      (right()->Type()->ToCid() == kDoubleCid)) {
     return NULL;  // Remove from the graph.
   }
   return this;
@@ -2122,13 +1440,11 @@
 
 
 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  if (!is_eliminated()) {
-    compiler->GenerateAssertAssignable(token_pos(),
-                                       deopt_id(),
-                                       dst_type(),
-                                       dst_name(),
-                                       locs());
-  }
+  compiler->GenerateAssertAssignable(token_pos(),
+                                     deopt_id(),
+                                     dst_type(),
+                                     dst_name(),
+                                     locs());
   ASSERT(locs()->in(0).reg() == locs()->out().reg());
 }
 
@@ -2400,7 +1716,7 @@
 
 
 void Definition::InferRange() {
-  ASSERT(GetPropagatedCid() == kSmiCid);  // Has meaning only for smis.
+  ASSERT(Type()->ToCid() == kSmiCid);  // Has meaning only for smis.
   if (range_ == NULL) {
     range_ = Range::Unknown();
   }
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 1d70a29..7e875e1 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -77,6 +77,121 @@
 };
 
 
+// CompileType describes type of the value produced by the definition.
+//
+// It captures the following properties:
+//    - whether value can potentially be null or it is definitely not null;
+//    - concrete class id of the value or kDynamicCid if unknown statically;
+//    - abstract super type of the value, concrete type of the value in runtime
+//      is guaranteed to be sub type of this type.
+//
+// Values of CompileType form a lattice with a None type as a bottom and a
+// nullable Dynamic type as a top element. Method Union provides a join
+// operation for the lattice.
+class CompileType : public ZoneAllocated {
+ public:
+  static const bool kNullable = true;
+  static const bool kNonNullable = false;
+
+  // Return type such that concrete value's type in runtime is guaranteed to
+  // be subtype of it.
+  const AbstractType* ToAbstractType();
+
+  // Return class id such that it is either kDynamicCid or in runtime
+  // value is guaranteed to have an equal class id.
+  intptr_t ToCid();
+
+  // Return class id such that it is either kDynamicCid or in runtime
+  // value is guaranteed to be either null or have an equal class id.
+  intptr_t ToNullableCid();
+
+  // Returns true if the value is guaranteed to be not-null or is known to be
+  // always null.
+  bool HasDecidableNullability();
+
+  // Returns true if the value is known to be always null.
+  bool IsNull();
+
+  // Returns true if this type is more specific than given type.
+  bool IsMoreSpecificThan(const AbstractType& other);
+
+  // Returns true if value of this type is assignable to a location of the
+  // given type.
+  bool IsAssignableTo(const AbstractType& type) {
+    bool is_instance;
+    return CanComputeIsInstanceOf(type, kNullable, &is_instance) &&
+           is_instance;
+  }
+
+  // Create a new CompileType representing given combination of class id and
+  // abstract type. The pair is assumed to be coherent.
+  static CompileType* New(intptr_t cid, const AbstractType& type);
+
+  // Create a new CompileType representing given abstract type. By default
+  // values as assumed to be nullable.
+  static CompileType* FromAbstractType(const AbstractType& type,
+                                       bool is_nullable = kNullable);
+
+  // Create a new CompileType representing an value with the given class id.
+  // Resulting CompileType is nullable only if cid is kDynamicCid or kNullCid.
+  static CompileType* FromCid(intptr_t cid);
+
+  // Create None CompileType. It is the bottom of the lattice and is used to
+  // represent type of the phi that was not yet inferred.
+  static CompileType* None() {
+    return new CompileType(true, kIllegalCid, NULL);
+  }
+
+  // Create Dynamic CompileType. It is the top of the lattice and is used to
+  // represent unknown type.
+  static CompileType* Dynamic();
+
+  static CompileType* Null();
+
+  // Create non-nullable Bool type.
+  static CompileType* Bool();
+
+  // Create non-nullable Int type.
+  static CompileType* Int();
+
+  // Perform a join operation over the type lattice.
+  void Union(CompileType* other);
+
+  // Returns true if this and other types are the same.
+  bool IsEqualTo(CompileType* other) {
+    return (is_nullable_ == other->is_nullable_) &&
+        (ToNullableCid() == other->ToNullableCid()) &&
+        (ToAbstractType()->Equals(*other->ToAbstractType()));
+  }
+
+  // Replaces this type with other.
+  void ReplaceWith(CompileType* other) {
+    is_nullable_ = other->is_nullable_;
+    cid_ = other->cid_;
+    type_ = other->type_;
+  }
+
+  bool IsNone() const {
+    return (cid_ == kIllegalCid) && (type_ == NULL);
+  }
+
+  void PrintTo(BufferFormatter* f) const;
+  const char* ToCString() const;
+
+ private:
+  CompileType(bool is_nullable, intptr_t cid, const AbstractType* type)
+      : is_nullable_(is_nullable), cid_(cid), type_(type) { }
+
+  bool CanComputeIsInstanceOf(const AbstractType& type,
+                              bool is_nullable,
+                              bool* is_instance);
+
+  bool is_nullable_;
+  intptr_t cid_;
+  const AbstractType* type_;
+};
+
+
 class Value : public ZoneAllocated {
  public:
   // A forward iterator that allows removing the current value from the
@@ -102,7 +217,7 @@
         next_use_(NULL),
         instruction_(NULL),
         use_index_(-1),
-        reaching_cid_(kIllegalCid) { }
+        reaching_type_(NULL) { }
 
   Definition* definition() const { return definition_; }
   void set_definition(Definition* definition) { definition_ = definition; }
@@ -124,8 +239,11 @@
 
   Value* Copy() { return new Value(definition_); }
 
-  RawAbstractType* CompileType() const;
-  intptr_t ResultCid() const;
+  CompileType* Type();
+
+  void SetReachingType(CompileType* type) {
+    reaching_type_ = type;
+  }
 
   void PrintTo(BufferFormatter* f) const;
 
@@ -140,24 +258,12 @@
   // Assert if BindsToConstant() is false, otherwise returns the constant value.
   const Object& BoundConstant() const;
 
-  // Compute a run-time null test at compile-time and set result in is_null.
-  // Return false if the computation is not possible at compile time.
-  bool CanComputeIsNull(bool* is_null) const;
-
-  // Compute a run-time type test at compile-time and set result in is_instance.
-  // Return false if the computation is not possible at compile time.
-  bool CanComputeIsInstanceOf(const AbstractType& type,
-                              bool* is_instance) const;
-
   // Compile time constants, Bool, Smi and Nulls do not need to update
   // the store buffer.
-  bool NeedsStoreBuffer() const;
+  bool NeedsStoreBuffer();
 
   bool Equals(Value* other) const;
 
-  void set_reaching_cid(intptr_t cid) { reaching_cid_ = cid; }
-  intptr_t reaching_cid() const { return reaching_cid_; }
-
  private:
   Definition* definition_;
   Value* previous_use_;
@@ -165,7 +271,7 @@
   Instruction* instruction_;
   intptr_t use_index_;
 
-  intptr_t reaching_cid_;
+  CompileType* reaching_type_;
 
   DISALLOW_COPY_AND_ASSIGN(Value);
 };
@@ -1094,37 +1200,24 @@
 
   // Compile time type of the definition, which may be requested before type
   // propagation during graph building.
-  virtual RawAbstractType* CompileType() const = 0;
-
-  virtual intptr_t ResultCid() const = 0;
-
-  bool HasPropagatedType() const {
-    return !propagated_type_.IsNull();
-  }
-  RawAbstractType* PropagatedType() const {
-    ASSERT(HasPropagatedType());
-    return propagated_type_.raw();
-  }
-  // Returns true if the propagated type has changed.
-  bool SetPropagatedType(const AbstractType& propagated_type) {
-    if (propagated_type.IsNull()) {
-      // Not a typed definition, e.g. access to a VM field.
-      return false;
+  CompileType* Type() {
+    if (type_ == NULL) {
+      type_ = ComputeInitialType();
     }
-    const bool changed =
-        propagated_type_.IsNull() || !propagated_type.Equals(propagated_type_);
-    propagated_type_ = propagated_type.raw();
-    return changed;
+    return type_;
   }
 
-  bool has_propagated_cid() const { return propagated_cid_ != kIllegalCid; }
-  intptr_t propagated_cid() const { return propagated_cid_; }
+  // Compute initial compile type for this definition. It is safe to use this
+  // approximation even before type propagator was run (e.g. during graph
+  // building).
+  virtual CompileType* ComputeInitialType() const {
+    return CompileType::Dynamic();
+  }
 
-  // May compute and set propagated cid.
-  virtual intptr_t GetPropagatedCid();
-
-  // Returns true if the propagated cid has changed.
-  bool SetPropagatedCid(intptr_t cid);
+  // Update CompileType of the definition. Returns true if the type has changed.
+  virtual bool RecomputeType() {
+    return false;
+  }
 
   bool HasUses() const {
     return (input_use_list_ != NULL) || (env_use_list_ != NULL);
@@ -1193,14 +1286,11 @@
   friend class RangeAnalysis;
 
   Range* range_;
+  CompileType* type_;
 
  private:
   intptr_t temp_index_;
   intptr_t ssa_temp_index_;
-  // TODO(regis): GrowableArray<const AbstractType*> propagated_types_;
-  // For now:
-  AbstractType& propagated_type_;
-  intptr_t propagated_cid_;
   Value* input_use_list_;
   Value* env_use_list_;
   UseKind use_kind_;
@@ -1228,8 +1318,8 @@
   virtual BlockEntryInstr* GetBlock() const { return block(); }
   JoinEntryInstr* block() const { return block_; }
 
-  virtual RawAbstractType* CompileType() const;
-  virtual intptr_t GetPropagatedCid();
+  virtual CompileType* ComputeInitialType() const;
+  virtual bool RecomputeType();
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
@@ -1243,9 +1333,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  // TODO(regis): This helper will be removed once we support type sets.
-  RawAbstractType* LeastSpecificInputType() const;
-
   // Phi is alive if it reaches a non-environment use.
   bool is_alive() const { return is_alive_; }
   void mark_alive() { is_alive_ = true; }
@@ -1268,11 +1355,6 @@
     return 0;
   }
 
-  virtual intptr_t ResultCid() const {
-    UNREACHABLE();
-    return kIllegalCid;
-  }
-
   DECLARE_INSTRUCTION(Phi)
 
   virtual void PrintTo(BufferFormatter* f) const;
@@ -1313,12 +1395,6 @@
   // Get the block entry for that instruction.
   virtual BlockEntryInstr* GetBlock() const { return block_; }
 
-  // Compile type of the passed-in parameter.
-  virtual RawAbstractType* CompileType() const;
-
-  // No known propagated cid for parameters.
-  virtual intptr_t GetPropagatedCid();
-
   virtual intptr_t ArgumentCount() const { return 0; }
 
   intptr_t InputCount() const { return 0; }
@@ -1337,13 +1413,10 @@
     return 0;
   }
 
-  virtual intptr_t ResultCid() const {
-    UNREACHABLE();
-    return kIllegalCid;
-  }
-
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
+  virtual CompileType* ComputeInitialType() const;
+
  private:
   const intptr_t index_;
   GraphEntryInstr* block_;
@@ -1373,12 +1446,7 @@
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
-  virtual RawAbstractType* CompileType() const;
-  virtual intptr_t GetPropagatedCid() { return propagated_cid(); }
-  virtual intptr_t ResultCid() const {
-    UNREACHABLE();
-    return kIllegalCid;
-  }
+  virtual CompileType* ComputeInitialType() const;
 
   Value* value() const { return value_; }
 
@@ -1599,7 +1667,6 @@
   }
 
   DECLARE_INSTRUCTION(StoreContext);
-  virtual RawAbstractType* CompileType() const;
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
@@ -1818,16 +1885,12 @@
     return (inputs_[1] == NULL) ? 1 : 2;
   }
 
-  virtual RawAbstractType* CompileType() const {
-    return Type::SmiType();
-  }
+  virtual CompileType* ComputeInitialType() const;
 
   virtual bool CanDeoptimize() const { return false; }
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kSmiCid; }
-
   virtual bool AttributesEqual(Instruction* other) const {
     UNREACHABLE();
     return false;
@@ -1869,7 +1932,7 @@
       : value_(value) { }
 
   DECLARE_INSTRUCTION(Constant)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   const Object& value() const { return value_; }
 
@@ -1879,8 +1942,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const;
-
   virtual bool AttributesEqual(Instruction* other) const;
   virtual bool AffectedBySideEffect() const { return false; }
 
@@ -1903,8 +1964,7 @@
                         const String& dst_name)
       : token_pos_(token_pos),
         dst_type_(AbstractType::ZoneHandle(dst_type.raw())),
-        dst_name_(dst_name),
-        is_eliminated_(false) {
+        dst_name_(dst_name) {
     ASSERT(value != NULL);
     ASSERT(instantiator != NULL);
     ASSERT(instantiator_type_arguments != NULL);
@@ -1916,7 +1976,8 @@
   }
 
   DECLARE_INSTRUCTION(AssertAssignable)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
+  virtual bool RecomputeType();
 
   Value* value() const { return inputs_[0]; }
   Value* instantiator() const { return inputs_[1]; }
@@ -1929,14 +1990,6 @@
   }
   const String& dst_name() const { return dst_name_; }
 
-  bool is_eliminated() const {
-    return is_eliminated_;
-  }
-  void eliminate() {
-    ASSERT(!is_eliminated_);
-    is_eliminated_ = true;
-  }
-
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const { return true; }
@@ -1946,16 +1999,12 @@
   virtual bool AffectedBySideEffect() const { return false; }
   virtual bool AttributesEqual(Instruction* other) const;
 
-  virtual intptr_t ResultCid() const { return value()->ResultCid(); }
-  virtual intptr_t GetPropagatedCid();
-
   virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
 
  private:
   const intptr_t token_pos_;
   AbstractType& dst_type_;
   const String& dst_name_;
-  bool is_eliminated_;
 
   DISALLOW_COPY_AND_ASSIGN(AssertAssignableInstr);
 };
@@ -1964,26 +2013,17 @@
 class AssertBooleanInstr : public TemplateDefinition<1> {
  public:
   AssertBooleanInstr(intptr_t token_pos, Value* value)
-      : token_pos_(token_pos),
-        is_eliminated_(false) {
+      : token_pos_(token_pos) {
     ASSERT(value != NULL);
     inputs_[0] = value;
   }
 
   DECLARE_INSTRUCTION(AssertBoolean)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   intptr_t token_pos() const { return token_pos_; }
   Value* value() const { return inputs_[0]; }
 
-  bool is_eliminated() const {
-    return is_eliminated_;
-  }
-  void eliminate() {
-    ASSERT(!is_eliminated_);
-    is_eliminated_ = true;
-  }
-
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const { return true; }
@@ -1993,13 +2033,10 @@
   virtual bool AffectedBySideEffect() const { return false; }
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
-  virtual intptr_t ResultCid() const { return kBoolCid; }
-
   virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
 
  private:
   const intptr_t token_pos_;
-  bool is_eliminated_;
 
   DISALLOW_COPY_AND_ASSIGN(AssertBooleanInstr);
 };
@@ -2015,7 +2052,7 @@
   }
 
   DECLARE_INSTRUCTION(ArgumentDefinitionTest)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   intptr_t token_pos() const { return ast_node_.token_pos(); }
   intptr_t formal_parameter_index() const {
@@ -2024,6 +2061,7 @@
   const String& formal_parameter_name() const {
     return ast_node_.formal_parameter_name();
   }
+
   Value* saved_arguments_descriptor() const { return inputs_[0]; }
 
   virtual void PrintOperandsTo(BufferFormatter* f) const;
@@ -2032,8 +2070,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kBoolCid; }
-
  private:
   const ArgumentDefinitionTestNode& ast_node_;
 
@@ -2048,14 +2084,12 @@
   CurrentContextInstr() { }
 
   DECLARE_INSTRUCTION(CurrentContext)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual bool CanDeoptimize() const { return false; }
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(CurrentContextInstr);
 };
@@ -2069,7 +2103,6 @@
         arguments_(arguments) { }
 
   DECLARE_INSTRUCTION(ClosureCall)
-  virtual RawAbstractType* CompileType() const;
 
   const Array& argument_names() const { return ast_node_.arguments()->names(); }
   intptr_t token_pos() const { return ast_node_.token_pos(); }
@@ -2085,8 +2118,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const ClosureCallNode& ast_node_;
   ZoneGrowableArray<PushArgumentInstr*>* arguments_;
@@ -2123,7 +2154,6 @@
   }
 
   DECLARE_INSTRUCTION(InstanceCall)
-  virtual RawAbstractType* CompileType() const;
 
   const ICData* ic_data() const { return ic_data_; }
   bool HasICData() const {
@@ -2149,8 +2179,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  protected:
   friend class FlowGraphOptimizer;
   void set_ic_data(ICData* value) { ic_data_ = value; }
@@ -2190,7 +2218,6 @@
   }
 
   DECLARE_INSTRUCTION(PolymorphicInstanceCall)
-  virtual RawAbstractType* CompileType() const;
 
   const ICData& ic_data() const { return ic_data_; }
 
@@ -2198,8 +2225,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
  private:
@@ -2296,7 +2321,7 @@
   StrictCompareInstr(Token::Kind kind, Value* left, Value* right);
 
   DECLARE_INSTRUCTION(StrictCompare)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
@@ -2309,8 +2334,6 @@
 
   virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
 
-  virtual intptr_t ResultCid() const { return kBoolCid; }
-
   virtual void EmitBranchCode(FlowGraphCompiler* compiler,
                               BranchInstr* branch);
 
@@ -2341,7 +2364,7 @@
   }
 
   DECLARE_INSTRUCTION(EqualityCompare)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   const ICData* ic_data() const { return ic_data_; }
   bool HasICData() const {
@@ -2354,20 +2377,21 @@
   void set_receiver_class_id(intptr_t value) { receiver_class_id_ = value; }
   intptr_t receiver_class_id() const { return receiver_class_id_; }
 
+  bool IsInlinedNumericComparison() const {
+    return (receiver_class_id() == kDoubleCid)
+        || (receiver_class_id() == kMintCid)
+        || (receiver_class_id() == kSmiCid);
+  }
+
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const {
-    return (receiver_class_id() != kDoubleCid)
-        && (receiver_class_id() != kMintCid)
-        && (receiver_class_id() != kSmiCid);
-  }
-  virtual bool HasSideEffect() const {
-    return (receiver_class_id() != kDoubleCid)
-        && (receiver_class_id() != kMintCid)
-        && (receiver_class_id() != kSmiCid);
+    return !IsInlinedNumericComparison();
   }
 
-  virtual intptr_t ResultCid() const;
+  virtual bool HasSideEffect() const {
+    return !IsInlinedNumericComparison();
+  }
 
   virtual void EmitBranchCode(FlowGraphCompiler* compiler,
                               BranchInstr* branch);
@@ -2409,7 +2433,7 @@
   }
 
   DECLARE_INSTRUCTION(RelationalOp)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   const ICData* ic_data() const { return ic_data_; }
   bool HasICData() const {
@@ -2426,21 +2450,21 @@
 
   intptr_t operands_class_id() const { return operands_class_id_; }
 
+  bool IsInlinedNumericComparison() const {
+    return (operands_class_id() == kDoubleCid)
+        || (operands_class_id() == kMintCid)
+        || (operands_class_id() == kSmiCid);
+  }
+
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const {
-    return (operands_class_id() != kDoubleCid)
-        && (operands_class_id() != kMintCid)
-        && (operands_class_id() != kSmiCid);
+    return !IsInlinedNumericComparison();
   }
   virtual bool HasSideEffect() const {
-    return (operands_class_id() != kDoubleCid)
-        && (operands_class_id() != kMintCid)
-        && (operands_class_id() != kSmiCid);
+    return !IsInlinedNumericComparison();
   }
 
-  virtual intptr_t ResultCid() const;
-
   virtual void EmitBranchCode(FlowGraphCompiler* compiler,
                               BranchInstr* branch);
 
@@ -2482,7 +2506,7 @@
   }
 
   DECLARE_INSTRUCTION(StaticCall)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   // Accessors forwarded to the AST node.
   const Function& function() const { return function_; }
@@ -2500,7 +2524,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return result_cid_; }
   void set_result_cid(intptr_t value) { result_cid_ = value; }
 
   bool is_known_constructor() const { return is_known_constructor_; }
@@ -2518,7 +2541,6 @@
   // Some library constructors have known semantics.
   bool is_known_constructor_;
 
-
   DISALLOW_COPY_AND_ASSIGN(StaticCallInstr);
 };
 
@@ -2530,7 +2552,7 @@
         context_level_(context_level) { }
 
   DECLARE_INSTRUCTION(LoadLocal)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   const LocalVariable& local() const { return local_; }
   intptr_t context_level() const { return context_level_; }
@@ -2544,8 +2566,6 @@
     return false;
   }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const LocalVariable& local_;
   const intptr_t context_level_;
@@ -2566,7 +2586,7 @@
   }
 
   DECLARE_INSTRUCTION(StoreLocal)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   const LocalVariable& local() const { return local_; }
   Value* value() const { return inputs_[0]; }
@@ -2584,8 +2604,6 @@
     return false;
   }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const LocalVariable& local_;
   const intptr_t context_level_;
@@ -2600,7 +2618,6 @@
       : ast_node_(*node) {}
 
   DECLARE_INSTRUCTION(NativeCall)
-  virtual RawAbstractType* CompileType() const;
 
   intptr_t token_pos() const { return ast_node_.token_pos(); }
 
@@ -2620,8 +2637,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const NativeBodyNode& ast_node_;
 
@@ -2643,7 +2658,7 @@
   }
 
   DECLARE_INSTRUCTION(StoreInstanceField)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   const Field& field() const { return field_; }
 
@@ -2659,8 +2674,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const Field& field_;
   const bool emit_store_barrier_;
@@ -2674,7 +2687,7 @@
   explicit LoadStaticFieldInstr(const Field& field) : field_(field) {}
 
   DECLARE_INSTRUCTION(LoadStaticField);
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   const Field& field() const { return field_; }
 
@@ -2684,8 +2697,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
   virtual bool AffectedBySideEffect() const { return !field().is_final(); }
   virtual bool AttributesEqual(Instruction* other) const;
 
@@ -2706,7 +2717,7 @@
   }
 
   DECLARE_INSTRUCTION(StoreStaticField);
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   const Field& field() const { return field_; }
   Value* value() const { return inputs_[0]; }
@@ -2717,8 +2728,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const Field& field_;
 
@@ -2742,7 +2751,7 @@
   }
 
   DECLARE_INSTRUCTION(LoadIndexed)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   Value* array() const { return inputs_[0]; }
   Value* index() const { return inputs_[1]; }
@@ -2755,8 +2764,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const;
-
   virtual Representation representation() const;
 
   virtual bool AttributesEqual(Instruction* other) const;
@@ -2785,7 +2792,7 @@
   }
 
   DECLARE_INSTRUCTION(StringFromCharCode)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   Value* char_code() const { return inputs_[0]; }
 
@@ -2793,8 +2800,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const {  return cid_; }
-
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
   virtual bool AffectedBySideEffect() const { return false; }
@@ -2826,7 +2831,6 @@
   }
 
   DECLARE_INSTRUCTION(StoreIndexed)
-  virtual RawAbstractType* CompileType() const;
 
   Value* array() const { return inputs_[0]; }
   Value* index() const { return inputs_[1]; }
@@ -2841,8 +2845,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
   virtual Representation RequiredInputRepresentation(intptr_t idx) const;
 
   virtual intptr_t DeoptimizationTarget() const {
@@ -2869,7 +2871,7 @@
   }
 
   DECLARE_INSTRUCTION(BooleanNegate)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   Value* value() const { return inputs_[0]; }
 
@@ -2877,8 +2879,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kBoolCid; }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(BooleanNegateInstr);
 };
@@ -2905,7 +2905,7 @@
   }
 
   DECLARE_INSTRUCTION(InstanceOf)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   Value* value() const { return inputs_[0]; }
   Value* instantiator() const { return inputs_[1]; }
@@ -2921,8 +2921,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kBoolCid; }
-
  private:
   const intptr_t token_pos_;
   Value* value_;
@@ -2947,7 +2945,7 @@
   }
 
   DECLARE_INSTRUCTION(AllocateObject)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual intptr_t ArgumentCount() const { return arguments_->length(); }
   PushArgumentInstr* ArgumentAt(intptr_t index) const {
@@ -2963,8 +2961,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return cid_; }
-
  private:
   const ConstructorCallNode& ast_node_;
   ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
@@ -2987,7 +2983,6 @@
   }
 
   DECLARE_INSTRUCTION(AllocateObjectWithBoundsCheck)
-  virtual RawAbstractType* CompileType() const;
 
   const Function& constructor() const { return ast_node_.constructor(); }
   intptr_t token_pos() const { return ast_node_.token_pos(); }
@@ -2998,8 +2993,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const ConstructorCallNode& ast_node_;
 
@@ -3010,16 +3003,13 @@
 class CreateArrayInstr : public TemplateDefinition<1> {
  public:
   CreateArrayInstr(intptr_t token_pos,
-                   ZoneGrowableArray<PushArgumentInstr*>* arguments,
+                   intptr_t num_elements,
                    const AbstractType& type,
                    Value* element_type)
       : token_pos_(token_pos),
-        arguments_(arguments),
+        num_elements_(num_elements),
         type_(type) {
 #if defined(DEBUG)
-    for (int i = 0; i < ArgumentCount(); ++i) {
-      ASSERT(ArgumentAt(i) != NULL);
-    }
     ASSERT(element_type != NULL);
     ASSERT(type_.IsZoneHandle());
     ASSERT(!type_.IsNull());
@@ -3029,12 +3019,11 @@
   }
 
   DECLARE_INSTRUCTION(CreateArray)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
-  virtual intptr_t ArgumentCount() const { return arguments_->length(); }
+  intptr_t num_elements() const { return num_elements_; }
 
   intptr_t token_pos() const { return token_pos_; }
-  PushArgumentInstr* ArgumentAt(intptr_t i) const { return (*arguments_)[i]; }
   const AbstractType& type() const { return type_; }
   Value* element_type() const { return inputs_[0]; }
 
@@ -3044,11 +3033,9 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kArrayCid; }
-
  private:
   const intptr_t token_pos_;
-  ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
+  const intptr_t num_elements_;
   const AbstractType& type_;
 
   DISALLOW_COPY_AND_ASSIGN(CreateArrayInstr);
@@ -3065,7 +3052,7 @@
         token_pos_(token_pos) { }
 
   DECLARE_INSTRUCTION(CreateClosure)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   intptr_t token_pos() const { return token_pos_; }
   const Function& function() const { return function_; }
@@ -3081,8 +3068,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const Function& function_;
   ZoneGrowableArray<PushArgumentInstr*>* arguments_;
@@ -3109,7 +3094,7 @@
   }
 
   DECLARE_INSTRUCTION(LoadField)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   Value* value() const { return inputs_[0]; }
   intptr_t offset_in_bytes() const { return offset_in_bytes_; }
@@ -3122,8 +3107,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return result_cid_; }
-
   virtual bool AttributesEqual(Instruction* other) const;
 
   virtual bool AffectedBySideEffect() const { return !immutable_; }
@@ -3171,7 +3154,7 @@
   }
 
   DECLARE_INSTRUCTION(StoreVMField)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   Value* value() const { return inputs_[0]; }
   Value* dest() const { return inputs_[1]; }
@@ -3184,8 +3167,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const intptr_t offset_in_bytes_;
   const AbstractType& type_;
@@ -3207,7 +3188,6 @@
   }
 
   DECLARE_INSTRUCTION(InstantiateTypeArguments)
-  virtual RawAbstractType* CompileType() const;
 
   Value* instantiator() const { return inputs_[0]; }
   const AbstractTypeArguments& type_arguments() const {
@@ -3221,8 +3201,6 @@
 
   virtual bool HasSideEffect() const { return true; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const intptr_t token_pos_;
   const AbstractTypeArguments& type_arguments_;
@@ -3244,7 +3222,6 @@
   }
 
   DECLARE_INSTRUCTION(ExtractConstructorTypeArguments)
-  virtual RawAbstractType* CompileType() const;
 
   Value* instantiator() const { return inputs_[0]; }
   const AbstractTypeArguments& type_arguments() const {
@@ -3258,8 +3235,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const intptr_t token_pos_;
   const AbstractTypeArguments& type_arguments_;
@@ -3278,7 +3253,6 @@
   }
 
   DECLARE_INSTRUCTION(ExtractConstructorInstantiator)
-  virtual RawAbstractType* CompileType() const;
 
   Value* instantiator() const { return inputs_[0]; }
   const AbstractTypeArguments& type_arguments() const {
@@ -3291,8 +3265,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const ConstructorCallNode& ast_node_;
 
@@ -3308,7 +3280,7 @@
         num_context_variables_(num_context_variables) {}
 
   DECLARE_INSTRUCTION(AllocateContext);
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   intptr_t token_pos() const { return token_pos_; }
   intptr_t num_context_variables() const { return num_context_variables_; }
@@ -3319,8 +3291,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   const intptr_t token_pos_;
   const intptr_t num_context_variables_;
@@ -3337,7 +3307,6 @@
   }
 
   DECLARE_INSTRUCTION(ChainContext)
-  virtual RawAbstractType* CompileType() const;
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
@@ -3364,14 +3333,12 @@
   Value* context_value() const { return inputs_[0]; }
 
   DECLARE_INSTRUCTION(CloneContext)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual bool CanDeoptimize() const { return true; }
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kContextCid; }
-
  private:
   const intptr_t token_pos_;
 
@@ -3389,7 +3356,6 @@
   const LocalVariable& stacktrace_var() const { return stacktrace_var_; }
 
   DECLARE_INSTRUCTION(CatchEntry)
-  virtual RawAbstractType* CompileType() const;
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
@@ -3420,7 +3386,6 @@
   }
 
   DECLARE_INSTRUCTION(CheckEitherNonSmi)
-  virtual RawAbstractType* CompileType() const;
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
@@ -3462,15 +3427,13 @@
   virtual bool AffectedBySideEffect() const { return false; }
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
-  virtual intptr_t ResultCid() const;
-
   virtual Representation RequiredInputRepresentation(intptr_t idx) const {
     ASSERT(idx == 0);
     return kUnboxedDouble;
   }
 
   DECLARE_INSTRUCTION(BoxDouble)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
  private:
   const intptr_t token_pos_;
@@ -3495,15 +3458,13 @@
   virtual bool AffectedBySideEffect() const { return false; }
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
-  virtual intptr_t ResultCid() const;
-
   virtual Representation RequiredInputRepresentation(intptr_t idx) const {
     ASSERT(idx == 0);
     return kUnboxedMint;
   }
 
   DECLARE_INSTRUCTION(BoxInteger)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(BoxIntegerInstr);
@@ -3521,15 +3482,12 @@
   Value* value() const { return inputs_[0]; }
 
   virtual bool CanDeoptimize() const {
-    return (value()->ResultCid() != kDoubleCid)
-        && (value()->ResultCid() != kSmiCid);
+    return (value()->Type()->ToCid() != kDoubleCid)
+        && (value()->Type()->ToCid() != kSmiCid);
   }
 
   virtual bool HasSideEffect() const { return false; }
 
-  // The output is not an instance but when it is boxed it becomes double.
-  virtual intptr_t ResultCid() const { return kDoubleCid; }
-
   virtual Representation representation() const {
     return kUnboxedDouble;
   }
@@ -3538,7 +3496,7 @@
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
   DECLARE_INSTRUCTION(UnboxDouble)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(UnboxDoubleInstr);
@@ -3556,15 +3514,13 @@
   Value* value() const { return inputs_[0]; }
 
   virtual bool CanDeoptimize() const {
-    return (value()->ResultCid() != kMintCid)
-        && (value()->ResultCid() != kSmiCid);
+    return (value()->Type()->ToCid() != kSmiCid)
+        && (value()->Type()->ToCid() != kMintCid);
   }
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const;
-
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual Representation representation() const {
     return kUnboxedMint;
@@ -3599,9 +3555,6 @@
     return true;
   }
 
-  // The output is not an instance but when it is boxed it becomes double.
-  virtual intptr_t ResultCid() const { return kDoubleCid; }
-
   virtual Representation representation() const {
     return kUnboxedDouble;
   }
@@ -3618,7 +3571,7 @@
   }
 
   DECLARE_INSTRUCTION(MathSqrt)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MathSqrtInstr);
@@ -3656,8 +3609,6 @@
     return op_kind() == other->AsBinaryDoubleOp()->op_kind();
   }
 
-  virtual intptr_t ResultCid() const;
-
   virtual Representation representation() const {
     return kUnboxedDouble;
   }
@@ -3674,7 +3625,7 @@
   }
 
   DECLARE_INSTRUCTION(BinaryDoubleOp)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
 
@@ -3718,8 +3669,7 @@
     return op_kind() == other->AsBinaryMintOp()->op_kind();
   }
 
-  virtual intptr_t ResultCid() const;
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual Representation representation() const {
     return kUnboxedMint;
@@ -3779,8 +3729,7 @@
     return op_kind() == other->AsShiftMintOp()->op_kind();
   }
 
-  virtual intptr_t ResultCid() const;
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual Representation representation() const {
     return kUnboxedMint;
@@ -3834,8 +3783,7 @@
     return op_kind() == other->AsUnaryMintOp()->op_kind();
   }
 
-  virtual intptr_t ResultCid() const;
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual Representation representation() const {
     return kUnboxedMint;
@@ -3890,7 +3838,7 @@
 
   DECLARE_INSTRUCTION(BinarySmiOp)
 
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual bool CanDeoptimize() const;
 
@@ -3899,8 +3847,6 @@
   virtual bool AffectedBySideEffect() const { return false; }
   virtual bool AttributesEqual(Instruction* other) const;
 
-  virtual intptr_t ResultCid() const;
-
   void set_overflow(bool overflow) {
     overflow_ = overflow;
   }
@@ -3943,14 +3889,12 @@
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   DECLARE_INSTRUCTION(UnarySmiOp)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual bool CanDeoptimize() const { return op_kind() == Token::kNEGATE; }
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kSmiCid; }
-
  private:
   const Token::Kind op_kind_;
 
@@ -3966,7 +3910,6 @@
   intptr_t token_pos() const { return token_pos_; }
 
   DECLARE_INSTRUCTION(CheckStackOverflow)
-  virtual RawAbstractType* CompileType() const;
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
@@ -3989,7 +3932,7 @@
   InstanceCallInstr* instance_call() const { return instance_call_; }
 
   DECLARE_INSTRUCTION(SmiToDouble)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual intptr_t ArgumentCount() const { return 1; }
 
@@ -3997,8 +3940,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kDoubleCid; }
-
  private:
   InstanceCallInstr* instance_call_;
 
@@ -4018,7 +3959,7 @@
   InstanceCallInstr* instance_call() const { return instance_call_; }
 
   DECLARE_INSTRUCTION(DoubleToInteger)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual intptr_t ArgumentCount() const { return 1; }
 
@@ -4026,9 +3967,6 @@
 
   virtual bool HasSideEffect() const { return false; }
 
-  // Result could be any of the int types.
-  virtual intptr_t ResultCid() const { return kDynamicCid; }
-
  private:
   InstanceCallInstr* instance_call_;
 
@@ -4049,14 +3987,12 @@
   Value* value() const { return inputs_[0]; }
 
   DECLARE_INSTRUCTION(DoubleToSmi)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual bool CanDeoptimize() const { return true; }
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kSmiCid; }
-
   virtual Representation RequiredInputRepresentation(intptr_t idx) const {
     ASSERT(idx == 0);
     return kUnboxedDouble;
@@ -4085,14 +4021,12 @@
   MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
 
   DECLARE_INSTRUCTION(DoubleToDouble)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
 
   virtual bool CanDeoptimize() const { return false; }
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kDoubleCid; }
-
   virtual Representation representation() const {
     return kUnboxedDouble;
   }
@@ -4128,15 +4062,13 @@
   MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
 
   DECLARE_INSTRUCTION(InvokeMathCFunction)
-  virtual RawAbstractType* CompileType() const;
+  virtual CompileType* ComputeInitialType() const;
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const { return false; }
 
   virtual bool HasSideEffect() const { return false; }
 
-  virtual intptr_t ResultCid() const { return kDoubleCid; }
-
   virtual Representation representation() const {
     return kUnboxedDouble;
   }
@@ -4188,7 +4120,6 @@
                   const ICData& unary_checks);
 
   DECLARE_INSTRUCTION(CheckClass)
-  virtual RawAbstractType* CompileType() const;
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
@@ -4225,7 +4156,6 @@
   }
 
   DECLARE_INSTRUCTION(CheckSmi)
-  virtual RawAbstractType* CompileType() const;
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
@@ -4261,7 +4191,6 @@
   }
 
   DECLARE_INSTRUCTION(CheckArrayBound)
-  virtual RawAbstractType* CompileType() const;
 
   virtual intptr_t ArgumentCount() const { return 0; }
 
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 176e4a4..2e3f226 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -172,9 +172,9 @@
 }
 
 
-intptr_t LoadIndexedInstr::ResultCid() const {
+CompileType* LoadIndexedInstr::ComputeInitialType() const {
   UNIMPLEMENTED();
-  return kDynamicCid;
+  return NULL;
 }
 
 
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 0787527..a475fd6 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -212,9 +212,7 @@
   Register obj = locs()->in(0).reg();
   Register result = locs()->out().reg();
 
-  if (!is_eliminated()) {
-    EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
-  }
+  EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
   ASSERT(obj == result);
 }
 
@@ -1097,14 +1095,16 @@
 }
 
 
-intptr_t LoadIndexedInstr::ResultCid() const {
+CompileType* LoadIndexedInstr::ComputeInitialType() const {
   switch (class_id_) {
     case kArrayCid:
     case kImmutableArrayCid:
-      return kDynamicCid;
+      return CompileType::Dynamic();
+
     case kFloat32ArrayCid :
     case kFloat64ArrayCid :
-      return kDoubleCid;
+      return CompileType::FromCid(kDoubleCid);
+
     case kInt8ArrayCid:
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
@@ -1114,16 +1114,19 @@
     case kUint16ArrayCid:
     case kOneByteStringCid:
     case kTwoByteStringCid:
-      return kSmiCid;
+      return CompileType::FromCid(kSmiCid);
+
     case kInt32ArrayCid:
     case kUint32ArrayCid:
       // Result can be Smi or Mint when boxed.
       // Instruction can deoptimize if we optimistically assumed that the result
       // fits into Smi.
-      return CanDeoptimize() ? kSmiCid : kDynamicCid;
+      return CanDeoptimize() ? CompileType::FromCid(kSmiCid)
+                             : CompileType::Int();
+
     default:
       UNIMPLEMENTED();
-      return kDynamicCid;
+      return CompileType::Dynamic();
   }
 }
 
@@ -1163,12 +1166,19 @@
   LocationSummary* locs =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
   locs->set_in(0, Location::RequiresRegister());
-  // The smi index is either untagged and tagged again at the end of the
-  // operation (element size == 1), or it is left smi tagged (for all element
-  // sizes > 1).
-  locs->set_in(1, CanBeImmediateIndex(index(), class_id())
-                    ? Location::RegisterOrSmiConstant(index())
-                    : Location::RequiresRegister());
+  // The smi index is either untagged (element size == 1), or it is left smi
+  // tagged (for all element sizes > 1).
+  if (index_scale() == 1) {
+    locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+                      ? Location::Constant(
+                          index()->definition()->AsConstant()->value())
+                      : Location::WritableRegister());
+  } else {
+    locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+                      ? Location::Constant(
+                          index()->definition()->AsConstant()->value())
+                      : Location::RequiresRegister());
+  }
   if (representation() == kUnboxedDouble) {
     locs->set_out(Location::RequiresFpuRegister());
   } else {
@@ -1199,9 +1209,6 @@
             FieldAddress(array, ExternalUint8Array::data_offset()));
     __ movzxb(result, element_address);
     __ SmiTag(result);
-    if (index.IsRegister()) {
-      __ SmiTag(index.reg());  // Re-tag.
-    }
     return;
   }
 
@@ -1236,9 +1243,6 @@
         __ movsd(result, element_address);
         break;
     }
-    if ((index_scale() == 1) && index.IsRegister()) {
-        __ SmiTag(index.reg());  // Re-tag.
-    }
     return;
   }
 
@@ -1291,9 +1295,6 @@
       __ movl(result, element_address);
       break;
   }
-  if ((index_scale() == 1) && index.IsRegister()) {
-      __ SmiTag(index.reg());  // Re-tag.
-  }
 }
 
 
@@ -1305,7 +1306,9 @@
     case kArrayCid:
     case kInt8ArrayCid:
     case kUint8ArrayCid:
+    case kExternalUint8ArrayCid:
     case kUint8ClampedArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
       return kTagged;
@@ -1328,18 +1331,31 @@
   LocationSummary* locs =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
   locs->set_in(0, Location::RequiresRegister());
-  // The smi index is either untagged and tagged again at the end of the
-  // operation (element size == 1), or it is left smi tagged (for all element
-  // sizes > 1).
-  locs->set_in(1, CanBeImmediateIndex(index(), class_id())
-                    ? Location::RegisterOrSmiConstant(index())
-                    : Location::RequiresRegister());
+  // The smi index is either untagged (element size == 1), or it is left smi
+  // tagged (for all element sizes > 1).
+  intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id());
+  if (index_scale == 1) {
+    locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+                      ? Location::Constant(
+                          index()->definition()->AsConstant()->value())
+                      : Location::WritableRegister());
+  } else {
+    locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+                      ? Location::Constant(
+                          index()->definition()->AsConstant()->value())
+                      : Location::RequiresRegister());
+  }
   switch (class_id()) {
     case kArrayCid:
       locs->set_in(2, ShouldEmitStoreBarrier()
                         ? Location::WritableRegister()
                         : Location::RegisterOrConstant(value()));
       break;
+    case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
+      // Need temp register to load the external array's data array.
+      locs->AddTemp(Location::RequiresRegister());
+      // Fall through.
     case kInt8ArrayCid:
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
@@ -1376,11 +1392,25 @@
 
   intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id());
 
-  FieldAddress element_address = index.IsRegister() ?
-      FlowGraphCompiler::ElementAddressForRegIndex(
-          class_id(), index_scale, array, index.reg()) :
-      FlowGraphCompiler::ElementAddressForIntIndex(
+  Address element_address(kNoRegister, 0);
+  if ((class_id() == kExternalUint8ArrayCid) ||
+      (class_id() == kExternalUint8ClampedArrayCid)) {
+    Register temp = locs()->temp(0).reg();
+    element_address = index.IsRegister()
+        ? FlowGraphCompiler::ExternalElementAddressForRegIndex(
+            class_id(), index_scale, temp, index.reg())
+        : FlowGraphCompiler::ExternalElementAddressForIntIndex(
+            class_id(), index_scale, temp,
+            Smi::Cast(index.constant()).Value());
+    __ movl(temp,
+            FieldAddress(array, ExternalUint8Array::data_offset()));
+  } else {
+    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:
@@ -1397,6 +1427,7 @@
       break;
     case kInt8ArrayCid:
     case kUint8ArrayCid:
+    case kExternalUint8ArrayCid:
       if (index.IsRegister()) {
         __ SmiUntag(index.reg());
       }
@@ -1409,11 +1440,9 @@
         __ SmiUntag(EAX);
         __ movb(element_address, AL);
       }
-      if (index.IsRegister()) {
-        __ SmiTag(index.reg());  // Re-tag.
-      }
       break;
-    case kUint8ClampedArrayCid: {
+    case kUint8ClampedArrayCid:
+    case kExternalUint8ClampedArrayCid: {
       if (index.IsRegister()) {
         __ SmiUntag(index.reg());
       }
@@ -1443,9 +1472,6 @@
         __ Bind(&store_value);
         __ movb(element_address, AL);
       }
-      if (index.IsRegister()) {
-        __ SmiTag(index.reg());  // Re-tag.
-      }
       break;
     }
     case kInt16ArrayCid:
@@ -1586,18 +1612,12 @@
 void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // Allocate the array.  EDX = length, ECX = element type.
   ASSERT(locs()->in(0).reg() == ECX);
-  __ movl(EDX, Immediate(Smi::RawValue(ArgumentCount())));
+  __ movl(EDX, Immediate(Smi::RawValue(num_elements())));
   compiler->GenerateCall(token_pos(),
                          &StubCode::AllocateArrayLabel(),
                          PcDescriptors::kOther,
                          locs());
   ASSERT(locs()->out().reg() == EAX);
-
-  // Pop the element values from the stack into the array.
-  __ leal(EDX, FieldAddress(EAX, Array::data_offset()));
-  for (int i = ArgumentCount() - 1; i >= 0; --i) {
-    __ popl(Address(EDX, i * kWordSize));
-  }
 }
 
 
@@ -2219,10 +2239,38 @@
       break;
     }
     case Token::kSHL: {
+      Range* right_range = this->right()->definition()->range();
+      if (this->left()->BindsToConstant()) {
+        // If left is constant, we know the maximal allowed size for right.
+        const Object& obj = this->left()->BoundConstant();
+        if (obj.IsSmi()) {
+          const intptr_t left_int = Smi::Cast(obj).Value();
+          if (left_int == 0) {
+            __ cmpl(right, Immediate(0));
+            __ j(NEGATIVE, deopt);
+            break;
+          }
+          intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
+          intptr_t max_right = kSmiBits;
+          while ((tmp >>= 1) != 0) {
+            max_right--;
+          }
+          const bool right_needs_check =
+              (right_range == NULL) ||
+              !right_range->IsWithin(0, max_right - 1);
+          if (right_needs_check) {
+            __ cmpl(right,
+              Immediate(reinterpret_cast<int32_t>(Smi::New(max_right))));
+            __ j(ABOVE_EQUAL, deopt);
+          }
+          __ SmiUntag(right);
+          __ shll(left, right);
+          break;
+        }
+      }
       Register temp = locs()->temp(0).reg();
       // Check if count too large for handling it inlined.
       __ movl(temp, left);
-      Range* right_range = this->right()->definition()->range();
       const bool right_needs_check =
           (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
       if (right_needs_check) {
@@ -2267,8 +2315,8 @@
 
 
 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
-  ASSERT((left()->ResultCid() != kDoubleCid) &&
-         (right()->ResultCid() != kDoubleCid));
+  ASSERT((left()->Type()->ToCid() != kDoubleCid) &&
+         (right()->Type()->ToCid() != kDoubleCid));
   const intptr_t kNumInputs = 2;
   const intptr_t kNumTemps = 1;
   LocationSummary* summary =
@@ -2354,18 +2402,23 @@
 
 LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0;
+  const intptr_t value_cid = value()->Type()->ToCid();
+  const bool needs_temp = ((value_cid != kSmiCid) && (value_cid != kDoubleCid));
+  const bool needs_writable_input = (value_cid == kSmiCid);
+  const intptr_t kNumTemps = needs_temp ? 1 : 0;
   LocationSummary* summary =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresRegister());
-  if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister());
+  summary->set_in(0, needs_writable_input
+                     ? Location::WritableRegister()
+                     : Location::RequiresRegister());
+  if (needs_temp) summary->set_temp(0, Location::RequiresRegister());
   summary->set_out(Location::RequiresFpuRegister());
   return summary;
 }
 
 
 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  const intptr_t value_cid = value()->ResultCid();
+  const intptr_t value_cid = value()->Type()->ToCid();
   const Register value = locs()->in(0).reg();
   const XmmRegister result = locs()->out().fpu_reg();
 
@@ -2374,13 +2427,21 @@
   } else if (value_cid == kSmiCid) {
     __ SmiUntag(value);  // Untag input before conversion.
     __ cvtsi2sd(result, value);
-    __ SmiTag(value);  // Restore input register.
   } else {
     Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp);
-    compiler->LoadDoubleOrSmiToFpu(result,
-                                   value,
-                                   locs()->temp(0).reg(),
-                                   deopt);
+    Register temp = locs()->temp(0).reg();
+    Label is_smi, done;
+    __ testl(value, Immediate(kSmiTagMask));
+    __ j(ZERO, &is_smi);
+    __ CompareClassId(value, kDoubleCid, temp);
+    __ j(NOT_EQUAL, deopt);
+    __ movsd(result, FieldAddress(value, Double::value_offset()));
+    __ jmp(&done);
+    __ Bind(&is_smi);
+    __ movl(temp, value);
+    __ SmiUntag(temp);
+    __ cvtsi2sd(result, temp);
+    __ Bind(&done);
   }
 }
 
@@ -2753,8 +2814,6 @@
 
 
 void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  // TODO(srdjan): Check if we can remove this by reordering CSE and LICM.
-  if (value()->ResultCid() == kSmiCid) return;
   Register value = locs()->in(0).reg();
   Label* deopt = compiler->AddDeoptStub(deopt_id(),
                                         kDeoptCheckSmi);
@@ -2809,18 +2868,23 @@
 
 LocationSummary* UnboxIntegerInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0;
+  const intptr_t value_cid = value()->Type()->ToCid();
+  const bool needs_temp = ((value_cid != kSmiCid) && (value_cid != kMintCid));
+  const bool needs_writable_input = (value_cid == kSmiCid);
+  const intptr_t kNumTemps = needs_temp ? 1 : 0;
   LocationSummary* summary =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresRegister());
-  if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister());
+  summary->set_in(0, needs_writable_input
+                     ? Location::WritableRegister()
+                     : Location::RequiresRegister());
+  if (needs_temp) summary->set_temp(0, Location::RequiresRegister());
   summary->set_out(Location::RequiresFpuRegister());
   return summary;
 }
 
 
 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  const intptr_t value_cid = value()->ResultCid();
+  const intptr_t value_cid = value()->Type()->ToCid();
   const Register value = locs()->in(0).reg();
   const XmmRegister result = locs()->out().fpu_reg();
 
@@ -2830,7 +2894,6 @@
     __ SmiUntag(value);  // Untag input before conversion.
     __ movd(result, value);
     __ pmovsxdq(result, result);
-    __ SmiTag(value);  // Restore input register.
   } else {
     Register temp = locs()->temp(0).reg();
     Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptUnboxInteger);
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 77bd6a2..2ec2dc6 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -172,9 +172,9 @@
 }
 
 
-intptr_t LoadIndexedInstr::ResultCid() const {
+CompileType* LoadIndexedInstr::ComputeInitialType() const {
   UNIMPLEMENTED();
-  return kDynamicCid;
+  return NULL;
 }
 
 
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index c0e93f9..41b82f9 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -219,9 +219,7 @@
   Register obj = locs()->in(0).reg();
   Register result = locs()->out().reg();
 
-  if (!is_eliminated()) {
-    EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
-  }
+  EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
   ASSERT(obj == result);
 }
 
@@ -961,14 +959,16 @@
 }
 
 
-intptr_t LoadIndexedInstr::ResultCid() const {
+CompileType* LoadIndexedInstr::ComputeInitialType() const {
   switch (class_id_) {
     case kArrayCid:
     case kImmutableArrayCid:
-      return kDynamicCid;
+      return CompileType::Dynamic();
+
     case kFloat32ArrayCid :
     case kFloat64ArrayCid :
-      return kDoubleCid;
+      return CompileType::FromCid(kDoubleCid);
+
     case kInt8ArrayCid:
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
@@ -980,10 +980,11 @@
     case kTwoByteStringCid:
     case kInt32ArrayCid:
     case kUint32ArrayCid:
-      return kSmiCid;
+      return CompileType::FromCid(kSmiCid);
+
     default:
       UNIMPLEMENTED();
-      return kSmiCid;
+      return NULL;
   }
 }
 
@@ -1020,12 +1021,19 @@
   LocationSummary* locs =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
   locs->set_in(0, Location::RequiresRegister());
-  // The smi index is either untagged and tagged again at the end of the
-  // operation (element size == 1), or it is left smi tagged (for all element
-  // sizes > 1).
-  locs->set_in(1, CanBeImmediateIndex(index(), class_id())
-                    ? Location::RegisterOrSmiConstant(index())
-                    : Location::RequiresRegister());
+  // The smi index is either untagged (element size == 1), or it is left smi
+  // tagged (for all element sizes > 1).
+  if (index_scale() == 1) {
+    locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+                      ? Location::Constant(
+                          index()->definition()->AsConstant()->value())
+                      : Location::WritableRegister());
+  } else {
+    locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+                      ? Location::Constant(
+                          index()->definition()->AsConstant()->value())
+                      : Location::RequiresRegister());
+  }
   if (representation() == kUnboxedDouble) {
     locs->set_out(Location::RequiresFpuRegister());
   } else {
@@ -1056,9 +1064,6 @@
             FieldAddress(array, ExternalUint8Array::data_offset()));
     __ movzxb(result, element_address);
     __ SmiTag(result);
-    if (index.IsRegister()) {
-      __ SmiTag(index.reg());  // Re-tag.
-    }
     return;
   }
 
@@ -1084,10 +1089,6 @@
       ASSERT(class_id() == kFloat64ArrayCid);
       __ movsd(result, element_address);
     }
-
-    if ((index_scale() == 1) && index.IsRegister()) {
-        __ SmiTag(index.reg());  // Re-tag.
-    }
     return;
   }
 
@@ -1129,9 +1130,6 @@
       __ movq(result, element_address);
       break;
   }
-  if ((index_scale() == 1) && index.IsRegister()) {
-      __ SmiTag(index.reg());  // Re-tag.
-  }
 }
 
 
@@ -1143,7 +1141,9 @@
     case kArrayCid:
     case kInt8ArrayCid:
     case kUint8ArrayCid:
+    case kExternalUint8ArrayCid:
     case kUint8ClampedArrayCid:
+    case kExternalUint8ClampedArrayCid:
     case kInt16ArrayCid:
     case kUint16ArrayCid:
     case kInt32ArrayCid:
@@ -1164,19 +1164,32 @@
   const intptr_t kNumTemps = 0;
   LocationSummary* locs =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  // The smi index is either untagged and tagged again at the end of the
-  // operation (element size == 1), or it is left smi tagged (for all element
-  // sizes > 1).
   locs->set_in(0, Location::RequiresRegister());
-  locs->set_in(1, CanBeImmediateIndex(index(), class_id())
-                    ? Location::RegisterOrSmiConstant(index())
-                    : Location::RequiresRegister());
+  // The smi index is either untagged (element size == 1), or it is left smi
+  // tagged (for all element sizes > 1).
+  intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id());
+  if (index_scale == 1) {
+    locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+                      ? Location::Constant(
+                          index()->definition()->AsConstant()->value())
+                      : Location::WritableRegister());
+  } else {
+    locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+                      ? Location::Constant(
+                          index()->definition()->AsConstant()->value())
+                      : Location::RequiresRegister());
+  }
   switch (class_id()) {
     case kArrayCid:
       locs->set_in(2, ShouldEmitStoreBarrier()
                         ? Location::WritableRegister()
                         : Location::RegisterOrConstant(value()));
       break;
+    case kExternalUint8ArrayCid:
+    case kExternalUint8ClampedArrayCid:
+      // Need temp register to load the external array's data array.
+      locs->AddTemp(Location::RequiresRegister());
+      // Fall through.
     case kInt8ArrayCid:
     case kUint8ArrayCid:
     case kUint8ClampedArrayCid:
@@ -1212,13 +1225,26 @@
   Location index = locs()->in(1);
 
   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());
+  Address element_address(kNoRegister, 0);
+  if ((class_id() == kExternalUint8ArrayCid) ||
+      (class_id() == kExternalUint8ClampedArrayCid)) {
+    Register temp = locs()->temp(0).reg();
+    element_address = index.IsRegister()
+        ? FlowGraphCompiler::ExternalElementAddressForRegIndex(
+            class_id(), index_scale, temp, index.reg())
+        : FlowGraphCompiler::ExternalElementAddressForIntIndex(
+            class_id(), index_scale, temp,
+            Smi::Cast(index.constant()).Value());
+    __ movq(temp,
+            FieldAddress(array, ExternalUint8Array::data_offset()));
+  } else {
+    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:
@@ -1235,6 +1261,7 @@
       break;
     case kInt8ArrayCid:
     case kUint8ArrayCid:
+    case kExternalUint8ArrayCid:
       if (index.IsRegister()) {
         __ SmiUntag(index.reg());
       }
@@ -1247,11 +1274,9 @@
         __ SmiUntag(RAX);
         __ movb(element_address, RAX);
       }
-      if (index.IsRegister()) {
-        __ SmiTag(index.reg());  // Re-tag.
-      }
       break;
-    case kUint8ClampedArrayCid: {
+    case kUint8ClampedArrayCid:
+    case kExternalUint8ClampedArrayCid: {
       if (index.IsRegister()) {
         __ SmiUntag(index.reg());
       }
@@ -1281,9 +1306,6 @@
         __ Bind(&store_value);
         __ movb(element_address, RAX);
       }
-      if (index.IsRegister()) {
-        __ SmiTag(index.reg());  // Re-tag.
-      }
       break;
     }
     case kInt16ArrayCid:
@@ -1425,18 +1447,12 @@
 void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // Allocate the array.  R10 = length, RBX = element type.
   ASSERT(locs()->in(0).reg() == RBX);
-  __ movq(R10, Immediate(Smi::RawValue(ArgumentCount())));
+  __ movq(R10, Immediate(Smi::RawValue(num_elements())));
   compiler->GenerateCall(token_pos(),
                          &StubCode::AllocateArrayLabel(),
                          PcDescriptors::kOther,
                          locs());
   ASSERT(locs()->out().reg() == RAX);
-
-  // Pop the element values from the stack into the array.
-  __ leaq(R10, FieldAddress(RAX, Array::data_offset()));
-  for (int i = ArgumentCount() - 1; i >= 0; --i) {
-    __ popq(Address(R10, i * kWordSize));
-  }
 }
 
 
@@ -2079,10 +2095,38 @@
       break;
     }
     case Token::kSHL: {
+      Range* right_range = this->right()->definition()->range();
+      if (this->left()->BindsToConstant()) {
+        // If left is constant, we know the maximal allowed size for right.
+        const Object& obj = this->left()->BoundConstant();
+        if (obj.IsSmi()) {
+          const intptr_t left_int = Smi::Cast(obj).Value();
+          if (left_int == 0) {
+            __ cmpq(right, Immediate(0));
+            __ j(NEGATIVE, deopt);
+            break;
+          }
+          intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
+          intptr_t max_right = kSmiBits;
+          while ((tmp >>= 1) != 0) {
+            max_right--;
+          }
+          const bool right_needs_check =
+              (right_range == NULL) ||
+              !right_range->IsWithin(0, max_right - 1);
+          if (right_needs_check) {
+            __ cmpq(right,
+              Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
+            __ j(ABOVE_EQUAL, deopt);
+          }
+          __ SmiUntag(right);
+          __ shlq(left, right);
+          break;
+        }
+      }
       Register temp = locs()->temp(0).reg();
       // Check if count too large for handling it inlined.
       __ movq(temp, left);
-      Range* right_range = this->right()->definition()->range();
       const bool right_needs_check =
           (right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
       if (right_needs_check) {
@@ -2127,8 +2171,8 @@
 
 
 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
-  ASSERT((left()->ResultCid() != kDoubleCid) &&
-         (right()->ResultCid() != kDoubleCid));
+  ASSERT((left()->Type()->ToCid() != kDoubleCid) &&
+         (right()->Type()->ToCid() != kDoubleCid));
   const intptr_t kNumInputs = 2;
   const intptr_t kNumTemps = 1;
   LocationSummary* summary =
@@ -2214,18 +2258,20 @@
 
 LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0;
+  const intptr_t kNumTemps = 0;
   LocationSummary* summary =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresRegister());
-  if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister());
+  const bool needs_writable_input = (value()->Type()->ToCid() != kDoubleCid);
+  summary->set_in(0, needs_writable_input
+                     ? Location::WritableRegister()
+                     : Location::RequiresRegister());
   summary->set_out(Location::RequiresFpuRegister());
   return summary;
 }
 
 
 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  const intptr_t value_cid = value()->ResultCid();
+  const intptr_t value_cid = value()->Type()->ToCid();
   const Register value = locs()->in(0).reg();
   const XmmRegister result = locs()->out().fpu_reg();
 
@@ -2234,13 +2280,19 @@
   } else if (value_cid == kSmiCid) {
     __ SmiUntag(value);  // Untag input before conversion.
     __ cvtsi2sd(result, value);
-    __ SmiTag(value);  // Restore input register.
   } else {
     Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp);
-    compiler->LoadDoubleOrSmiToFpu(result,
-                                   value,
-                                   locs()->temp(0).reg(),
-                                   deopt);
+    Label is_smi, done;
+    __ testq(value, Immediate(kSmiTagMask));
+    __ j(ZERO, &is_smi);
+    __ CompareClassId(value, kDoubleCid);
+    __ j(NOT_EQUAL, deopt);
+    __ movsd(result, FieldAddress(value, Double::value_offset()));
+    __ jmp(&done);
+    __ Bind(&is_smi);
+    __ SmiUntag(value);
+    __ cvtsi2sd(result, value);
+    __ Bind(&done);
   }
 }
 
@@ -2627,8 +2679,6 @@
 
 
 void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  // TODO(srdjan): Check if we can remove this by reordering CSE and LICM.
-  if (value()->ResultCid() == kSmiCid) return;
   Register value = locs()->in(0).reg();
   Label* deopt = compiler->AddDeoptStub(deopt_id(),
                                         kDeoptCheckSmi);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 5ed01da..5ed104a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -42,8 +42,10 @@
     "instead of showing the corresponding interface names (e.g. \"String\")");
 DEFINE_FLAG(bool, trace_disabling_optimized_code, false,
     "Trace disabling optimized code.");
-DEFINE_FLAG(int, huge_method_cutoff, 20000,
-            "Huge method cutoff: Disables optimizations for huge methods.");
+DEFINE_FLAG(int, huge_method_cutoff_in_tokens, 20000,
+    "Huge method cutoff in tokens: Disables optimizations for huge methods.");
+DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000,
+    "Huge method cutoff in unoptimized code size (in bytes).");
 DECLARE_FLAG(bool, trace_compiler);
 DECLARE_FLAG(bool, eliminate_type_checks);
 DECLARE_FLAG(bool, enable_type_checks);
@@ -2075,6 +2077,13 @@
 }
 
 
+void Class::set_mixin(const Type& value) const {
+  // Resolution and application of mixin type occurs in finalizer.
+  ASSERT(!value.IsNull());
+  StorePointer(&raw_ptr()->mixin_, value.raw());
+}
+
+
 void Class::AddDirectSubclass(const Class& subclass) const {
   ASSERT(!subclass.IsNull());
   ASSERT(subclass.SuperClass() == raw());
@@ -2185,12 +2194,13 @@
     // Since we do not truncate the type argument vector of a subclass (see
     // below), we only check a prefix of the proper length.
     // Check for covariance.
-    if (other_type_arguments.IsNull() ||
-        other_type_arguments.IsRawInstantiatedRaw(len)) {
+    if (other_type_arguments.IsNull() || other_type_arguments.IsRaw(len)) {
       return true;
     }
-    if (type_arguments.IsNull() ||
-        type_arguments.IsRawInstantiatedRaw(len)) {
+    if (type_arguments.IsNull() || type_arguments.IsRaw(len)) {
+      // Other type can't be more specific than this one because for that
+      // it would have to have all dynamic type arguments which is checked
+      // above.
       return test_kind == kIsSubtypeOf;
     }
     return type_arguments.TypeTest(test_kind,
@@ -3663,10 +3673,20 @@
 
 
 bool Function::is_optimizable() const {
-  return OptimizableBit::decode(raw_ptr()->kind_tag_) &&
-         (script() != Script::null()) &&
-         !is_native() &&
-         ((end_token_pos() - token_pos()) < FLAG_huge_method_cutoff);
+  if (OptimizableBit::decode(raw_ptr()->kind_tag_) &&
+      (script() != Script::null()) &&
+      !is_native() &&
+      ((end_token_pos() - token_pos()) < FLAG_huge_method_cutoff_in_tokens)) {
+    // Additional check needed for implicit getters.
+    if (HasCode() &&
+       (Code::Handle(unoptimized_code()).Size() >=
+        FLAG_huge_method_cutoff_in_code_size)) {
+      return false;
+    } else {
+      return true;
+    }
+  }
+  return false;
 }
 
 
@@ -4081,6 +4101,15 @@
 }
 
 
+// The compiler generates an implicit constructor if a class definition
+// does not contain an explicit constructor or factory. The implicit
+// constructor has the same token position as the owner class.
+bool Function::IsImplicitConstructor() const {
+  return IsConstructor() &&
+         (token_pos() == Class::Handle(Owner()).token_pos());
+}
+
+
 bool Function::IsImplicitClosureFunction() const {
   if (!IsClosureFunction()) {
     return false;
@@ -4140,6 +4169,24 @@
 }
 
 
+RawFunction* Function::Clone(const Class& new_owner) const {
+  ASSERT(!IsConstructor());
+  Function& clone = Function::Handle();
+  clone ^= Object::Clone(*this, Heap::kOld);
+  const Class& owner = Class::Handle(this->Owner());
+  const PatchClass& clone_owner =
+      PatchClass::Handle(PatchClass::New(new_owner, owner));
+  clone.set_owner(clone_owner);
+  clone.StorePointer(&clone.raw_ptr()->code_, Code::null());
+  clone.StorePointer(&clone.raw_ptr()->unoptimized_code_, Code::null());
+  clone.set_usage_counter(0);
+  clone.set_deoptimization_counter(0);
+  clone.set_optimized_instruction_count(0);
+  clone.set_optimized_call_site_count(0);
+  return clone.raw();
+}
+
+
 RawFunction* Function::NewClosureFunction(const String& name,
                                           const Function& parent,
                                           intptr_t token_pos) {
@@ -4378,6 +4425,16 @@
 }
 
 
+RawClass* Function::origin() const {
+  const Object& obj = Object::Handle(raw_ptr()->owner_);
+  if (obj.IsClass()) {
+    return Class::Cast(obj).raw();
+  }
+  ASSERT(obj.IsPatchClass());
+  return PatchClass::Cast(obj).source_class();
+}
+
+
 RawScript* Function::script() const {
   const Object& obj = Object::Handle(raw_ptr()->owner_);
   if (obj.IsClass()) {
@@ -4637,6 +4694,26 @@
 }
 
 
+RawClass* Field::owner() const {
+  const Object& obj = Object::Handle(raw_ptr()->owner_);
+  if (obj.IsClass()) {
+    return Class::Cast(obj).raw();
+  }
+  ASSERT(obj.IsPatchClass());
+  return PatchClass::Cast(obj).patched_class();
+}
+
+
+RawClass* Field::origin() const {
+  const Object& obj = Object::Handle(raw_ptr()->owner_);
+  if (obj.IsClass()) {
+    return Class::Cast(obj).raw();
+  }
+  ASSERT(obj.IsPatchClass());
+  return PatchClass::Cast(obj).source_class();
+}
+
+
 RawInstance* Field::value() const {
   ASSERT(is_static());  // Valid only for static dart fields.
   return raw_ptr()->value_;
@@ -4688,6 +4765,21 @@
 }
 
 
+
+RawField* Field::Clone(const Class& new_owner) const {
+  Field& clone = Field::Handle();
+  clone ^= Object::Clone(*this, Heap::kOld);
+  const Class& owner = Class::Handle(this->owner());
+  const PatchClass& clone_owner =
+      PatchClass::Handle(PatchClass::New(new_owner, owner));
+  clone.set_owner(clone_owner);
+  if (!clone.is_static()) {
+    clone.SetOffset(0);
+  }
+  return clone.raw();
+}
+
+
 RawString* Field::UserVisibleName() const {
   const String& str = String::Handle(name());
   return IdentifierPrettyName(str);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 7a4c908..88e93d2 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -661,6 +661,9 @@
   // Asserts that the class of the super type has been resolved.
   RawClass* SuperClass() const;
 
+  RawType* mixin() const { return raw_ptr()->mixin_; }
+  void set_mixin(const Type& value) const;
+
   // Interfaces is an array of Types.
   RawArray* interfaces() const { return raw_ptr()->interfaces_; }
   void set_interfaces(const Array& value) const;
@@ -1197,7 +1200,7 @@
   bool HasInstantiatedSignature() const;
 
   RawClass* Owner() const;
-
+  RawClass* origin() const;
   RawScript* script() const;
 
   RawAbstractType* result_type() const { return raw_ptr()->result_type_; }
@@ -1205,12 +1208,14 @@
 
   RawAbstractType* ParameterTypeAt(intptr_t index) const;
   void SetParameterTypeAt(intptr_t index, const AbstractType& value) const;
+  RawArray* parameter_types() const { return raw_ptr()->parameter_types_; }
   void set_parameter_types(const Array& value) const;
 
   // Parameter names are valid for all valid parameter indices, and are not
   // limited to named optional parameters.
   RawString* ParameterNameAt(intptr_t index) const;
   void SetParameterNameAt(intptr_t index, const String& value) const;
+  RawArray* parameter_names() const { return raw_ptr()->parameter_names_; }
   void set_parameter_names(const Array& value) const;
 
   // Sets function's code and code's function.
@@ -1284,6 +1289,7 @@
   bool IsConstructor() const {
     return (kind() == RawFunction::kConstructor) && !is_static();
   }
+  bool IsImplicitConstructor() const;
   bool IsFactory() const {
     return (kind() == RawFunction::kConstructor) && is_static();
   }
@@ -1561,6 +1567,10 @@
                                          const Function& parent,
                                          intptr_t token_pos);
 
+  // Allocate new function object, clone values from this function. The
+  // owner of the clone is new_owner.
+  RawFunction* Clone(const Class& new_owner) const;
+
   // Slow function, use in asserts to track changes in important library
   // functions.
   int32_t SourceFingerprint() const;
@@ -1723,7 +1733,8 @@
   RawInstance* value() const;
   void set_value(const Instance& value) const;
 
-  RawClass* owner() const { return raw_ptr()->owner_; }
+  RawClass* owner() const;
+  RawClass* origin() const;  // Either mixin class, or same as owner().
 
   RawAbstractType* type() const  { return raw_ptr()->type_; }
   void set_type(const AbstractType& value) const;
@@ -1739,6 +1750,10 @@
                        const Class& owner,
                        intptr_t token_pos);
 
+  // Allocate new field object, clone values from this field. The
+  // owner of the clone is new_owner.
+  RawField* Clone(const Class& new_owner) const;
+
   static intptr_t value_offset() { return OFFSET_OF(RawField, value_); }
 
   intptr_t token_pos() const { return raw_ptr()->token_pos_; }
@@ -1783,7 +1798,7 @@
   void set_is_const(bool value) const {
     set_kind_bits(ConstBit::update(value, raw_ptr()->kind_bits_));
   }
-  void set_owner(const Class& value) const {
+  void set_owner(const Object& value) const {
     StorePointer(&raw_ptr()->owner_, value.raw());
   }
   void set_token_pos(intptr_t token_pos) const {
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index cee4d82..0c9427e 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -114,6 +114,13 @@
 }
 
 
+LocalVariable* ParsedFunction::CreateArrayLiteralVar(intptr_t token_pos) {
+  return new LocalVariable(token_pos,
+                           Symbols::ArrayLiteralVar(),
+                           Type::ZoneHandle(Type::ArrayType()));
+}
+
+
 void ParsedFunction::SetNodeSequence(SequenceNode* node_sequence) {
   ASSERT(node_sequence_ == NULL);
   ASSERT(node_sequence != NULL);
@@ -284,7 +291,8 @@
       parsed_function_(parsed_function),
       innermost_function_(Function::Handle(parsed_function->function().raw())),
       current_class_(Class::Handle(parsed_function->function().Owner())),
-      library_(Library::Handle(current_class_.library())),
+      library_(Library::Handle(Class::Handle(
+          parsed_function->function().origin()).library())),
       try_blocks_list_(NULL) {
   ASSERT(tokens_iterator_.IsValid());
   ASSERT(!current_function().IsNull());
@@ -758,6 +766,10 @@
       UNREACHABLE();
   }
 
+  parsed_function->set_array_literal_var(
+      ParsedFunction::CreateArrayLiteralVar(func.token_pos()));
+  node_sequence->scope()->AddVariable(parsed_function->array_literal_var());
+
   if (!HasReturnNode(node_sequence)) {
     // Add implicit return node.
     node_sequence->Add(new ReturnNode(func.end_token_pos()));
@@ -1375,6 +1387,18 @@
 }
 
 
+LocalVariable* Parser::BuildArrayTempLocal(intptr_t token_pos) {
+  char name[64];
+  OS::SNPrint(name, 64, ":arrlit%"Pd, token_pos);
+  LocalVariable* temp =
+      new LocalVariable(token_pos,
+                        String::ZoneHandle(Symbols::New(name)),
+                        Type::ZoneHandle(Type::ArrayType()));
+  current_block_->scope->AddVariable(temp);
+  return temp;
+}
+
+
 StaticCallNode* Parser::BuildInvocationMirrorAllocation(
     intptr_t call_pos,
     const String& function_name,
@@ -1393,7 +1417,8 @@
   // The third argument is an array containing the original function arguments,
   // including the receiver.
   ArrayNode* args_array = new ArrayNode(
-      args_pos, Type::ZoneHandle(Type::ArrayType()));
+      args_pos, Type::ZoneHandle(Type::ArrayType()),
+      *BuildArrayTempLocal(call_pos));
   for (intptr_t i = 0; i < function_args.length(); i++) {
     args_array->AddElement(function_args.NodeAt(i));
   }
@@ -1817,6 +1842,13 @@
         initialized_fields->Add(&field);
       }
       intptr_t field_pos = field.token_pos();
+      if (current_class().raw() != field.origin()) {
+        const Class& origin_class = Class::Handle(field.origin());
+        if (origin_class.library() != library_.raw()) {
+          ErrorMsg("Cannot handle initialized mixin field '%s'"
+                   "from imported library\n", field.ToCString());
+        }
+      }
       SetPosition(field_pos);
       ASSERT(IsIdentifier());
       ConsumeToken();
@@ -2009,13 +2041,11 @@
   const Class& cls = Class::Handle(func.Owner());
   ASSERT(!cls.IsNull());
 
-  if (CurrentToken() == Token::kCLASS) {
+  if (func.IsImplicitConstructor()) {
     // Special case: implicit constructor.
     // The parser adds an implicit default constructor when a class
     // does not have any explicit constructor or factory (see
-    // Parser::AddImplicitConstructor). The token position of this implicit
-    // constructor points to the 'class' keyword, which is followed
-    // by the name of the class (which is also the constructor name).
+    // Parser::AddImplicitConstructor).
     // There is no source text to parse. We just build the
     // sequence node by hand.
     return MakeImplicitConstructor(func);
@@ -3220,8 +3250,11 @@
                String::Handle(type.UserVisibleName()).ToCString());
     }
     super_type ^= type.raw();
+    if (CurrentToken() == Token::kWITH) {
+      super_type = ParseMixins(super_type);
+    }
   } else {
-    // No extends clause: Implicitly extend Object.
+    // No extends clause: implicitly extend Object.
     super_type = Type::ObjectType();
   }
   ASSERT(!super_type.IsNull());
@@ -3246,13 +3279,13 @@
     cls.set_is_abstract();
   }
 
-  // Add an implicit constructor if no explicit constructor is present. No
-  // implicit constructors are needed for patch classes.
-  if (!members.has_constructor() && !is_patch) {
-    AddImplicitConstructor(&members);
-  }
   CheckConstructors(&members);
 
+  // Need to compute this here since MakeArray() will clear the
+  // functions array in members.
+  const bool need_implicit_constructor =
+      !members.has_constructor() && !is_patch;
+
   Array& array = Array::Handle();
   array = Array::MakeArray(members.fields());
   cls.SetFields(array);
@@ -3261,6 +3294,12 @@
   array = Array::MakeArray(members.functions());
   cls.SetFunctions(array);
 
+  // Add an implicit constructor if no explicit constructor is present.
+  // No implicit constructors are needed for patch classes.
+  if (need_implicit_constructor) {
+    AddImplicitConstructor(cls);
+  }
+
   if (!is_patch) {
     pending_classes.Add(cls, Heap::kOld);
   } else {
@@ -3276,15 +3315,14 @@
 }
 
 
-// Add an implicit constructor if no explicit constructor is present.
-void Parser::AddImplicitConstructor(ClassDesc* class_desc) {
-  // The implicit constructor is unnamed, has no explicit parameter,
-  // and contains a supercall in the initializer list.
-  String& ctor_name = String::ZoneHandle(
-    String::Concat(class_desc->class_name(), Symbols::Dot()));
+// Add an implicit constructor to the given class.
+void Parser::AddImplicitConstructor(const Class& cls) {
+  // The implicit constructor is unnamed, has no explicit parameter.
+  String& ctor_name = String::ZoneHandle(cls.Name());
+  ctor_name = String::Concat(ctor_name, Symbols::Dot());
   ctor_name = Symbols::New(ctor_name);
-  // The token position for the implicit constructor is the 'class'
-  // keyword of the constructor's class.
+  // To indicate that this is an implicit constructor, we set the
+  // token position is the same as the token position of the class.
   Function& ctor = Function::Handle(
       Function::New(ctor_name,
                     RawFunction::kConstructor,
@@ -3292,22 +3330,23 @@
                     /* is_const = */ false,
                     /* is_abstract = */ false,
                     /* is_external = */ false,
-                    current_class(),
-                    class_desc->token_pos()));
+                    cls,
+                    cls.token_pos()));
   ParamList params;
-  // Add implicit 'this' parameter.
-  ASSERT(current_class().raw() == ctor.Owner());
-  params.AddReceiver(ReceiverType(TokenPos()));
+  // Add implicit 'this' parameter. We don't care about the specific type
+  // and just specify dynamic.
+  const Type& receiver_type = Type::Handle(Type::DynamicType());
+  params.AddReceiver(&receiver_type);
   // Add implicit parameter for construction phase.
-  params.AddFinalParameter(TokenPos(),
+  params.AddFinalParameter(cls.token_pos(),
                            &Symbols::PhaseParameter(),
                            &Type::ZoneHandle(Type::SmiType()));
 
   AddFormalParamsToFunction(&params, ctor);
   // The body of the constructor cannot modify the type of the constructed
   // instance, which is passed in as the receiver.
-  ctor.set_result_type(*((*params.parameters)[0].type));
-  class_desc->AddFunction(ctor);
+  ctor.set_result_type(receiver_type);
+  cls.AddFunction(ctor);
 }
 
 
@@ -3352,6 +3391,75 @@
 }
 
 
+void Parser::ParseMixinTypedef(const GrowableObjectArray& pending_classes) {
+  TRACE_PARSER("ParseMixinTypedef");
+  const intptr_t classname_pos = TokenPos();
+  String& class_name = *ExpectUserDefinedTypeIdentifier("class name expected");
+  if (FLAG_trace_parser) {
+    OS::Print("toplevel parsing typedef class '%s'\n", class_name.ToCString());
+  }
+  const Object& obj = Object::Handle(library_.LookupLocalObject(class_name));
+  if (!obj.IsNull()) {
+    ErrorMsg(classname_pos, "'%s' is already defined",
+             class_name.ToCString());
+  }
+  const Class& mixin_application =
+      Class::Handle(Class::New(class_name, script_, classname_pos));
+  library_.AddClass(mixin_application);
+  set_current_class(mixin_application);
+  ParseTypeParameters(mixin_application);
+  ExpectToken(Token::kASSIGN);
+
+  if (CurrentToken() == Token::kABSTRACT) {
+    mixin_application.set_is_abstract();
+    ConsumeToken();
+  }
+
+  const intptr_t supertype_pos = TokenPos();
+  const AbstractType& type =
+      AbstractType::Handle(ParseType(ClassFinalizer::kTryResolve));
+  if (type.IsTypeParameter()) {
+    ErrorMsg(supertype_pos,
+             "class '%s' may not extend type parameter '%s'",
+             class_name.ToCString(),
+             String::Handle(type.UserVisibleName()).ToCString());
+  }
+  Type& mixin_super_type = Type::Handle();
+  mixin_super_type ^= type.raw();
+
+  if (CurrentToken() != Token::kWITH) {
+    ErrorMsg("mixin application 'with Type' expected");
+  }
+
+  Type& mixin_application_type = Type::Handle(ParseMixins(mixin_super_type));
+  // The result of ParseMixins() is a chain of super classes that is the
+  // result of the mixin composition 'S with M1, M2, ...'. The mixin
+  // application classes are anonymous (i.e. not registered in the current
+  // library). We steal the super type and mixin type from the bottom of
+  // the chain and add it to the named mixin application class. The bottom
+  // anonymous class in the chain is thrown away.
+  const Class& anon_mixin_app_class =
+      Class::Handle(mixin_application_type.type_class());
+  mixin_application.set_super_type(
+      Type::Handle(anon_mixin_app_class.super_type()));
+  mixin_application.set_mixin(Type::Handle(anon_mixin_app_class.mixin()));
+  const Array& interfaces = Array::Handle(anon_mixin_app_class.interfaces());
+  mixin_application.set_interfaces(interfaces);
+  AddImplicitConstructor(mixin_application);
+
+  if (CurrentToken() == Token::kIMPLEMENTS) {
+    Array& interfaces = Array::Handle();
+    const intptr_t interfaces_pos = TokenPos();
+    const Type& super_type = Type::Handle(mixin_application.super_type());
+    interfaces = ParseInterfaceList(super_type);
+    AddInterfaces(interfaces_pos, mixin_application, interfaces);
+  }
+
+  pending_classes.Add(mixin_application, Heap::kOld);
+  ExpectSemicolon();
+}
+
+
 // Look ahead to detect if we are seeing ident [ TypeParameters ] "(".
 // We need this lookahead to distinguish between the optional return type
 // and the alias name of a function type alias.
@@ -3373,11 +3481,34 @@
 }
 
 
-void Parser::ParseFunctionTypeAlias(
-    const GrowableObjectArray& pending_classes) {
-  TRACE_PARSER("ParseFunctionTypeAlias");
+// Look ahead to detect if we are seeing ident [ TypeParameters ] "=".
+// Token position remains unchanged.
+bool Parser::IsMixinTypedef() {
+  if (IsIdentifier() && (LookaheadToken(1) == Token::kASSIGN)) {
+    return true;
+  }
+  const intptr_t saved_pos = TokenPos();
+  bool is_mixin_def = false;
+  if (IsIdentifier() && (LookaheadToken(1) == Token::kLT)) {
+    ConsumeToken();
+    if (TryParseTypeParameter() && (CurrentToken() == Token::kASSIGN)) {
+      is_mixin_def = true;
+    }
+  }
+  SetPosition(saved_pos);
+  return is_mixin_def;
+}
+
+
+void Parser::ParseTypedef(const GrowableObjectArray& pending_classes) {
+  TRACE_PARSER("ParseTypedef");
   ExpectToken(Token::kTYPEDEF);
 
+  if (IsMixinTypedef()) {
+    ParseMixinTypedef(pending_classes);
+    return;
+  }
+
   // Parse the result type of the function type.
   AbstractType& result_type = Type::Handle(Type::DynamicType());
   if (CurrentToken() == Token::kVOID) {
@@ -3659,8 +3790,7 @@
 // Parse and return an array of interface types.
 RawArray* Parser::ParseInterfaceList(const Type& super_type) {
   TRACE_PARSER("ParseInterfaceList");
-  ASSERT((CurrentToken() == Token::kIMPLEMENTS) ||
-         (CurrentToken() == Token::kEXTENDS));
+  ASSERT(CurrentToken() == Token::kIMPLEMENTS);
   const GrowableObjectArray& interfaces =
       GrowableObjectArray::Handle(GrowableObjectArray::New());
   String& interface_name = String::Handle();
@@ -3674,6 +3804,9 @@
     interface = ParseType(ClassFinalizer::kTryResolve);
     interface_name = interface.UserVisibleName();
     if (interface_name.Equals(super_type_name)) {
+      // TODO(hausner): I think this check is not necessary. There is
+      // no such restriction. If the check is removed, the 'super_type'
+      // parameter to this function can be eliminated.
       ErrorMsg(interface_pos, "class may not extend and implement '%s'",
                interface_name.ToCString());
     }
@@ -3691,6 +3824,72 @@
 }
 
 
+RawType* Parser::ParseMixins(const Type& super_type) {
+  TRACE_PARSER("ParseMixins");
+  ASSERT(CurrentToken() == Token::kWITH);
+
+  // TODO(hausner): Remove this restriction.
+  if (super_type.arguments() != AbstractTypeArguments::null()) {
+    ErrorMsg(super_type.token_pos(),
+             "super class of mixin may not have type arguments");
+  }
+
+  AbstractType& mixin_type = AbstractType::Handle();
+  AbstractTypeArguments& mixin_type_arguments =
+      AbstractTypeArguments::Handle();
+  Class& mixin_application = Class::Handle();
+  Type& mixin_application_type = Type::Handle();
+  Type& mixin_super_type = Type::Handle(super_type.raw());
+  Array& mixin_application_interfaces = Array::Handle();
+  const TypeArguments& no_type_arguments = TypeArguments::Handle();
+  do {
+    ConsumeToken();
+    const intptr_t mixin_pos = TokenPos();
+    mixin_type = ParseType(ClassFinalizer::kTryResolve);
+    if (mixin_type.IsTypeParameter()) {
+      ErrorMsg(mixin_pos,
+               "mixin type '%s' may not be a type parameter",
+               String::Handle(mixin_type.UserVisibleName()).ToCString());
+    }
+    // TODO(hausner): Remove this check once we handle mixins with type
+    // arguments.
+    mixin_type_arguments = mixin_type.arguments();
+    if (!mixin_type_arguments.IsNull()) {
+      ErrorMsg(mixin_pos,
+               "mixin type '%s' may not have type arguments",
+               String::Handle(mixin_type.UserVisibleName()).ToCString());
+    }
+
+    // The name of the mixin application class is a combination of
+    // the superclass and mixin class.
+    String& mixin_app_name = String::Handle();
+    mixin_app_name = mixin_super_type.Name();
+    mixin_app_name = String::Concat(mixin_app_name, Symbols::Ampersand());
+    mixin_app_name = String::Concat(mixin_app_name,
+                                     String::Handle(mixin_type.Name()));
+    mixin_app_name = Symbols::New(mixin_app_name);
+
+    mixin_application = Class::New(mixin_app_name, script_, mixin_pos);
+    mixin_application.set_super_type(mixin_super_type);
+    mixin_application.set_mixin(Type::Cast(mixin_type));
+    mixin_application.set_library(library_);
+    AddImplicitConstructor(mixin_application);
+    // Add the mixin type to the interfaces that the mixin application
+    // class implements. This is necessary so that type tests work.
+    mixin_application_interfaces = Array::New(1);
+    mixin_application_interfaces.SetAt(0, mixin_type);
+    mixin_application.set_interfaces(mixin_application_interfaces);
+
+    // TODO(hausner): Need to support type arguments.
+    mixin_application_type = Type::New(mixin_application,
+                                       no_type_arguments,
+                                       Scanner::kDummyTokenIndex);
+    mixin_super_type = mixin_application_type.raw();
+  } while (CurrentToken() == Token::kCOMMA);
+  return mixin_application_type.raw();
+}
+
+
 // Add 'interface' to 'interface_list' if it is not already in the list.
 // An error is reported if the interface conflicts with an interface already in
 // the list with the same class and same type arguments.
@@ -4425,7 +4624,7 @@
     } else if ((CurrentToken() == Token::kTYPEDEF) &&
                (LookaheadToken(1) != Token::kLPAREN)) {
       set_current_class(toplevel_class);
-      ParseFunctionTypeAlias(pending_classes);
+      ParseTypedef(pending_classes);
     } else if ((CurrentToken() == Token::kABSTRACT) &&
         (LookaheadToken(1) == Token::kCLASS)) {
       ParseClassDefinition(pending_classes);
@@ -8683,7 +8882,8 @@
     }
     factory_type_args = factory_type_args.Canonicalize();
     ArgumentListNode* factory_param = new ArgumentListNode(literal_pos);
-    ArrayNode* list = new ArrayNode(TokenPos(), type, element_list);
+    const LocalVariable& temp_local = *BuildArrayTempLocal(type_pos);
+    ArrayNode* list = new ArrayNode(TokenPos(), type, temp_local, element_list);
     factory_param->Add(list);
     return CreateConstructorCallNode(literal_pos,
                                      factory_type_args,
@@ -8773,8 +8973,6 @@
   ASSERT(map_type_arguments.IsNull() || (map_type_arguments.Length() == 2));
   map_type_arguments ^= map_type_arguments.Canonicalize();
 
-  // The kv_pair array is temporary and of element type dynamic. It is passed
-  // to the factory to initialize a properly typed map.
   GrowableArray<AstNode*> kv_pairs_list;
   // Parse the map entries. Note: there may be an optional extra
   // comma after the last entry.
@@ -8902,8 +9100,13 @@
     }
     factory_type_args = factory_type_args.Canonicalize();
     ArgumentListNode* factory_param = new ArgumentListNode(literal_pos);
+    // The kv_pair array is temporary and of element type dynamic. It is passed
+    // to the factory to initialize a properly typed map.
     ArrayNode* kv_pairs = new ArrayNode(
-        TokenPos(), Type::ZoneHandle(Type::ArrayType()), kv_pairs_list);
+        TokenPos(),
+        Type::ZoneHandle(Type::ArrayType()),
+        *BuildArrayTempLocal(type_pos),
+        kv_pairs_list);
     factory_param->Add(kv_pairs);
     return CreateConstructorCallNode(literal_pos,
                                      factory_type_args,
@@ -9279,7 +9482,10 @@
   } else {
     ArgumentListNode* interpolate_arg = new ArgumentListNode(TokenPos());
     ArrayNode* values = new ArrayNode(
-        TokenPos(), Type::ZoneHandle(Type::ArrayType()), values_list);
+        TokenPos(),
+        Type::ZoneHandle(Type::ArrayType()),
+        *BuildArrayTempLocal(TokenPos()),
+        values_list);
     interpolate_arg->Add(values);
     primary = MakeStaticCall(Symbols::StringBase(),
                              PrivateCoreLibName(Symbols::Interpolate()),
@@ -9444,6 +9650,14 @@
       ErrorMsg("class '%s' does not have a superclass",
                String::Handle(current_class().Name()).ToCString());
     }
+    if (current_class().mixin() != Type::null()) {
+      const Type& mixin_type = Type::Handle(current_class().mixin());
+      if (mixin_type.type_class() == current_function().origin()) {
+        ErrorMsg("class '%s' may not use super "
+                 "because it is used as mixin class",
+                 String::Handle(current_class().Name()).ToCString());
+      }
+    }
     ConsumeToken();
     if (CurrentToken() == Token::kPERIOD) {
       ConsumeToken();
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 6ca97c4..f0ca6d5 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -40,6 +40,7 @@
         saved_current_context_var_(NULL),
         saved_entry_context_var_(NULL),
         expression_temp_var_(NULL),
+        array_literal_var_(NULL),
         first_parameter_index_(0),
         first_stack_local_index_(0),
         num_copied_params_(0),
@@ -102,6 +103,17 @@
   }
   static LocalVariable* CreateExpressionTempVar(intptr_t token_pos);
 
+  void set_array_literal_var(LocalVariable* local) {
+    ASSERT((local != NULL) &&  (array_literal_var_ == NULL));
+    array_literal_var_ = local;
+  }
+  LocalVariable* array_literal_var() const {
+    ASSERT(array_literal_var_ != NULL);
+    return array_literal_var_;
+  }
+
+  static LocalVariable* CreateArrayLiteralVar(intptr_t token_pos);
+
   int first_parameter_index() const { return first_parameter_index_; }
   int first_stack_local_index() const { return first_stack_local_index_; }
   int num_copied_params() const { return num_copied_params_; }
@@ -117,6 +129,9 @@
   LocalVariable* saved_current_context_var_;
   LocalVariable* saved_entry_context_var_;
   LocalVariable* expression_temp_var_;
+  // TODO(hausner): Remove once ArrayNode creation is removed from flow
+  // graph builder.
+  LocalVariable* array_literal_var_;
 
   int first_parameter_index_;
   int first_stack_local_index_;
@@ -313,7 +328,8 @@
   // Support for parsing of scripts.
   void ParseTopLevel();
   void ParseClassDefinition(const GrowableObjectArray& pending_classes);
-  void ParseFunctionTypeAlias(const GrowableObjectArray& pending_classes);
+  void ParseMixinTypedef(const GrowableObjectArray& pending_classes);
+  void ParseTypedef(const GrowableObjectArray& pending_classes);
   void ParseTopLevelVariable(TopLevel* top_level);
   void ParseTopLevelFunction(TopLevel* top_level);
   void ParseTopLevelAccessor(TopLevel* top_level);
@@ -351,7 +367,7 @@
   void ParseFormalParameterList(bool allow_explicit_default_values,
                                 ParamList* params);
   void CheckConstFieldsInitialized(const Class& cls);
-  void AddImplicitConstructor(ClassDesc* members);
+  void AddImplicitConstructor(const Class& cls);
   void CheckConstructors(ClassDesc* members);
   void ParseInitializedInstanceFields(
       const Class& cls,
@@ -372,6 +388,7 @@
                          GrowableArray<Field*>* initialized_fields);
   String& ParseNativeDeclaration();
   RawArray* ParseInterfaceList(const Type& super_type);
+  RawType* ParseMixins(const Type& super_type);
   void AddInterfaceIfUnique(intptr_t interfaces_pos,
                             const GrowableObjectArray& interface_list,
                             const AbstractType& interface);
@@ -474,6 +491,7 @@
   bool IsIdentifier();
   bool IsSimpleLiteral(const AbstractType& type, Instance* value);
   bool IsFunctionTypeAliasName();
+  bool IsMixinTypedef();
   bool TryParseTypeParameter();
   bool TryParseOptionalType();
   bool TryParseReturnType();
@@ -612,6 +630,7 @@
       const Function& constructor,
       ArgumentListNode* arguments);
 
+  LocalVariable* BuildArrayTempLocal(intptr_t token_pos);
 
   const Script& script_;
   TokenStream::Iterator tokens_iterator_;
@@ -642,6 +661,9 @@
   Class& current_class_;
 
   // The current library (and thus class dictionary) used to resolve names.
+  // When parsing a function, this is the library in which the function
+  // is defined. This can be the library in which the current_class_ is
+  // defined, or the library of a mixin class where the function originates.
   const Library& library_;
 
   // List of try blocks seen so far, this is used to generate inlined finally
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index ac66f62..9dd8faa 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -433,6 +433,7 @@
   RawLibrary* library_;
   RawTypeArguments* type_parameters_;  // Array of TypeParameter.
   RawType* super_type_;
+  RawType* mixin_;
   RawFunction* signature_function_;  // Associated function for signature class.
   RawArray* constants_;  // Canonicalized values of this class.
   RawArray* canonical_types_;  // Canonicalized types of this class.
@@ -555,7 +556,8 @@
 
   RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->name_); }
   RawString* name_;
-  RawObject* owner_;  // Class or  patch class where this function was defined.
+  RawObject* owner_;  // Class or patch class or mixin class
+                      // where this function is defined.
   RawAbstractType* result_type_;
   RawArray* parameter_types_;
   RawArray* parameter_names_;
@@ -619,7 +621,8 @@
 
   RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->name_); }
   RawString* name_;
-  RawClass* owner_;
+  RawObject* owner_;  // Class or patch class or mixin class
+                      // where this field is defined.
   RawAbstractType* type_;
   RawInstance* value_;  // Offset in words for instance and value for static.
   RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->value_); }
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index caec906..0e6e274 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -59,6 +59,7 @@
   V(SavedTryContextVar, ":saved_try_context_var")                              \
   V(ExceptionVar, ":exception_var")                                            \
   V(StacktraceVar, ":stacktrace_var")                                          \
+  V(ArrayLiteralVar, ":array_literal_var")                                     \
   V(ListLiteralElement, "list literal element")                                \
   V(ForInIter, ":for-in-iter")                                                 \
   V(Library, "library")                                                        \
@@ -281,6 +282,9 @@
   static const String& Dash() {
     return *(symbol_handles_[kNullCharId + '-']);
   }
+  static const String& Ampersand() {
+    return *(symbol_handles_[kNullCharId + '&']);
+  }
 
   // Access methods for symbol handles stored in the vm isolate.
 #define DEFINE_SYMBOL_HANDLE_ACCESSOR(symbol, literal)                         \
diff --git a/runtime/vm/token.h b/runtime/vm/token.h
index ee57ca9..aebd94a 100644
--- a/runtime/vm/token.h
+++ b/runtime/vm/token.h
@@ -185,7 +185,8 @@
   KW(kTYPEDEF, "typedef", 0, kPseudoKeyword)                                   \
   KW(kVAR, "var", 0, kKeyword)                                                 \
   KW(kVOID, "void", 0, kKeyword)                                               \
-  KW(kWHILE, "while", 0, kKeyword) /* == kLastKeyword */
+  KW(kWHILE, "while", 0, kKeyword)                                             \
+  KW(kWITH, "with", 0, kKeyword) /* == kLastKeyword */
 
 
 class String;
@@ -207,8 +208,8 @@
   };
 
   static const Kind kFirstKeyword = kABSTRACT;
-  static const Kind kLastKeyword = kWHILE;
-  static const int  numKeywords = kWHILE - kABSTRACT + 1;
+  static const Kind kLastKeyword = kWITH;
+  static const int  numKeywords = kLastKeyword - kFirstKeyword + 1;
 
   static bool IsAssignmentOperator(Kind tok) {
     return kASSIGN <= tok && tok <= kASSIGN_MOD;
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 1f53461..2f70b1a 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -155,6 +155,8 @@
     'flow_graph_inliner.h',
     'flow_graph_optimizer.cc',
     'flow_graph_optimizer.h',
+    'flow_graph_type_propagator.cc',
+    'flow_graph_type_propagator.h',
     'freelist.cc',
     'freelist.h',
     'freelist_test.cc',
diff --git a/sdk/lib/_collection_dev/iterable.dart b/sdk/lib/_collection_dev/iterable.dart
index ac490e1..676ad73 100644
--- a/sdk/lib/_collection_dev/iterable.dart
+++ b/sdk/lib/_collection_dev/iterable.dart
@@ -4,6 +4,317 @@
 
 part of dart._collection.dev;
 
+
+/**
+ * An [Iterable] for classes that have efficient [length] and [elementAt].
+ *
+ * All other methods are implemented in terms of [length] and [elementAt],
+ * including [iterator].
+ */
+abstract class ListIterable<E> extends Iterable<E> {
+  int get length;
+  E elementAt(int i);
+
+  Iterator<E> get iterator => new ListIterableIterator<E>(this);
+
+  void forEach(void action(E element)) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      action(elementAt(i));
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+  }
+
+  bool get isEmpty => length != 0;
+
+  E get first {
+    if (length == 0) throw new StateError("No elements");
+    return elementAt(0);
+  }
+
+  E get last {
+    if (length == 0) throw new StateError("No elements");
+    return elementAt(length - 1);
+  }
+
+  E get single {
+    if (length == 0) throw new StateError("No elements");
+    if (length > 1) throw new StateError("Too many elements");
+    return elementAt(0);
+  }
+
+  bool contains(E element) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      if (elementAt(i) == element) return true;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return false;
+  }
+
+  bool every(bool test(E element)) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      if (!test(elementAt(i))) return false;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return true;
+  }
+
+  bool any(bool test(E element)) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      if (test(elementAt(i))) return true;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return false;
+  }
+
+  E firstMatching(bool test(E element), { E orElse() }) {
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      E element = elementAt(i);
+      if (test(element)) return element;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    if (orElse != null) return orElse();
+    throw new StateError("No matching element");
+  }
+
+  E lastMatching(bool test(E element), { E orElse() }) {
+    int length = this.length;
+    for (int i = length - 1; i >= 0; i++) {
+      E element = elementAt(i);
+      if (test(element)) return element;
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    if (orElse != null) return orElse();
+    throw new StateError("No matching element");
+  }
+
+  E singleMatching(bool test(E element)) {
+    int length = this.length;
+    E match = null;
+    bool matchFound = false;
+    for (int i = 0; i < length; i++) {
+      E element = elementAt(i);
+      if (test(element)) {
+        if (matchFound) {
+          throw new StateError("More than one matching element");
+        }
+        matchFound = true;
+        match = element;
+      }
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    if (matchFound) return match;
+    throw new StateError("No matching element");
+  }
+
+  E min([int compare(E a, E b)]) {
+    if (length == 0) return null;
+    if (compare == null) {
+      var defaultCompare = Comparable.compare;
+      compare = defaultCompare;
+    }
+    E min = elementAt(0);
+    int length = this.length;
+    for (int i = 1; i < length; i++) {
+      E element = elementAt(i);
+      if (compare(min, element) > 0) {
+        min = element;
+      }
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return min;
+  }
+
+  E max([int compare(E a, E b)]) {
+    if (length == 0) return null;
+    if (compare == null) {
+      var defaultCompare = Comparable.compare;
+      compare = defaultCompare;
+    }
+    E max = elementAt(0);
+    int length = this.length;
+    for (int i = 1; i < length; i++) {
+      E element = elementAt(i);
+      if (compare(max, element) < 0) {
+        max = element;
+      }
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return max;
+  }
+
+  String join([String separator]) {
+    int length = this.length;
+    if (separator != null && !separator.isEmpty) {
+      if (length == 0) return "";
+      String first = "${elementAt(0)}";
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+      StringBuffer buffer = new StringBuffer(first);
+      for (int i = 1; i < length; i++) {
+        buffer.add(separator);
+        buffer.add("${elementAt(i)}");
+        if (length != this.length) {
+          throw new ConcurrentModificationError(this);
+        }
+      }
+      return buffer.toString();
+    } else {
+      StringBuffer buffer = new StringBuffer();
+      for (int i = 0; i < length; i++) {
+        buffer.add("${elementAt(i)}");
+        if (length != this.length) {
+          throw new ConcurrentModificationError(this);
+        }
+      }
+      return buffer.toString();
+    }
+  }
+
+  Iterable<E> where(bool test(E element)) => super.where(test);
+
+  Iterable map(f(E element)) => new MappedIterable(this, f);
+
+  Iterable mappedBy(f(E element)) => super.mappedBy(f);
+
+  reduce(var initialValue, combine(var previousValue, E element)) {
+    var value = initialValue;
+    int length = this.length;
+    for (int i = 0; i < length; i++) {
+      value = reduce(value, elementAt(i));
+      if (length != this.length) {
+        throw new ConcurrentModificationError(this);
+      }
+    }
+    return value;
+  }
+
+  Iterable<E> skip(int count) => new SubListIterable(this, count, null);
+
+  Iterable<E> skipWhile(bool test(E element)) => super.skipWhile(test);
+
+  Iterable<E> take(int count) => new SubListIterable(this, 0, count);
+
+  Iterable<E> takeWhile(bool test(E element)) => super.takeWhile(test);
+
+  List<E> toList() {
+    List<E> result = new List(length);
+    for (int i = 0; i < length; i++) {
+      result[i] = elementAt(i);
+    }
+    return result;
+  }
+
+  Set<E> toSet() {
+    Set<E> result = new Set<E>();
+    for (int i = 0; i < length; i++) {
+      result.add(elementAt(i));
+    }
+    return result;
+  }
+}
+
+abstract class SubListIterable<E> extends ListIterable<E> {
+  final Iterable<E> _iterable;
+  final int _start;
+  /** If null, represents the length of the iterable. */
+  final int _endOrLength;
+
+  SubListIterable(this._iterable, this._start, this._endOrLength);
+
+  int get _endIndex {
+    int length = _iterable.length;
+    if (_endOrLength == null || _endOrLength > length) return length;
+    return _endOrLength;
+  }
+
+  int get _startIndex {
+    int length = _iterable.length;
+    if (_start > length) return length;
+    return _start;
+  }
+
+  int get length {
+    int length = _iterable.length;
+    if (_start >= length) return 0;
+    if (_endOrLength == null || _endOrLength >= length) {
+      return length - _start;
+    }
+    return _endOrLength - _start;
+  }
+
+  E elementAt(int index) {
+    int realIndex = _startIndex + index;
+    if (index < 0 || realIndex >= _endIndex) {
+      throw new RangeError.range(index, 0, length);
+    }
+    return _iterable.elementAt(realIndex);
+  }
+
+  Iterable<E> skip(int count) {
+    if (count < 0) throw new ArgumentError(count);
+    return new SubListIterable(_iterable, _start + count, _endOrLength);
+  }
+
+  Iterable<E> take(int count) {
+    if (count < 0) throw new ArgumentError(count);
+    if (_endOrLength == null) {
+      return new SubListIterable(_iterable, _start, _start + count);
+    } else {
+      newEnd = _start + count;
+      if (_endOrLength < newEnd) return this;
+      return new SubListIterable(_iterable, _start, newEnd);
+    }
+  }
+}
+
+class ListIterableIterator<E> implements Iterator<E> {
+  final Iterable<E> _iterable;
+  final int _length;
+  int _index;
+  E _current;
+  ListIterableIterator(Iterable<E> iterable)
+      : _iterable = iterable, _length = iterable.length, _index = 0;
+
+  E get current => _current;
+
+  bool moveNext() {
+    if (_length != _iterable.length) {
+      throw new ConcurrentModificationError(_iterable);
+    }
+    if (_index == _length) {
+      _current = null;
+      return false;
+    }
+    _current = _iterable.elementAt(_index);
+    _index++;
+    return true;
+  }
+}
+
 typedef T _Transformation<S, T>(S value);
 
 class MappedIterable<S, T> extends Iterable<T> {
diff --git a/sdk/lib/_internal/compiler/implementation/apiimpl.dart b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
index 663e003..c9759f3 100644
--- a/sdk/lib/_internal/compiler/implementation/apiimpl.dart
+++ b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
@@ -134,7 +134,7 @@
    * Reads the script designated by [readableUri].
    */
   leg.Script readScript(Uri readableUri, [tree.Node node]) {
-    if (!readableUri.isAbsolute()) {
+    if (!readableUri.isAbsolute) {
       internalError('Relative uri $readableUri provided to readScript(Uri)',
                     node: node);
     }
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 71c3860..adf2a77 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -650,13 +650,13 @@
     if (analyzeOnly) return;
     assert(main != null);
 
-    log('Inferring types...');
-    typesTask.onResolutionComplete(main);
-
     // TODO(ahe): Remove this line. Eventually, enqueuer.resolution
     // should know this.
     world.populate();
 
+    log('Inferring types...');
+    typesTask.onResolutionComplete(main);
+
     log('Compiling...');
     phase = PHASE_COMPILING;
     // TODO(johnniwinther): Move these to [CodegenEnqueuer].
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 6a3b000..45a6523 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -360,10 +360,9 @@
         classMembers[enclosingClass].add(element);
         processElement(element, elementAst);
       } else {
-        if (!element.isTopLevel()) {
-          compiler.cancel('Cannot process $element', element: element);
+        if (element.isTopLevel()) {
+          addTopLevel(element, elementAst);
         }
-        addTopLevel(element, elementAst);
       }
     });
 
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
index d184663..669aa02 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -579,6 +579,12 @@
     }
   }
 
+  visitNamedMixinApplication(NamedMixinApplication node) {
+    ClassElement classElement = currentElement;
+    makeElementPlaceholder(node.name, classElement);
+    node.visitChildren(this);
+  }
+
   bool tryResolveAndCollectTypeVariable(
       TypeDeclarationElement typeDeclaration, Identifier name) {
     // Hack for case when interface and default class are in different
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 0a06ad4..312b35b 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -612,6 +612,13 @@
   void set type(DartType value);
 }
 
+/**
+ * A synthetic element which holds a getter and/or a setter.
+ *
+ * This element unifies handling of fields and getters/setters.  When
+ * looking at code like "foo.x", we don't have to look for both a
+ * field named "x", a getter named "x", and a setter named "x=".
+ */
 abstract class AbstractFieldElement extends Element {
   FunctionElement get getter;
   FunctionElement get setter;
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
index fa5677f..c15fcae 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
@@ -235,22 +235,22 @@
 
   bool operator <(num other) {
     if (other is !num) throw new ArgumentError(other);
-    return JS('num', '# < #', this, other);
+    return JS('bool', '# < #', this, other);
   }
 
   bool operator >(num other) {
     if (other is !num) throw new ArgumentError(other);
-    return JS('num', '# > #', this, other);
+    return JS('bool', '# > #', this, other);
   }
 
   bool operator <=(num other) {
     if (other is !num) throw new ArgumentError(other);
-    return JS('num', '# <= #', this, other);
+    return JS('bool', '# <= #', this, other);
   }
 
   bool operator >=(num other) {
     if (other is !num) throw new ArgumentError(other);
-    return JS('num', '# >= #', this, other);
+    return JS('bool', '# >= #', this, other);
   }
 }
 
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_string.dart b/sdk/lib/_internal/compiler/implementation/lib/js_string.dart
index dcb5b4e..6d81f32 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_string.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_string.dart
@@ -149,9 +149,7 @@
     return result;
   }
 
-  Iterable<int> get codeUnits {
-    throw new UnimplementedError("String.codeUnits");
-  }
+  Iterable<int> get codeUnits => new CodeUnits(this);
 
   Runes get runes => new Runes(this);
 
diff --git a/sdk/lib/_internal/compiler/implementation/library_loader.dart b/sdk/lib/_internal/compiler/implementation/library_loader.dart
index 074cece..e5854b5 100644
--- a/sdk/lib/_internal/compiler/implementation/library_loader.dart
+++ b/sdk/lib/_internal/compiler/implementation/library_loader.dart
@@ -358,7 +358,7 @@
    * used as is, any URI resolution should be done beforehand.
    */
   void scanPart(Part part, Uri resolvedUri, LibraryElement library) {
-    if (!resolvedUri.isAbsolute()) throw new ArgumentError(resolvedUri);
+    if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri);
     Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part);
     Script sourceScript = compiler.readScript(readableUri, part);
     CompilationUnitElement unit =
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index e62aa70..c13a959 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -1837,6 +1837,9 @@
     FunctionElement function = new FunctionElementX.node(
         name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
         enclosingElement);
+    // [function] and its enclosing method share the same
+    // [TreeElementMapping].
+    compiler.enqueuer.resolution.resolvedElements[function] = mapping;
     Scope oldScope = scope; // The scope is modified by [setupFunction].
     setupFunction(node, function);
     defineElement(node, function, doAddToScope: node.name != null);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 8b44913..916b4db 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -296,8 +296,7 @@
         builder.parameters[parameterElement] = parameter;
         directLocals[parameterElement] = parameter;
         parameter.guaranteedType =
-            builder.mapInferredType(
-                typesTask.getGuaranteedTypeOfElement(parameterElement));
+            builder.getGuaranteedTypeOfElement(parameterElement);
       });
     }
 
@@ -2586,24 +2585,12 @@
     HInstruction createForeignArray(String code, inputs) {
       return createForeign(code, HType.READABLE_ARRAY, inputs);
     }
-    HInstruction typeInfo;
-
-    /// Helper to create an instruction that contains the runtime value of
-    /// the type variable [variable].
-    HInstruction getTypeArgument(TypeVariableType variable) {
-      if (typeInfo == null) {
-        typeInfo = getRuntimeTypeInfo(localsHandler.readThis());
-      }
-      int intIndex = RuntimeTypeInformation.getTypeVariableIndex(variable);
-      HInstruction index = graph.addConstantInt(intIndex, constantSystem);
-      return createForeignArray('#[#]', <HInstruction>[typeInfo, index]);
-    }
 
     // Compute the representation of the type arguments, including access
     // to the runtime type information for type variables as instructions.
     HInstruction representations;
     if (type.element.isTypeVariable()) {
-      return <HInstruction>[getTypeArgument(type)];
+      return <HInstruction>[addTypeVariableReference(type)];
     } else {
       assert(type.element.isClass());
       List<HInstruction> arguments = <HInstruction>[];
@@ -2611,8 +2598,7 @@
       for (DartType argument in interface.typeArguments) {
         List<HInstruction> inputs = <HInstruction>[];
         String template = rti.getTypeRepresentation(argument, (variable) {
-          HInstruction runtimeType = getTypeArgument(variable);
-          add(runtimeType);
+          HInstruction runtimeType = addTypeVariableReference(variable);
           inputs.add(runtimeType);
         });
         HInstruction representation = createForeignArray(template, inputs);
@@ -3151,6 +3137,49 @@
   }
 
   /**
+   * Helper to create an instruction that gets the value of a type variable.
+   */
+  HInstruction addTypeVariableReference(TypeVariableType type) {
+    Element member = currentElement;
+    if (member.enclosingElement.isClosure()) {
+      ClosureClassElement closureClass = member.enclosingElement;
+      member = closureClass.methodElement;
+      member = member.getOutermostEnclosingMemberOrTopLevel();
+    }
+    if (member.isFactoryConstructor()) {
+      // The type variable is stored in a parameter of the method.
+      return localsHandler.readLocal(type.element);
+    } else if (member.isInstanceMember() ||
+               member.isGenerativeConstructor()) {
+      // The type variable is stored on the object.  Generate code to extract
+      // the type arguments from the object, substitute them as an instance
+      // of the type we are testing against (if necessary), and extract the
+      // type argument by the index of the variable in the list of type
+      // variables for that class.
+      int index = RuntimeTypeInformation.getTypeVariableIndex(type);
+      HInstruction thisObject = localsHandler.readThis();
+      String substitutionNameString =
+          backend.namer.substitutionName(member.getEnclosingClass());
+      HInstruction substitutionName = graph.addConstantString(
+          new LiteralDartString(substitutionNameString), null, constantSystem);
+      HInstruction substitution = createForeign('#[#]', HType.UNKNOWN,
+          <HInstruction>[thisObject, substitutionName]);
+      add(substitution);
+      pushInvokeHelper3(backend.getGetRuntimeTypeArgument(),
+                        thisObject,
+                        substitution,
+                        graph.addConstantInt(index, constantSystem),
+                        HType.UNKNOWN);
+      return pop();
+    } else {
+      // TODO(ngeoffray): Match the VM behavior and throw an
+      // exception at runtime.
+      compiler.cancel('Unimplemented unresolved type variable',
+                      element: type.element);
+    }
+  }
+
+  /**
    * Documentation wanted -- johnniwinther
    *
    * Invariant: [argument] must not be malformed in checked mode.
@@ -3164,54 +3193,12 @@
       return graph.addConstantNull(constantSystem);
     }
 
-    // The inputs are shared between invocations of the helper.
     List<HInstruction> inputs = <HInstruction>[];
 
-    /**
-     * Helper to create an instruction that gets the value of a type variable.
-     */
-    String addTypeVariableReference(TypeVariableType type) {
-      Element member = currentElement;
-      if (member.enclosingElement.isClosure()) {
-        ClosureClassElement closureClass = member.enclosingElement;
-        member = closureClass.methodElement;
-        member = member.getOutermostEnclosingMemberOrTopLevel();
-      }
-      if (member.isFactoryConstructor()) {
-        // The type variable is stored in a parameter of the method.
-        inputs.add(localsHandler.readLocal(type.element));
-      } else if (member.isInstanceMember() ||
-                 member.isGenerativeConstructor()) {
-        // The type variable is stored on the object.  Generate code to extract
-        // the type arguments from the object, substitute them as an instance
-        // of the type we are testing against (if necessary), and extract the
-        // type argument by the index of the variable in the list of type
-        // variables for that class.
-        int index = RuntimeTypeInformation.getTypeVariableIndex(type);
-        HInstruction thisObject = localsHandler.readThis();
-        String substitutionNameString =
-            backend.namer.substitutionName(member.getEnclosingClass());
-        HInstruction substitutionName = graph.addConstantString(
-            new LiteralDartString(substitutionNameString), null, constantSystem);
-        HInstruction substitution = createForeign('#[#]', HType.UNKNOWN,
-            <HInstruction>[thisObject, substitutionName]);
-        add(substitution);
-        pushInvokeHelper3(backend.getGetRuntimeTypeArgument(),
-                          thisObject,
-                          substitution,
-                          graph.addConstantInt(index, constantSystem),
-                          HType.UNKNOWN);
-        inputs.add(pop());
-      } else {
-        // TODO(ngeoffray): Match the VM behavior and throw an
-        // exception at runtime.
-        compiler.cancel('Unimplemented unresolved type variable',
-                        node: currentNode);
-      }
-    }
+    String template = rti.getTypeRepresentation(argument, (variable) {
+      inputs.add(addTypeVariableReference(variable));
+    });
 
-    String template = rti.getTypeRepresentation(argument,
-                                                addTypeVariableReference);
     HInstruction result = createForeign(template, HType.STRING, inputs);
     add(result);
     return result;
@@ -3376,11 +3363,14 @@
       }
 
       HInvokeStatic instruction = new HInvokeStatic(inputs, HType.UNKNOWN);
-      // TODO(ngeoffray): Only do this if knowing the return type is
-      // useful.
-      HType returnType =
-          builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange(
-              currentElement, element);
+      HType returnType = getGuaranteedTypeOfElement(element);
+      if (returnType.isUnknown()) {
+        // TODO(ngeoffray): Only do this if knowing the return type is
+        // useful.
+        returnType =
+            builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange(
+                currentElement, element);
+      }
       if (returnType != null) instruction.guaranteedType = returnType;
       pushWithPosition(instruction, node);
     } else {
@@ -3572,7 +3562,14 @@
     }
     inputs.add(receiver);
     inputs.addAll(arguments);
-    return new HInvokeDynamicMethod(selector, inputs, isIntercepted);
+    HInstruction invoke = new HInvokeDynamicMethod(
+        selector, inputs, isIntercepted);
+    HType returnType = mapInferredType(
+        compiler.typesTask.getGuaranteedTypeOfNode(work.element, node));
+    if (returnType != null) {
+      invoke.guaranteedType = returnType;
+    }
+    return invoke;
   }
 
   visitSendSet(SendSet node) {
@@ -4656,10 +4653,15 @@
     for (BaseType baseType in concreteType.baseTypes) {
       ssaType = ssaType.union(mapBaseType(baseType), compiler);
     }
-    assert(!ssaType.isConflicting());
+    if (ssaType.isConflicting()) return HType.UNKNOWN;
     return ssaType;
   }
 
+  HType getGuaranteedTypeOfElement(Element element) {
+    return mapInferredType(
+        compiler.typesTask.getGuaranteedTypeOfElement(element));
+  }
+
   // [type] is either an instance of [DartType] or special objects
   // like [native.SpecialType.JsObject], or [native.SpecialType.JsArray].
   HType mapNativeType(type) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index d9407c0..def1a12 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -1528,6 +1528,30 @@
         } else if (target == backend.jsStringConcat) {
           push(new js.Binary('+', object, arguments[0]), node);
           return;
+        } else if (target.isNative()
+                   && !compiler.enableTypeAssertions
+                   && target.isFunction()) {
+          // Enable direct calls to a native method only if we don't
+          // run in checked mode, where the Dart version may have
+          // type annotations on parameters and return type that it
+          // should check.
+          // Also check that the parameters are not functions: it's
+          // the callee that will translate them to JS functions.
+          // TODO(ngeoffray): There are some cases where we could
+          // still inline in checked mode if we know the arguments
+          // have the right type. And we could do the closure
+          // conversion as well as the return type annotation check.
+          bool canInlineNativeCall = true;
+          FunctionElement function = target;
+          function.computeSignature(compiler).forEachParameter((Element element) {
+            DartType type = element.computeType(compiler).unalias(compiler);
+            if (type is FunctionType) {
+              canInlineNativeCall = false;
+            }
+          });
+          if (canInlineNativeCall) {
+            methodName = target.fixedBackendName();
+          }
         }
       }
     }
@@ -1617,6 +1641,7 @@
     if (target != null) {
       // If we know we're calling a specific method, register that
       // method only.
+      assert(selector.typeKind != TypedSelectorKind.UNKNOWN);
       world.registerDynamicInvocationOf(target, selector);
     } else {
       SourceString name = node.selector.name;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 5d7a29c..4d83538 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -1369,7 +1369,8 @@
   }
 
   HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
-    return specializer.computeTypeFromInputTypes(this, types, compiler);
+    HType type = specializer.computeTypeFromInputTypes(this, types, compiler);
+    return type.isUnknown() ? guaranteedType : type;
   }
 }
 
@@ -1671,6 +1672,9 @@
 abstract class HBinaryBitOp extends HBinaryArithmetic {
   HBinaryBitOp(HInstruction left, HInstruction right) : super(left, right);
   HType get guaranteedType => HType.INTEGER;
+  HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
+    return guaranteedType;
+  }
 }
 
 class HShiftLeft extends HBinaryBitOp {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index 0166ac0..1b2ae05 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -58,7 +58,7 @@
           // Previous optimizations may have generated new
           // opportunities for constant folding.
           new SsaConstantFolder(constantSystem, backend, work, types),
-          new SsaSimplifyInterceptors(constantSystem),
+          new SsaSimplifyInterceptors(constantSystem, types),
           new SsaDeadCodeEliminator(types)];
       runPhases(graph, phases);
       if (!speculative) {
@@ -150,8 +150,10 @@
 
         // If we can replace [instruction] with [replacement], then
         // [replacement]'s type can be narrowed.
-        types[replacement] =
-            types[replacement].intersection(types[instruction], compiler);
+        types[replacement] = types[replacement].intersection(
+            types[instruction], compiler);
+        replacement.guaranteedType = replacement.guaranteedType.intersection(
+            instruction.guaranteedType, compiler);
 
         // If the replacement instruction does not know its
         // source element, use the source element of the
@@ -258,9 +260,6 @@
   }
 
   HInstruction handleInterceptorCall(HInvokeDynamic node) {
-    // We only optimize for intercepted method calls in this method.
-    Selector selector = node.selector;
-
     // Try constant folding the instruction.
     Operation operation = node.specializer.operation(constantSystem);
     if (operation != null) {
@@ -275,17 +274,22 @@
         node.specializer.tryConvertToBuiltin(node, types);
     if (instruction != null) return instruction;
 
-    // Check if this call does not need to be intercepted.
-    HInstruction input = node.inputs[1];
-    HType type = types[input];
+    Selector selector = node.selector;
     var interceptor = node.inputs[0];
 
-    if (interceptor.isConstant() && selector.isCall()) {
+    // If the intercepted call is through a constant interceptor, we
+    // know which element to call.
+    if (node is !HOneShotInterceptor
+        && interceptor.isConstant()
+        && selector.isCall()) {
       DartType type = types[interceptor].computeType(compiler);
       ClassElement cls = type.element;
       node.element = cls.lookupSelector(selector);
     }
 
+    HInstruction input = node.inputs[1];
+    HType type = types[input];
+    // Check if this call does not need to be intercepted.
     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.
@@ -385,19 +389,16 @@
   HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
     if (node.isInterceptorCall) return handleInterceptorCall(node);
     HType receiverType = types[node.receiver];
-    if (receiverType.isExact()) {
-      Element element = receiverType.lookupMember(node.selector.name, compiler);
-      // TODO(ngeoffray): Also fold if it's a getter or variable.
-      if (element != null && element.isFunction()) {
-        if (node.selector.applies(element, compiler)) {
-          FunctionElement method = element;
-          FunctionSignature parameters = method.computeSignature(compiler);
-          if (parameters.optionalParameterCount == 0) {
-            node.element = element;
-          }
-          // TODO(ngeoffray): If the method has optional parameters,
-          // we should pass the default values here.
-        }
+    Element element = receiverType.lookupSingleTarget(node.selector, compiler);
+    // TODO(ngeoffray): Also fold if it's a getter or variable.
+    if (element != null && element.isFunction()) {
+      FunctionElement method = element;
+      FunctionSignature parameters = method.computeSignature(compiler);
+      // TODO(ngeoffray): If the method has optional parameters,
+      // we should pass the default values.
+      if (parameters.optionalParameterCount == 0
+          || parameters.parameterCount == node.selector.argumentCount) {
+        node.element = element;
       }
     }
     return node;
@@ -599,9 +600,9 @@
                                             Selector selector) {
     HType receiverType = types[receiver];
     if (!receiverType.isUseful()) return null;
-    if (receiverType.canBeNull()) return null;
     DartType type = receiverType.computeType(compiler);
     if (type == null) return null;
+    if (Elements.isErroneousElement(type.element)) return null;
     return compiler.world.locateSingleField(type, selector);
   }
 
@@ -635,11 +636,17 @@
     }
     HFieldGet result = new HFieldGet(
         field, node.inputs[0], isAssignable: !isFinalOrConst);
-    HType type = backend.optimisticFieldType(field);
-    if (type != null) {
-      result.guaranteedType = type;
-      backend.registerFieldTypesOptimization(
-          work.element, field, result.guaranteedType);
+
+    if (field.getEnclosingClass().isNative()) {
+      result.guaranteedType =
+          new HType.subtype(field.computeType(compiler), compiler);
+    } else {
+      HType type = backend.optimisticFieldType(field);
+      if (type != null) {
+        backend.registerFieldTypesOptimization(
+            work.element, field, result.guaranteedType);
+        result.guaranteedType = type;
+      }
     }
     return result;
   }
@@ -1502,9 +1509,10 @@
     implements OptimizationPhase {
   final String name = "SsaSimplifyInterceptors";
   final ConstantSystem constantSystem;
+  final HTypeMap types;
   HGraph graph;
 
-  SsaSimplifyInterceptors(this.constantSystem);
+  SsaSimplifyInterceptors(this.constantSystem, this.types);
 
   void visitGraph(HGraph graph) {
     this.graph = graph;
@@ -1531,6 +1539,8 @@
         user.selector, inputs, node.interceptedClasses);
     interceptor.sourcePosition = user.sourcePosition;
     interceptor.sourceElement = user.sourceElement;
+    interceptor.guaranteedType = user.guaranteedType;
+    types[interceptor] = types[user];
 
     HBasicBlock block = user.block;
     block.addAfter(user, interceptor);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index 3e01f1a..8b55c23 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -26,18 +26,28 @@
           isInterfaceType: isInterfaceType);
     }
 
-    if (element == compiler.intClass) {
+    JavaScriptBackend backend = compiler.backend;
+    if (element == compiler.intClass || element == backend.jsIntClass) {
       return canBeNull ? HType.INTEGER_OR_NULL : HType.INTEGER;
-    } else if (element == compiler.numClass) {
+    } else if (element == compiler.numClass 
+               || element == backend.jsNumberClass) {
       return canBeNull ? HType.NUMBER_OR_NULL : HType.NUMBER;
-    } else if (element == compiler.doubleClass) {
+    } else if (element == compiler.doubleClass
+               || element == backend.jsDoubleClass) {
       return canBeNull ? HType.DOUBLE_OR_NULL : HType.DOUBLE;
-    } else if (element == compiler.stringClass) {
+    } else if (element == compiler.stringClass
+               || element == backend.jsStringClass) {
       return canBeNull ? HType.STRING_OR_NULL : HType.STRING;
-    } else if (element == compiler.boolClass) {
+    } else if (element == compiler.boolClass
+               || element == backend.jsBoolClass) {
       return canBeNull ? HType.BOOLEAN_OR_NULL : HType.BOOLEAN;
-    } else if (element == compiler.nullClass) {
+    } else if (element == compiler.nullClass
+               || element == backend.jsNullClass) {
       return HType.NULL;
+    } else if (element == backend.jsArrayClass) {
+      return canBeNull
+          ? HType.READABLE_ARRAY.union(HType.NULL, compiler)
+          : HType.READABLE_ARRAY;
     } else if (!isExact) {
       if (element == compiler.listClass
           || Elements.isListSupertype(element, compiler)) {
@@ -55,7 +65,8 @@
             type,
             canBeNull: canBeNull,
             isInterfaceType: isInterfaceType);
-      } else if (element == compiler.objectClass) {
+      } else if (element == compiler.objectClass
+                 || element == compiler.dynamicClass) {
         return new HBoundedPotentialPrimitiveType(
             compiler.objectClass.computeType(compiler),
             true,
@@ -158,12 +169,23 @@
   /** Alias for isReadableArray. */
   bool isArray() => isReadableArray();
 
-  Element lookupMember(SourceString name, Compiler compiler) {
-    if (!isExact()) return null;
+  Element lookupSingleTarget(Selector selector, Compiler compiler) {
+    if (isInterfaceType()) return null;
     DartType type = computeType(compiler);
     if (type == null) return null;
     ClassElement cls = type.element;
-    return cls.lookupMember(name);
+    Element member = cls.lookupSelector(selector);
+    if (member == null) return null;
+    // [:ClassElement.lookupSelector:] may return an abstract field,
+    // and selctors don't work well with them.
+    // TODO(ngeoffray): Clean up lookupSelector and selectors to know
+    // if it's a getter or a setter that we're interested in.
+    if (!member.isFunction()) return null;
+    if (!selector.applies(member, compiler)) return null;
+    if (!isExact() && !compiler.world.hasNoOverridingMember(member)) {
+      return null;
+    }
+    return member;
   }
 
   DartType computeType(Compiler compiler);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
index ee0f1a1..223e017 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
@@ -20,7 +20,6 @@
         pendingOptimizations = new Map<HInstruction, Function>();
 
   HType computeType(HInstruction instruction) {
-    if (instruction.hasGuaranteedType()) return instruction.guaranteedType;
     return instruction.computeTypeFromInputTypes(types, compiler);
   }
 
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
index c28d5c4..7ea24ed 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
@@ -647,6 +647,8 @@
     HInstruction next = check.next;
     Range indexRange = ranges[check.index];
     Range lengthRange = ranges[check.length];
+    assert(check.index.isInteger(types));
+    assert(check.length.isInteger(types));
 
     // Check if the index is strictly below the upper bound of the length
     // range.
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index 6c05203..f268488 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -86,7 +86,7 @@
    */
   factory ConcreteType.singleton(int maxConcreteTypeSize, BaseType baseType) {
     if (baseType.isUnknown() || maxConcreteTypeSize < 1) {
-      return new UnknownConcreteType();
+      return const UnknownConcreteType();
     }
     Set<BaseType> singletonSet = new Set<BaseType>();
     singletonSet.add(baseType);
@@ -391,7 +391,7 @@
  * A task which conservatively infers a [ConcreteType] for each sub expression
  * of the program. The entry point is [analyzeMain].
  */
-class ConcreteTypesInferrer {
+class ConcreteTypesInferrer extends TypesInferrer {
   static final bool LOG_FAILURES = true;
 
   final String name = "Type inferrer";
@@ -686,13 +686,16 @@
   /**
    * Get the inferred concrete type of [node].
    */
-  ConcreteType getConcreteTypeOfNode(Node node) => inferredTypes[node];
+  ConcreteType getConcreteTypeOfNode(Element owner, Node node) {
+    return inferredTypes[node];
+  }
 
   /**
-   * Get the inferred concrete type of [parameter].
+   * Get the inferred concrete type of [element].
    */
-  ConcreteType getConcreteTypeOfParameter(VariableElement parameter) {
-    return inferredParameterTypes[parameter];
+  ConcreteType getConcreteTypeOfElement(Element element) {
+    if (!element.isParameter()) return null;
+    return inferredParameterTypes[element];
   }
 
   // --- analysis ---
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
new file mode 100644
index 0000000..e4a16b0
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -0,0 +1,779 @@
+// 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 simple_types_inferrer;
+
+import '../native_handler.dart' as native;
+import '../elements/elements.dart';
+import '../dart2jslib.dart';
+import '../tree/tree.dart';
+import '../util/util.dart' show Link;
+import 'types.dart' show TypesInferrer, ConcreteType, ClassBaseType;
+
+/**
+ * A work queue that ensures there are no duplicates, and adds and
+ * removes in LIFO.
+ */
+class WorkSet<E extends Element> {
+  final List<E> queue = new List<E>();
+  final Set<E> elementsInQueue = new Set<E>();
+  
+  void add(E element) {
+    element = element.implementation;
+    if (elementsInQueue.contains(element)) return;
+    queue.addLast(element);
+    elementsInQueue.add(element);
+  }
+
+  E remove() {
+    E element = queue.removeLast();
+    elementsInQueue.remove(element);
+    return element;
+  }
+
+  bool get isEmpty => queue.isEmpty;
+}
+
+class SimpleTypesInferrer extends TypesInferrer {
+  /**
+   * Maps an element to its callers.
+   */
+  final Map<Element, Set<Element>> callersOf =
+      new Map<Element, Set<Element>>();
+
+  /**
+   * Maps an element to its return type.
+   */
+  final Map<Element, Element> returnTypeOf =
+      new Map<Element, Element>();
+
+  /**
+   * Maps a name to elements in the universe that have that name.
+   */
+  final Map<SourceString, Set<Element>> methodCache =
+      new Map<SourceString, Set<Element>>();
+
+  /**
+   * Maps an element to the number of times this type inferrer
+   * analyzed it.
+   */
+  final Map<Element, int> analyzeCount = new Map<Element, int>();
+
+  /**
+   * The work list of the inferrer.
+   */
+  final WorkSet<Element> workSet = new WorkSet<Element>();
+
+  /**
+   * Heuristic for avoiding too many re-analysis of an element.
+   */
+  final int MAX_ANALYSIS_COUNT_PER_ELEMENT = 5;
+
+  /**
+   * Sentinal used by the inferrer to notify that it gave up finding a type
+   * on a specific element.
+   */
+  Element giveUpType;
+
+  final Compiler compiler;
+
+  // Times the computation of the call graph.
+  final Stopwatch memberWatch = new Stopwatch();
+  // Times the computation of re-analysis of methods.
+  final Stopwatch recomputeWatch = new Stopwatch();
+  // Number of re-analysis.
+  int recompiles = 0;
+
+  SimpleTypesInferrer(this.compiler);
+
+  /**
+   * Main entry point of the inferrer. Analyzes all elements that the
+   * resolver found as reachable. Returns whether it succeeded.
+   */
+  bool analyzeMain(Element element) {
+    // We use the given element as the sentinel. This is a temporary
+    // situation as long as this inferrer is using [ClassElement] for
+    // expressing types.
+    giveUpType = element;
+    buildWorkQueue();
+    int analyzed = 0;
+    compiler.progress.reset();
+    do {
+      if (compiler.progress.elapsedMilliseconds > 500) {
+        compiler.log('Inferred $analyzed methods.');
+        compiler.progress.reset();
+      }
+      element = workSet.remove();
+      if (element.isErroneous()) continue;
+
+      bool wasAnalyzed = analyzeCount.containsKey(element);
+      if (wasAnalyzed) {
+        recompiles++;
+        recomputeWatch.start();
+      }
+      bool changed = analyze(element);
+      analyzed++;
+      if (wasAnalyzed) {
+        recomputeWatch.stop();
+      }
+      if (!changed) continue;
+      // If something changed during the analysis of [element],
+      // put back callers of it in the work list.
+      Set<Element> methodCallers = callersOf[element];
+      if (methodCallers != null) {
+        methodCallers.forEach(enqueueAgain);
+      }
+    } while (!workSet.isEmpty);
+    dump();
+    clear();
+    return true;
+  }
+
+  /**
+   * Query method after the analysis to know the type of [element].
+   */
+  getConcreteTypeOfElement(element) {
+    return getTypeIfValuable(returnTypeOf[element]);
+  }
+
+  getTypeIfValuable(returnType) {
+    if (returnType == null
+        || returnType == compiler.dynamicClass
+        || returnType == giveUpType) {
+      return null;
+    }
+    return new ConcreteType.singleton(
+        compiler.maxConcreteTypeSize, new ClassBaseType(returnType));
+  }
+
+  /**
+   * Query method after the analysis to know the type of [node],
+   * defined in the context of [owner].
+   */
+  getConcreteTypeOfNode(Element owner, Node node) {
+    var elements = compiler.enqueuer.resolution.resolvedElements[owner];
+    Selector selector = elements.getSelector(node);
+    // TODO(ngeoffray): Should the builder call this method with a
+    // SendSet?
+    if (selector == null || selector.isSetter() || selector.isIndexSet()) {
+      return null;
+    }
+    return getTypeIfValuable(returnTypeOfSelector(selector));
+  }
+
+  /**
+   * Enqueues [e] in the work queue if it is valuable.
+   */
+  void enqueueAgain(Element e) {
+    Element returnType = returnTypeOf[e];
+    // If we have found a type for [e], no need to re-analyze it.
+    if (returnType != compiler.dynamicClass) return;
+    if (analyzeCount[e] > MAX_ANALYSIS_COUNT_PER_ELEMENT) return;
+    workSet.add(e);
+  }
+
+  /**
+   * Builds the initial work queue by adding all resolved elements in
+   * the work queue, ordered by the number of selectors they use. This
+   * order is benficial for the analysis of return types, but we may
+   * have to refine it once we analyze parameter types too.
+   */
+  void buildWorkQueue() {
+    int max = 0;
+    Map<int, Set<Element>> methodSizes = new Map<int, Set<Element>>();
+    compiler.enqueuer.resolution.resolvedElements.forEach(
+      (Element element, TreeElementMapping mapping) {
+        // TODO(ngeoffray): Not sure why the resolver would put a null
+        // mapping.
+        if (mapping == null) return;
+        if (element.isAbstract(compiler)) return;
+        int length = mapping.selectors.length;
+        max = length > max ? length : max;
+        Set<Element> set = methodSizes.putIfAbsent(
+            length, () => new Set<Element>());
+        set.add(element);
+    });
+    
+    // This iteration assumes the [WorkSet] is LIFO.
+    for (int i = max; i >= 0; i--) {
+      Set<Element> set = methodSizes[i];
+      if (set != null) {
+        set.forEach((e) { workSet.add(e); });
+      }
+    }
+  }
+
+  dump() {
+    int interestingTypes = 0;
+    int giveUpTypes = 0;
+    returnTypeOf.forEach((Element method, Element type) {
+      if (type == giveUpType) {
+        giveUpTypes++;
+      } else if (type != compiler.nullClass && type != compiler.dynamicClass) {
+        interestingTypes++;
+      }
+    });
+    compiler.log('Type inferrer spent ${memberWatch.elapsedMilliseconds} ms '
+                 'computing a call graph.');
+    compiler.log('Type inferrer re-analyzed methods $recompiles times '
+                 'in ${recomputeWatch.elapsedMilliseconds} ms.');
+    compiler.log('Type inferrer found $interestingTypes interesting '
+                 'return types and gave up on $giveUpTypes methods.');
+  }
+
+  /**
+   * Clear data structures that are not used after the analysis.
+   */
+  void clear() {
+    callersOf.clear();
+    analyzeCount.clear();
+  }
+
+  bool analyze(Element element) {
+    if (element.isField()) {
+      // TODO(ngeoffray): Analyze its initializer.
+      return false;
+    } else {
+      SimpleTypeInferrerVisitor visitor =
+          new SimpleTypeInferrerVisitor(element, compiler, this);
+      return visitor.run();
+    }
+  }
+
+  /**
+   * Records [returnType] as the return type of [analyzedElement].
+   * Returns whether the new type is worth recompiling the callers of
+   * [analyzedElement].
+   */
+  bool recordReturnType(analyzedElement, returnType) {
+    assert(returnType != null);
+    Element existing = returnTypeOf[analyzedElement];
+    if (existing == null) {
+      // First time we analyzed [analyzedElement]. Initialize the
+      // return type.
+      assert(!analyzeCount.containsKey(analyzedElement));
+      returnTypeOf[analyzedElement] = returnType;
+      // If the return type is useful, say it has changed.
+      return returnType != compiler.dynamicClass
+          && returnType != compiler.nullClass;
+    } else if (existing == compiler.dynamicClass) {
+      // Previous analysis did not find any type.
+      returnTypeOf[analyzedElement] = returnType;
+      // If the return type is useful, say it has changed.
+      return returnType != compiler.dynamicClass
+          && returnType != compiler.nullClass;
+    } else if (existing == giveUpType) {
+      // If we already gave up on the return type, we don't change it.
+      return false;
+    } else if (existing != returnType) {
+      // The method is returning two different types. Give up for now.
+      // TODO(ngeoffray): Compute LUB.
+      returnTypeOf[analyzedElement] = giveUpType;
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Returns the return type of [element]. Returns [:Dynamic:] if
+   * [element] has not been analyzed yet.
+   */
+  ClassElement returnTypeOfElement(Element element) {
+    element = element.implementation;
+    if (element.isGenerativeConstructor()) return element.getEnclosingClass();
+    Element returnType = returnTypeOf[element];
+    if (returnType == null || returnType == giveUpType) {
+      return compiler.dynamicClass;
+    }
+    return returnType;
+  }
+
+  /**
+   * Returns the union of the return types of all elements that match
+   * the called [selector].
+   */
+  ClassElement returnTypeOfSelector(Selector selector) {
+    ClassElement result;
+    iterateOverElements(selector, (Element element) {
+      assert(element.isImplementation);
+      Element cls;
+      if (element.isFunction() && selector.isGetter()) {
+        cls = compiler.functionClass;
+      } else {
+        cls = returnTypeOf[element];
+      }
+      if (cls == null
+          || cls == compiler.dynamicClass
+          || cls == giveUpType
+          || (cls != result && result != null)) {
+        result = compiler.dynamicClass;
+        return false;
+      } else {
+        result = cls;
+        return true;
+      }
+    });
+    return result;
+  }
+
+  /**
+   * Registers that [caller] calls [callee] with the given
+   * [arguments].
+   */
+  void registerCalledElement(Element caller,
+                             Element callee,
+                             ArgumentsTypes arguments) {
+    if (analyzeCount.containsKey(caller)) return;
+    callee = callee.implementation;
+    Set<FunctionElement> callers = callersOf.putIfAbsent(
+        callee, () => new Set<FunctionElement>());
+    callers.add(caller);
+  }
+
+  /**
+   * Registers that [caller] accesses [callee] through a property
+   * access.
+   */
+  void registerGetterOnElement(Element caller,
+                               Element callee) {
+    if (analyzeCount.containsKey(caller)) return;
+    callee = callee.implementation;
+    Set<FunctionElement> callers = callersOf.putIfAbsent(
+        callee, () => new Set<FunctionElement>());
+    callers.add(caller);
+  }
+
+  /**
+   * Registers that [caller] calls an element matching [selector]
+   * with the given [arguments].
+   */
+  void registerCalledSelector(Element caller,
+                              Selector selector,
+                              ArgumentsTypes arguments) {
+    if (analyzeCount.containsKey(caller)) return;
+    iterateOverElements(selector, (Element element) {
+      assert(element.isImplementation);
+      Set<FunctionElement> callers = callersOf.putIfAbsent(
+          element, () => new Set<FunctionElement>());
+      callers.add(caller);
+      return true;
+    });
+  }
+
+  /**
+   * Registers that [caller] accesses an element matching [selector]
+   * through a property access.
+   */
+  void registerGetterOnSelector(Element caller, Selector selector) {
+    if (analyzeCount.containsKey(caller)) return;
+    iterateOverElements(selector, (Element element) {
+      assert(element.isImplementation);
+      Set<FunctionElement> callers = callersOf.putIfAbsent(
+          element, () => new Set<FunctionElement>());
+      callers.add(caller);
+      return true;
+    });
+  }
+
+  /**
+   * Registers that [caller] closurizes [function].
+   */
+  void registerGetFunction(Element caller, Element function) {
+    assert(caller.isImplementation);
+    if (analyzeCount.containsKey(caller)) return;
+    // We don't register that [caller] calls [function] because we
+    // don't know if the code is going to call it, and if it is, then
+    // the inferrer has lost track of its identity anyway.
+  }
+
+  /**
+   * Applies [f] to all elements in the universe that match
+   * [selector]. If [f] returns false, aborts the iteration.
+   */
+  void iterateOverElements(Selector selector, bool f(Element element)) {
+    SourceString name = selector.name;
+
+    // The following is already computed by the resolver, but it does
+    // not save it yet.
+    Set<Element> methods = methodCache[name];
+    if (methods == null) {
+      memberWatch.start();
+      methods = new Set<Element>();
+      void add(element) {
+        if (!element.isInstanceMember()) return;
+        if (element.isAbstract(compiler)) return;
+        if (!compiler.enqueuer.resolution.isProcessed(element)) return;
+        methods.add(element.implementation);
+      }
+      for (ClassElement cls in compiler.enqueuer.resolution.seenClasses) {
+        var element = cls.lookupLocalMember(name);
+        if (element != null) {
+          if (element.isAbstractField()) {
+            if (element.getter != null) add(element.getter);
+            if (element.setter != null) add(element.setter);
+          } else {
+            add(element);
+          }
+        }
+      }
+      methodCache[name] = methods;
+      memberWatch.stop();
+    }
+
+    for (Element element in methods) {
+      if (selector.appliesUnnamed(element, compiler)) {
+        if (!f(element)) return;
+      }
+    }
+  }
+}
+
+/**
+ * Placeholder for inferred arguments types on sends.
+ */
+class ArgumentsTypes {
+  final List<Element> positional;
+  final Map<Identifier, Element> named;
+  ArgumentsTypes(this.positional, this.named);
+  int get length => positional.length + named.length;
+  toString() => "{ positional = $positional, named = $named }";
+}
+
+class SimpleTypeInferrerVisitor extends ResolvedVisitor {
+  final FunctionElement analyzedElement;
+  final SimpleTypesInferrer inferrer;
+  final Compiler compiler;
+  Element returnType;
+
+  SimpleTypeInferrerVisitor(FunctionElement element,
+                            Compiler compiler,
+                            this.inferrer)
+    : super(compiler.enqueuer.resolution.resolvedElements[element.declaration]),
+      analyzedElement = element,
+      compiler = compiler {
+    assert(elements != null);
+  }
+
+  bool run() {
+    FunctionExpression node =
+        analyzedElement.implementation.parseNode(compiler);
+    bool changed;
+    if (analyzedElement.isGenerativeConstructor()) {
+      FunctionSignature signature = analyzedElement.computeSignature(compiler);
+      // TODO(ngeoffray): handle initializing formals.
+      // TODO(ngeoffray): handle initializers.
+      node.body.accept(this);
+      // We always know the return type of a generative constructor.
+      changed = false;
+    } else if (analyzedElement.isNative()) {
+      // Native methods do not have a body, and we currently just say
+      // they return dynamic.
+      inferrer.recordReturnType(analyzedElement, compiler.dynamicClass);
+      changed = false;
+    } else {
+      node.body.accept(this);
+      if (returnType == null) {
+        // No return in the body.
+        returnType = compiler.nullClass;
+      }
+      changed = inferrer.recordReturnType(analyzedElement, returnType);
+    }
+    if (inferrer.analyzeCount.containsKey(analyzedElement)) {
+      inferrer.analyzeCount[analyzedElement]++;
+    } else {
+      inferrer.analyzeCount[analyzedElement] = 1;
+    }
+    return changed;
+  }
+
+  recordReturnType(ClassElement cls) {
+    if (returnType == null) {
+      returnType = cls;
+    } else if (returnType != inferrer.giveUpType
+               && cls == compiler.dynamicClass) {
+      returnType = cls;
+    } else if (returnType == compiler.dynamicClass) {
+      // Nothing to do. Stay dynamic.
+    } else if (leastUpperBound(cls, returnType) == compiler.dynamicClass) {
+      returnType = inferrer.giveUpType;
+    }
+  }
+
+  visitNode(Node node) {
+    node.visitChildren(this);
+    return compiler.dynamicClass;
+  }
+
+  visitNewExpression(NewExpression node) {
+    return node.send.accept(this);
+  }
+
+  visitFunctionExpression(FunctionExpression node) {
+    // We don't put the closure in the work queue of the
+    // inferrer, because it will share information with its enclosing
+    // method, like for example the types of local variables.
+    SimpleTypeInferrerVisitor visitor =
+        new SimpleTypeInferrerVisitor(elements[node], compiler, inferrer);
+    visitor.run();
+    return compiler.functionClass;
+  }
+
+  visitLiteralString(LiteralString node) {
+    return compiler.stringClass;
+  }
+
+  visitStringInterpolation(StringInterpolation node) {
+    return compiler.stringClass;
+  }
+
+  visitStringJuxtaposition(StringJuxtaposition node) {
+    return compiler.stringClass;
+  }
+
+  visitLiteralBool(LiteralBool node) {
+    return compiler.boolClass;
+  }
+
+  visitLiteralDouble(LiteralDouble node) {
+    return compiler.doubleClass;
+  }
+
+  visitLiteralInt(LiteralInt node) {
+    return compiler.intClass;
+  }
+
+  visitLiteralList(LiteralList node) {
+    return compiler.listClass;
+  }
+
+  visitLiteralMap(LiteralMap node) {
+    return compiler.mapClass;
+  }
+
+  visitLiteralNull(LiteralNull node) {
+    return compiler.nullClass;
+  }
+
+  visitTypeReferenceSend(Send node) {
+    return compiler.typeClass;
+  }
+
+  visitSendSet(SendSet node) {
+    // TODO(ngeoffray): return the right hand side's type.
+    node.visitChildren(this);
+    return compiler.dynamicClass;
+  }
+
+  visitIdentifier(Identifier node) {
+    if (node.isThis() || node.isSuper()) {
+      // TODO(ngeoffray): Represent subclasses.
+      return compiler.dynamicClass;
+    }
+    return compiler.dynamicClass;
+  }
+
+  visitSuperSend(Send node) {
+    Element element = elements[node];
+    if (Elements.isUnresolved(element)) {
+      return compiler.dynamicClass;
+    }
+    Selector selector = elements.getSelector(node);
+    if (node.isPropertyAccess) {
+      inferrer.registerGetterOnElement(analyzedElement, element);
+      return inferrer.returnTypeOfElement(element);
+    } else if (element.isFunction()) {
+      ArgumentsTypes arguments = analyzeArguments(node.arguments);
+      inferrer.registerCalledElement(analyzedElement, element, arguments);
+      return inferrer.returnTypeOfElement(element);
+    } else {
+      // Closure call on a getter. We don't have function types yet,
+      // so we just return [:Dynamic:].
+      return compiler.dynamicClass;
+    }
+  }
+
+  visitStaticSend(Send node) {
+    Element element = elements[node];
+    if (Elements.isUnresolved(element)) {
+      return compiler.dynamicClass;
+    }
+    if (element.isForeign(compiler)) {
+      return handleForeignSend(node);
+    }
+    ArgumentsTypes arguments = analyzeArguments(node.arguments);
+    inferrer.registerCalledElement(analyzedElement, element, arguments);
+    return inferrer.returnTypeOfElement(element);
+  }
+
+  handleForeignSend(Send node) {
+    node.visitChildren(this);
+    Selector selector = elements.getSelector(node);
+    SourceString name = selector.name;
+    if (name == const SourceString('JS')) {
+      native.NativeBehavior nativeBehavior =
+          compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
+      if (nativeBehavior == null) return compiler.dynamicClass;
+      List typesReturned = nativeBehavior.typesReturned;
+      if (typesReturned.isEmpty) return compiler.dynamicClass;
+      ClassElement returnType;
+      for (var type in typesReturned) {
+        ClassElement mappedType;
+        if (type == native.SpecialType.JsObject) {
+          mappedType = compiler.objectClass;
+        } else if (type == native.SpecialType.JsArray) {
+          mappedType = compiler.listClass;
+        } else {
+          mappedType = type.element;
+          // For primitive types, we know how to handle them here and
+          // in the backend.
+          if (mappedType != compiler.stringClass
+              && mappedType != compiler.intClass
+              && mappedType != compiler.doubleClass
+              && mappedType != compiler.boolClass
+              && mappedType != compiler.numClass) {
+            Set<ClassElement> subtypes = compiler.world.subtypes[mappedType];
+            // TODO(ngeoffray): Handle subtypes and subclasses.
+            if (subtypes != null && !subtypes.isEmpty) {
+              return compiler.dynamicClass;
+            }
+          }
+        }
+        if (returnType == null) {
+          returnType = mappedType;
+        } else {
+          return compiler.dynamicClass;
+        }
+      }
+      return returnType;
+    } else if (name == const SourceString('JS_OPERATOR_IS_PREFIX')) {
+      return compiler.stringClass;
+    } else {
+      return compiler.dynamicClass;
+    }
+  }
+
+  analyzeArguments(Link<Node> arguments) {
+    List<ClassElement> positional = [];
+    Map<Identifier, ClassElement> named = new Map<Identifier, ClassElement>();
+    for (Node argument in arguments) {
+      NamedArgument namedArgument = argument.asNamedArgument();
+      if (namedArgument != null) {
+        named[namedArgument.name] = namedArgument.expression.accept(this);
+      } else {
+        positional.add(argument.accept(this));
+      }
+    }
+    return new ArgumentsTypes(positional, named);
+  }
+
+  visitOperatorSend(Send node) {
+    Operator op = node.selector;
+    if (const SourceString("[]") == op.source) {
+      return visitDynamicSend(node);
+    } else if (const SourceString("&&") == op.source ||
+               const SourceString("||") == op.source) {
+      node.visitChildren(this);
+      return compiler.boolClass;
+    } else if (const SourceString("!") == op.source) {
+      node.visitChildren(this);
+      return compiler.boolClass;
+    } else if (const SourceString("is") == op.source) {
+      node.visitChildren(this);
+      return compiler.boolClass;
+    } else if (const SourceString("as") == op.source) {
+      node.visitChildren(this);
+      return compiler.dynamicClass;
+    } else if (node.isParameterCheck) {
+      node.visitChildren(this);
+      return compiler.boolClass;
+    } else if (node.argumentsNode is Prefix) {
+      // Unary operator.
+      return visitDynamicSend(node);
+    } else if (const SourceString('===') == op.source
+               || const SourceString('!==') == op.source) {
+      node.visitChildren(this);
+      return compiler.boolClass;
+    } else {
+      // Binary operator.
+      return visitDynamicSend(node);
+    }
+  }
+
+  // Because some nodes just visit their children, we may end up
+  // visiting a type annotation, that may contain a send in case of a
+  // prefixed type. Therefore we explicitly visit the type annotation
+  // to avoid confusing the [ResolvedVisitor].
+  visitTypeAnnotation(TypeAnnotation node) {}
+
+  visitGetterSend(Send node) {
+    Element element = elements[node];
+    if (Elements.isStaticOrTopLevelField(element)) {
+      if (element.isGetter()) {
+        inferrer.registerGetterOnElement(analyzedElement, element);
+        return inferrer.returnTypeOfElement(element);
+      } else {
+        // Nothing yet.
+        // TODO: Analyze initializer of element.
+        return compiler.dynamicClass;
+      }
+    } else if (Elements.isInstanceSend(node, elements)) {
+      ClassElement receiverType;
+      if (node.receiver == null) {
+        receiverType = analyzedElement.getEnclosingClass();
+      } else {
+        receiverType = node.receiver.accept(this);
+      }
+      Selector selector = elements.getSelector(node);
+      inferrer.registerGetterOnSelector(analyzedElement, selector);
+      return inferrer.returnTypeOfSelector(selector);
+    } else if (Elements.isStaticOrTopLevelFunction(element)) {
+      inferrer.registerGetFunction(analyzedElement, element);
+      return compiler.functionClass;
+    } else {
+      // TODO: Analyze variable.
+      return compiler.dynamicClass;
+    }
+  }
+
+  visitClosureSend(Send node) {
+    node.visitChildren(this);
+    return compiler.dynamicClass;
+  }
+
+  visitDynamicSend(Send node) {
+    ClassElement receiverType;
+    if (node.receiver == null) {
+      receiverType = analyzedElement.getEnclosingClass();
+    } else {
+      receiverType = node.receiver.accept(this);
+    }
+    ArgumentsTypes arguments = analyzeArguments(node.arguments);
+    Selector selector = elements.getSelector(node);
+    inferrer.registerCalledSelector(analyzedElement, selector, arguments);
+    return inferrer.returnTypeOfSelector(selector);
+  }
+
+  visitReturn(Return node) {
+    Node expression = node.expression;
+    recordReturnType(expression == null
+        ? compiler.nullClass
+        : expression.accept(this));
+  }
+
+  visitConditional(Conditional node) {
+    node.condition.accept(this);
+    Element firstType = node.thenExpression.accept(this);
+    Element secondType = node.elseExpression.accept(this);
+    return leastUpperBound(firstType, secondType);
+  }
+
+  leastUpperBound(Element firstType, Element secondType) {
+    if (firstType == secondType) return firstType;
+    return compiler.dynamicClass;
+  }
+
+  internalError(String reason, {Node node}) {
+    compiler.internalError(reason, node: node);
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index fdce427..345f0be 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -12,23 +12,36 @@
 import '../elements/elements.dart';
 import '../util/util.dart';
 import '../universe/universe.dart';
+import 'simple_types_inferrer.dart' show SimpleTypesInferrer;
 
 part 'concrete_types_inferrer.dart';
 
 /**
+ * Common super class for our type inferrers. Currently, its query methods
+ * return instances of [ConcreteType], but that may change in the
+ * future.
+ */
+abstract class TypesInferrer {
+  analyzeMain(Element element);
+  getConcreteTypeOfElement(Element element);
+  getConcreteTypeOfNode(Element owner, Node node);
+}
+
+/**
  * The types task infers guaranteed types globally.
  */
 class TypesTask extends CompilerTask {
   final String name = 'Type inference';
   final Set<Element> untypedElements;
   final Map<Element, Link<Element>> typedSends;
-  ConcreteTypesInferrer concreteTypesInferrer;
+  TypesInferrer typesInferrer;
 
   TypesTask(Compiler compiler)
     : untypedElements = new Set<Element>(),
       typedSends = new Map<Element, Link<Element>>(),
-      concreteTypesInferrer = compiler.enableConcreteTypeInference
-          ? new ConcreteTypesInferrer(compiler) : null,
+      typesInferrer = compiler.enableConcreteTypeInference
+          ? new ConcreteTypesInferrer(compiler)
+          : new SimpleTypesInferrer(compiler),
       super(compiler);
 
   /**
@@ -46,13 +59,13 @@
    */
   void onResolutionComplete(Element mainElement) {
     measure(() {
-      if (concreteTypesInferrer != null) {
-        bool success = concreteTypesInferrer.analyzeMain(mainElement);
+      if (typesInferrer != null) {
+        bool success = typesInferrer.analyzeMain(mainElement);
         if (!success) {
           // If the concrete type inference bailed out, we pretend it didn't
           // happen. In the future we might want to record that it failed but
           // use the partial results as hints.
-          concreteTypesInferrer = null;
+          typesInferrer = null;
         }
       }
     });
@@ -63,12 +76,12 @@
    */
   ConcreteType getGuaranteedTypeOfElement(Element element) {
     return measure(() {
-      if (!element.isParameter()) return null;
-      if (concreteTypesInferrer != null) {
-        ConcreteType guaranteedType = concreteTypesInferrer
-            .getConcreteTypeOfParameter(element);
+      if (typesInferrer != null) {
+        ConcreteType guaranteedType = typesInferrer
+            .getConcreteTypeOfElement(element);
         if (guaranteedType != null) return guaranteedType;
       }
+      if (!element.isParameter()) return null;
       Element holder = element.enclosingElement;
       Link<Element> types = typedSends[holder];
       if (types == null) return null;
@@ -92,10 +105,10 @@
    * Return the (inferred) guaranteed concrete type of [node] or null.
    * [node] must be an AST node of [owner].
    */
-  ConcreteType getGuaranteedTypeOfNode(Node node, Element owner) {
+  ConcreteType getGuaranteedTypeOfNode(owner, node) {
     return measure(() {
-      if (concreteTypesInferrer != null) {
-        return concreteTypesInferrer.getConcreteTypeOfNode(node);
+      if (typesInferrer != null) {
+        return typesInferrer.getConcreteTypeOfNode(owner, node);
       }
       return null;
     });
diff --git a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
index 6afdf09..b6c6a53 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
@@ -89,7 +89,7 @@
         isList = false;
       }
       elements.add(element);
-      cache.clear();
+      if (!cache.isEmpty) cache.clear();
     }
   }
 
@@ -103,14 +103,14 @@
       if (index != list.length) {
         list[index] = last;
       }
-      cache.clear();
+      if (!cache.isEmpty) cache.clear();
     } else {
       Set set = elements;
       if (set.remove(element)) {
         // To avoid wobbling between the two representations, we do
         // not transition back to the list representation even if we
         // end up with few enough elements at this point.
-        cache.clear();
+        if (!cache.isEmpty) cache.clear();
       }
     }
   }
diff --git a/sdk/lib/_internal/compiler/implementation/universe/partial_type_tree.dart b/sdk/lib/_internal/compiler/implementation/universe/partial_type_tree.dart
deleted file mode 100644
index b0ed8dc..0000000
--- a/sdk/lib/_internal/compiler/implementation/universe/partial_type_tree.dart
+++ /dev/null
@@ -1,141 +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 universe;
-
-abstract class PartialTypeTree {
-  final Compiler compiler;
-  PartialTypeTreeNode root;
-
-  PartialTypeTree(this.compiler);
-
-  PartialTypeTreeNode newNode(ClassElement type);
-
-  /**
-   * Returns a [ClassElement] that is an upper bound of the receiver type on
-   * [selector].
-   */
-  // TODO(kasperl): Move this to the Selector class?
-  ClassElement selectorType(Selector selector) {
-    // TODO(ngeoffray): Should the tree be specialized with DartType?
-    DartType type = selector.receiverType;
-    if (type == null) return compiler.objectClass;
-    // TODO(kasperl): Should [dynamic] return Object?
-    if (identical(type.kind, TypeKind.MALFORMED_TYPE))
-        return compiler.objectClass;
-    // TODO(johnniwinther): Change to use [DartType.unalias].
-    if (type.element.isTypedef()) return compiler.functionClass;
-    return type.element;
-  }
-
-  /**
-   * Finds the tree node corresponding to the given [type]. If [insert]
-   * is true, we always return a node that matches the type by
-   * inserting a new node if necessary. If [insert] is false, we
-   * return null if we cannot find a node that matches the [type].
-   */
-  PartialTypeTreeNode findNode(ClassElement type, bool insert) {
-    if (root == null) {
-      if (!insert) return null;
-      root = newNode(compiler.objectClass);
-    }
-
-    PartialTypeTreeNode current = root;
-    L: while (!identical(current.type, type)) {
-      assert(type.isSubclassOf(current.type));
-
-      // Run through the children. If we find a subtype of the type
-      // we are looking for we go that way. If not, we keep track of
-      // the subtypes so we can move them from being children of the
-      // current node to being children of a new node if we need
-      // to insert that.
-      Link<PartialTypeTreeNode> subtypes = const Link();
-      for (Link link = current.children; !link.isEmpty; link = link.tail) {
-        PartialTypeTreeNode child = link.head;
-        ClassElement childType = child.type;
-        if (type.isSubclassOf(childType)) {
-          assert(subtypes.isEmpty);
-          current = child;
-          continue L;
-        } else if (childType.isSubclassOf(type)) {
-          if (insert) subtypes = subtypes.prepend(child);
-        }
-      }
-
-      // If we are not inserting any nodes, we are done.
-      if (!insert) return null;
-
-      // Create a new node and move the children of the current node
-      // that are subtypes of the type of the new node below the new
-      // node in the hierarchy.
-      PartialTypeTreeNode node = newNode(type);
-      if (!subtypes.isEmpty) {
-        node.children = subtypes;
-        Link<PartialTypeTreeNode> remaining = const Link();
-        for (Link link = current.children; !link.isEmpty; link = link.tail) {
-          PartialTypeTreeNode child = link.head;
-          if (!child.type.isSubclassOf(type)) {
-            remaining = remaining.prepend(child);
-          }
-        }
-        current.children = remaining;
-      }
-
-      // Add the new node as a child node of the current node and return it.
-      current.children = current.children.prepend(node);
-      return node;
-    }
-
-    // We found an exact match. No need to insert new nodes.
-    assert(identical(current.type, type));
-    return current;
-  }
-
-  /**
-   * Visits all superclass and subclass nodes for the given [type]. If
-   * the [visit] function ever returns false, we abort the traversal.
-   */
-  void visitHierarchy(ClassElement type, bool visit(PartialTypeTreeNode node)) {
-    PartialTypeTreeNode current = root;
-    L: while (!identical(current.type, type)) {
-      assert(type.isSubclassOf(current.type));
-      if (!visit(current)) return;
-      for (Link link = current.children; !link.isEmpty; link = link.tail) {
-        PartialTypeTreeNode child = link.head;
-        ClassElement childType = child.type;
-        if (type.isSubclassOf(childType)) {
-          current = child;
-          continue L;
-        } else if (childType.isSubclassOf(type)) {
-          if (!child.visitRecursively(visit)) return;
-        }
-      }
-      return;
-    }
-    current.visitRecursively(visit);
-  }
-
-}
-
-class PartialTypeTreeNode {
-
-  final ClassElement type;
-  Link<PartialTypeTreeNode> children;
-
-  PartialTypeTreeNode(this.type) : children = const Link();
-
-  /**
-   * Visits this node and its children recursively. If the visit
-   * callback ever returns false, the visiting stops early.
-   */
-  bool visitRecursively(bool visit(PartialTypeTreeNode node)) {
-    if (!visit(this)) return false;
-    for (Link link = children; !link.isEmpty; link = link.tail) {
-      PartialTypeTreeNode child = link.head;
-      if (!child.visitRecursively(visit)) return false;
-    }
-    return true;
-  }
-
-}
diff --git a/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart b/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
index 36b51399..29e705c 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
@@ -4,62 +4,41 @@
 
 part of universe;
 
-// TODO(kasperl): It seems possible to rewrite this class to be more
-// like the FunctionSet abstraction which is a lot simpler.
-class SelectorMap<T> extends PartialTypeTree {
-
-  SelectorMap(Compiler compiler) : super(compiler);
-
-  SelectorMapNode<T> newNode(ClassElement type) => new SelectorMapNode<T>(type);
+class SelectorMap<T> {
+  final Compiler compiler;
+  final Map<SourceString, SelectorMapNode<T>> nodes =
+      new Map<SourceString, SelectorMapNode<T>>();
+  SelectorMap(this.compiler);
 
   T operator [](Selector selector) {
-    SelectorMapNode<T> node = findNode(selectorType(selector), false);
-    if (node == null) return null;
-    Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name];
-    if (selectors == null) return null;
-    for (Link link = selectors; !link.isEmpty; link = link.tail) {
-      SelectorValue<T> existing = link.head;
-      if (existing.selector.equalsUntyped(selector)) return existing.value;
-    }
-    return null;
-  }
-
-  // TODO(kasperl): Do we need to support removing selectors by
-  // passing null as the value?
-  void operator []=(Selector selector, T value) {
-    ClassElement type = selectorType(selector);
-    SelectorMapNode<T> node = findNode(type, true);
     SourceString name = selector.name;
-    Link<SelectorValue<T>> selectors = node.selectorsByName.putIfAbsent(
-        name, () => const Link());
-    // Run through the linked list of selectors with the same name. If
-    // we find one that matches, we update the value in the mapping.
-    for (Link link = selectors; !link.isEmpty; link = link.tail) {
-      SelectorValue<T> existing = link.head;
-      // It is safe to ignore the type here, because all selector
-      // mappings that are stored in a single node have the same type.
-      if (existing.selector.equalsUntyped(selector)) {
-        existing.value = value;
-        return;
-      }
-    }
-    // We could not find an existing mapping for the selector, so
-    // we add a new one to the existing linked list.
-    SelectorValue<T> head = new SelectorValue<T>(selector, value);
-    node.selectorsByName[name] = selectors.prepend(head);
+    SelectorMapNode node = nodes[name];
+    return (node != null)
+        ? node.lookup(selector)
+        : null;
   }
 
-  // TODO(kasperl): Share code with the [] operator?
+  void operator []=(Selector selector, T value) {
+    SourceString name = selector.name;
+    SelectorMapNode node = nodes.putIfAbsent(
+        name, () => new SelectorMapNode(name));
+    node.update(selector, value);
+  }
+
   bool containsKey(Selector selector) {
-    SelectorMapNode<T> node = findNode(selectorType(selector), false);
-    if (node == null) return false;
-    Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name];
-    if (selectors == null) return false;
-    for (Link link = selectors; !link.isEmpty; link = link.tail) {
-      SelectorValue<T> existing = link.head;
-      if (existing.selector.equalsUntyped(selector)) return true;
-    }
-    return false;
+    SourceString name = selector.name;
+    SelectorMapNode node = nodes[name];
+    return (node != null)
+        ? node.containsKey(selector)
+        : false;
+  }
+
+  T remove(Selector selector) {
+    SourceString name = selector.name;
+    SelectorMapNode node = nodes[name];
+    return (node != null)
+        ? node.remove(selector)
+        : null;
   }
 
   /**
@@ -69,56 +48,82 @@
    */
   void visitMatching(Element member, bool visit(Selector selector, T value)) {
     assert(member.isMember());
-    if (root == null) return;
-    // TODO(kasperl): Use visitHierachyMatching when possible. It is
-    // currently broken in subtle ways when it comes to finding typed
-    // selectors where we only know the interface of the receiver.
-    visitAllMatching(member, visit);
+    SourceString name = member.name;
+    SelectorMapNode node = nodes[name];
+    if (node != null) {
+      node.visitMatching(member, compiler, visit);
+    }
   }
-
-  void visitAllMatching(Element member, bool visit(selector, value)) {
-    root.visitRecursively((SelectorMapNode<T> node) {
-      Link<SelectorValue<T>> selectors = node.selectorsByName[member.name];
-      if (selectors == null) return true;
-      for (Link link = selectors; !link.isEmpty; link = link.tail) {
-        SelectorValue<T> existing = link.head;
-        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.appliesUnnamed(member, compiler)) {
-          if (!visit(selector, existing.value)) return false;
-        }
-      }
-      return true;
-    });
-  }
-
-  void visitHierarchyMatching(Element member, bool visit(selector, value)) {
-    visitHierarchy(member.getEnclosingClass(), (SelectorMapNode<T> node) {
-      Link<SelectorValue<T>> selectors = node.selectorsByName[member.name];
-      if (selectors == null) return true;
-      for (Link link = selectors; !link.isEmpty; link = link.tail) {
-        SelectorValue<T> existing = link.head;
-        Selector selector = existing.selector;
-        if (selector.appliesUntyped(member, compiler)) {
-          if (!visit(selector, existing.value)) return false;
-        }
-      }
-      return true;
-    });
-  }
-
 }
 
-class SelectorMapNode<T> extends PartialTypeTreeNode {
-  final Map<SourceString, Link<SelectorValue<T>>> selectorsByName =
-      new Map<SourceString, Link<SelectorValue<T>>>();
-  SelectorMapNode(ClassElement type) : super(type);
-}
+class SelectorMapNode<T> {
+  final SourceString name;
+  final Map<Selector, T> selectors = new Map<Selector, T>();
 
-class SelectorValue<T> {
-  final Selector selector;
-  T value;
-  SelectorValue(this.selector, this.value);
-  toString() => "$selector -> $value";
+  // We start caching which selectors match which elements when the
+  // number of different selectors exceed a threshold. This way we
+  // avoid lots of repeated calls to the Selector.applies method.
+  static const int MAX_SELECTORS_NO_CACHE = 8;
+  Map<Element, List<Selector>> cache;
+
+  SelectorMapNode(this.name);
+
+  T lookup(Selector selector) {
+    assert(selector.name == name);
+    return selectors[selector];
+  }
+
+  void update(Selector selector, T value) {
+    assert(selector.name == name);
+    bool existing = selectors.containsKey(selector);
+    selectors[selector] = value;
+    if (existing) return;
+    // The update has introduced a new selector in the map, so we need
+    // to consider if we should start caching. At the very least, we
+    // have to clear the cache because the new element may invalidate
+    // existing cache entries.
+    if (cache == null) {
+      if (selectors.length > MAX_SELECTORS_NO_CACHE) {
+        cache = new Map<Element, List<Selector>>();
+      }
+    } else if (!cache.isEmpty) {
+      cache.clear();
+    }
+  }
+
+  bool containsKey(Selector selector) {
+    assert(selector.name == name);
+    return selectors.containsKey(selector);
+  }
+
+  T remove(Selector selector) {
+    assert(selector.name == name);
+    if (!selectors.containsKey(selector)) return null;
+    if (cache != null && !cache.isEmpty) cache.clear();
+    return selectors.remove(selector);
+  }
+
+  void visitMatching(Element member, Compiler compiler,
+                     bool visit(Selector selector, T value)) {
+    assert(member.name == name);
+    Iterable<Selector> matching = computeMatching(member, compiler);
+    for (Selector selector in matching) {
+      if (!visit(selector, selectors[selector])) return;
+    }
+  }
+
+  Iterable<Selector> computeMatching(Element member, Compiler compiler) {
+    // Probe the cache if it exists. Do this before creating the
+    // matching iterable to cut down on the overhead for cache hits.
+    if (cache != null) {
+      List<Selector> cached = cache[member];
+      if (cached != null) return cached;
+    }
+    // Filter the selectors keys so we only have the ones that apply
+    // to the given member element.
+    Iterable<Selector> matching = selectors.keys.where(
+        (Selector selector) => selector.appliesUnnamed(member, compiler));
+    if (cache == null) return matching;
+    return cache[member] = matching.toList();
+  }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index 3840965..8f57035 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -13,7 +13,6 @@
 import '../js/js.dart' as js;
 
 part 'function_set.dart';
-part 'partial_type_tree.dart';
 part 'selector_map.dart';
 
 class Universe {
diff --git a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
index 7163496..59ab485 100644
--- a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
+++ b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
@@ -157,7 +157,7 @@
   /** Package description */
   final description;
   /** Libraries contained in this package. */
-  final List<String> libraries = <String>[];
+  final List<Reference> libraries = <Reference>[];
   /**
    * Descriptive string describing the version# of the package.
    *
@@ -419,11 +419,10 @@
         version, revision);
 
     for (final lib in _sortedLibraries) {
-      var libraryElement = new LibraryElement(lib.qualifiedName, lib)
+      var libraryElement = new LibraryElement(lib.qualifiedName, lib, lookupMdnComment)
           ..stripDuplicateUris(null, null);
-      packageManifest.libraries.add(libraryElement.id);
+      packageManifest.libraries.add(new Reference.fromElement(libraryElement));
       startFile("$revision/${libraryElement.id}.json");
-
       write(json_serializer.serialize(libraryElement));
       endFile();
     }
@@ -439,6 +438,8 @@
     write(json_serializer.serialize(packageManifest));
     endFile();
   }
+  
+  MdnComment lookupMdnComment(Mirror mirror) => null;
 
   void startFile(String path) {
     _filePath = new Path(path);
@@ -1986,3 +1987,27 @@
 
   String toString() => text;
 }
+
+class MdnComment implements DocComment {
+  final String mdnComment;
+  final String mdnUrl;
+
+  MdnComment(String this.mdnComment, String this.mdnUrl);
+
+  String get text => mdnComment;
+
+  ClassMirror get inheritedFrom => null;
+
+  String get html {
+    // Wrap the mdn comment so we can highlight it and so we handle MDN scraped
+    // content that lacks a top-level block tag.
+   return '''
+        <div class="mdn">
+        $mdnComment
+        <div class="mdn-note"><a href="$mdnUrl">from MDN</a></div>
+        </div>
+        ''';
+  }
+
+  String toString() => mdnComment;
+}
diff --git a/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart b/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart
index f2ffbcf..53da583 100755
--- a/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart
+++ b/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart
@@ -24,6 +24,10 @@
   }
 }
 
+String _escapeId(String id) {
+  return id.replaceAll(new RegExp('[/]'), '#slash');
+}
+
 /**
  * Base class for all elements in the AST.
  */
@@ -36,6 +40,14 @@
   final String id;
   /** Raw text of the comment associated with the Element if any. */
   final String comment;
+  /** Raw html comment for the Element from MDN. */ 
+  String mdnCommentHtml;
+  /**
+   * The URL to the page on MDN that content was pulled from for the current
+   * type being documented. Will be `null` if the type doesn't use any MDN
+   * content.
+   */
+  String mdnUrl;
   /** Children of the node. */
   List<Element> children;
   /** Whether the element is private. */
@@ -50,10 +62,20 @@
    */
   String line;
 
-  Element(Mirror mirror, this.kind, this.name, this.id, this.comment)
+  Element(Mirror mirror, this.kind, this.name, String id, this.comment,
+      MdnComment lookupMdnComment(Mirror))
       : line = mirror.location.line.toString(),
+        id = _escapeId(id),
         isPrivate = _optionalBool(mirror.isPrivate),
-        uri = _stripUri(mirror.location.sourceUri.toString());
+        uri = _stripUri(mirror.location.sourceUri.toString()) {
+    if (lookupMdnComment != null) {
+      var mdnComment = lookupMdnComment(mirror);
+      if (mdnComment != null) {
+        mdnCommentHtml = mdnComment.mdnComment;
+        mdnUrl = mdnComment.mdnUrl;
+      }
+    }
+  }
 
   void addChild(Element child) {
     if (children == null) {
@@ -97,31 +119,69 @@
  * [Element] describing a Dart library.
  */
 class LibraryElement extends Element {
-  LibraryElement(String name, LibraryMirror mirror)
-      : super(mirror, 'library', name, name, computeComment(mirror)) {
-
+  LibraryElement(String name, LibraryMirror mirror,
+      MdnComment lookupMdnComment(Mirror))
+      : super(mirror, 'library', _libraryName(mirror), name,
+          computeComment(mirror), lookupMdnComment) {
+  
     mirror.functions.forEach((childName, childMirror) {
-      addChild(new MethodElement(childName, childMirror));
+      addChild(new MethodElement(childName, childMirror, lookupMdnComment));
     });
 
     mirror.getters.forEach((childName, childMirror) {
-      addChild(new GetterElement(childName, childMirror));
+      addChild(new GetterElement(childName, childMirror, lookupMdnComment));
     });
 
     mirror.variables.forEach((childName, childMirror) {
-        addChild(new VariableElement(childName, childMirror));
+        addChild(new VariableElement(childName, childMirror, lookupMdnComment));
     });
 
     mirror.classes.forEach((className, classMirror) {
-      if (!classMirror.isPrivate) {
-        if (classMirror is TypedefMirror) {
-          addChild(new TypedefElement(className, classMirror));
-        } else {
-          addChild(new ClassElement(className, classMirror));
-        }
+      if (classMirror is TypedefMirror) {
+        addChild(new TypedefElement(className, classMirror));
+      } else {
+        addChild(new ClassElement(className, classMirror, lookupMdnComment));
       }
     });
   }
+
+  static String _libraryName(LibraryMirror mirror) {
+    if (mirror.uri.scheme == 'file') {
+      // TODO(jacobr): this is a hack. Remove once these libraries are removed
+      // from the sdk.
+      var uri = mirror.uri;
+      var path = uri.path;
+      var pattern = new RegExp(r'[\\/]dart[\\/]pkg[\\/]([^\\/]+)[\\/]lib[\\/](.+)$');
+      var match = pattern.firstMatch(path);
+      var package;
+      if (match != null) {
+        package = match.group(1);
+        path = match.group(2);
+      }
+      // TODO(jacobr): add a second pattern for a more typical pub environment.
+      if (package != null) {
+        return 'package:$package/$path';
+      } else {
+        // TODO(jacobr): this is a lousy fallback.
+        print("Unable to determine package for $path.");
+        return mirror.uri.toString();
+      }
+    } else {
+      return mirror.uri.toString();
+    }
+  }
+}
+
+/**
+ * Returns whether the class implements or extends [Error] or [Exception].
+ */
+bool _isThrowable(ClassMirror mirror) {
+  if (mirror.library.uri.toString() == 'dart:core' &&
+      mirror.simpleName == 'Error' || mirror.simpleName == 'Exception')
+    return true;
+  if (mirror.superclass != null && _isThrowable(mirror.superclass))
+    return true;
+  return mirror.superinterfaces.any(_isThrowable);
 }
 
 /**
@@ -134,11 +194,16 @@
   final bool isAbstract;
   /** Interfaces the class implements. */
   List<Reference> interfaces;
+  /** Whether the class implements or extends [Error] or [Exception]. */
+  bool isThrowable;
 
-  ClassElement(String name, ClassMirror mirror)
-      : super(mirror, 'class', mirror.simpleName, name, computeComment(mirror)),
+  ClassElement(String name, ClassMirror mirror,
+      MdnComment lookupMdnComment(Mirror))
+      : super(mirror, 'class', mirror.simpleName, name, computeComment(mirror),
+          lookupMdnComment),
         superclass = _optionalReference(mirror.superclass),
         isAbstract = _optionalBool(mirror.isAbstract) {
+        isThrowable = _optionalBool(_isThrowable(mirror));
     for (var interface in mirror.superinterfaces) {
       if (this.interfaces == null) {
         this.interfaces = <Reference>[];
@@ -148,20 +213,22 @@
 
     mirror.methods.forEach((childName, childMirror) {
       if (!childMirror.isConstructor && !childMirror.isGetter) {
-        addChild(new MethodElement(childName, childMirror));
+        addChild(new MethodElement(childName, childMirror, lookupMdnComment));
       }
     });
 
     mirror.getters.forEach((childName, childMirror) {
-      addChild(new GetterElement(childName, childMirror));
+      addChild(new GetterElement(childName, childMirror, lookupMdnComment));
     });
 
     mirror.variables.forEach((childName, childMirror) {
-        addChild(new VariableElement(childName, childMirror));
+        addChild(new VariableElement(childName, childMirror,
+            lookupMdnComment));
     });
 
     mirror.constructors.forEach((constructorName, methodMirror) {
-      addChild(new MethodElement(constructorName, methodMirror, 'constructor'));
+      addChild(new MethodElement(constructorName, methodMirror,
+          lookupMdnComment, 'constructor'));
     });
 
     for (var typeVariable in mirror.originalDeclaration.typeVariables) {
@@ -178,8 +245,10 @@
   final Reference ref;
   final bool isStatic;
 
-  GetterElement(String name, MethodMirror mirror)
-      : super(mirror, 'property', mirror.simpleName, name, computeComment(mirror)),
+  GetterElement(String name, MethodMirror mirror,
+      MdnComment lookupMdnComment(Mirror))
+      : super(mirror, 'property', mirror.simpleName, name, computeComment(mirror),
+          lookupMdnComment),
         ref = _optionalReference(mirror.returnType),
         isStatic = _optionalBool(mirror.isStatic);
 }
@@ -194,9 +263,10 @@
   final bool isOperator;
   final bool isStatic;
 
-  MethodElement(String name, MethodMirror mirror, [String kind = 'method'])
+  MethodElement(String name, MethodMirror mirror,
+      MdnComment lookupMdnComment(Mirror), [String kind = 'method'])
       : super(mirror, kind, name, '$name${mirror.parameters.length}()',
-              computeComment(mirror)),
+              computeComment(mirror), lookupMdnComment),
         returnType = _optionalReference(mirror.returnType),
         isSetter = _optionalBool(mirror.isSetter),
         isOperator = _optionalBool(mirror.isOperator),
@@ -214,13 +284,55 @@
 class ParameterElement extends Element {
   /** Type of the parameter. */
   final Reference ref;
-  /** Whether the parameter is optional. */
+
+  /**
+   * Returns the default value for this parameter.
+   */
+  final String defaultValue;
+
+  /**
+   * Is this parameter optional?
+   */
   final bool isOptional;
 
+  /**
+   * Is this parameter named?
+   */
+  final bool isNamed;
+
+  /**
+   * Returns the initialized field, if this parameter is an initializing formal.
+   */
+  final Reference initializedField;
+  
   ParameterElement(ParameterMirror mirror)
-      : super(mirror, 'param', mirror.simpleName, mirror.simpleName, null),
+      : super(mirror, 'param', mirror.simpleName, mirror.simpleName, null,
+          null),
         ref = _optionalReference(mirror.type),
-        isOptional = _optionalBool(mirror.isOptional) {
+        isOptional = _optionalBool(mirror.isOptional),
+        defaultValue = mirror.defaultValue,
+        isNamed = _optionalBool(mirror.isNamed),
+        initializedField = _optionalReference(mirror.initializedField) {
+              
+    if (mirror.type is FunctionTypeMirror) {
+      addChild(new FunctionTypeElement(mirror.type));
+    }
+  }
+}
+
+class FunctionTypeElement extends Element {
+  final Reference returnType;
+ 
+  FunctionTypeElement(FunctionTypeMirror mirror)
+      : super(mirror, 'functiontype', mirror.simpleName, mirror.simpleName, null, null),
+        returnType = _optionalReference(mirror.returnType) {
+    for (var param in mirror.parameters) {
+      addChild(new ParameterElement(param));
+    }
+    // TODO(jacobr): can a FunctionTypeElement really have type variables?
+    for (var typeVariable in mirror.originalDeclaration.typeVariables) {
+      addChild(new TypeParameterElement(typeVariable));
+    }
   }
 }
 
@@ -234,10 +346,11 @@
    * In the following code sample, [:Bar:] is an upper bound:
    * [: class Bar<T extends Foo> { } :]
    */
-  Reference upperBound;
+  final Reference upperBound;
 
   TypeParameterElement(TypeMirror mirror)
-      : super(mirror, 'typeparam', mirror.simpleName, mirror.simpleName, null),
+      : super(mirror, 'typeparam', mirror.simpleName, mirror.simpleName, null,
+          null),
         upperBound = mirror.upperBound != null && !mirror.upperBound.isObject ?
             new Reference(mirror.upperBound) : null;
 }
@@ -253,8 +366,10 @@
   /** Whether the variable is final. */
   final bool isFinal;
 
-  VariableElement(String name, VariableMirror mirror)
-      : super(mirror, 'variable', mirror.simpleName, name, null),
+  VariableElement(String name, VariableMirror mirror,
+      MdnComment lookupMdnComment(Mirror))
+      : super(mirror, 'variable', mirror.simpleName, name,
+          computeComment(mirror), lookupMdnComment),
         ref = _optionalReference(mirror.type),
         isStatic = _optionalBool(mirror.isStatic),
         isFinal = _optionalBool(mirror.isFinal);
@@ -270,7 +385,7 @@
 
   TypedefElement(String name, TypedefMirror mirror)
       : super(mirror, 'typedef', mirror.simpleName, name,
-               computeComment(mirror)),
+               computeComment(mirror), null),
         returnType = _optionalReference(mirror.value.returnType) {
     for (var param in mirror.value.parameters) {
       addChild(new ParameterElement(param));
@@ -301,9 +416,13 @@
       }
     }
   }
+  
+  // TODO(jacobr): compute the referenceId correctly for the general case so
+  // that this method can work with all element types not just LibraryElements.
+  Reference.fromElement(LibraryElement e) : name = e.name, refId = e.id;
 
   static String getId(Mirror mirror) {
-    String id = mirror.simpleName;
+    String id = _escapeId(mirror.simpleName);
     if (mirror.owner != null) {
       id = '${getId(mirror.owner)}/$id';
     }
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index efa4144..820ba00 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -137,19 +137,29 @@
   /**
    * Creates a future that completes after a delay.
    *
-   * The future will be completed after [milliseconds] have passed with
-   * the result of calling [value]. If [milliseconds] is 0, it completes at the
-   * earliest in the next event-loop iteration.
+   * The future will be completed after the given [duration] has passed with
+   * the result of calling [computation]. If the duration is 0 or less, it
+   * completes no sooner than in the next event-loop iteration.
    *
-   * If calling [value] throws, the created future will complete with the
+   * If [computation] is not given or [:null:] then it will behave as if
+   * [computation] was set to [:() => null:]. That is, it will complete with
+   * [:null:].
+   *
+   * If calling [computation] throws, the created future will complete with the
    * error.
    *
    * See [Completer]s, for futures with values that are computed asynchronously.
+   *
+   * *Deprecation note*: this method initially took an [int] as argument (the
+   * milliseconds to wait). It is now a [Duration].
    */
-  factory Future.delayed(int milliseconds, T value()) {
+  factory Future.delayed(var duration, [T computation()]) {
+    // TODO(floitsch): no need to allocate a ThenFuture when the computation is
+    // null.
+    if (computation == null) computation = (() => null);
     _ThenFuture<dynamic, T> future =
-        new _ThenFuture<dynamic, T>((_) => value());
-    new Timer(milliseconds, (_) => future._sendValue(null));
+        new _ThenFuture<dynamic, T>((_) => computation());
+    new Timer(duration, () => future._sendValue(null));
     return future;
   }
 
diff --git a/sdk/lib/core/duration.dart b/sdk/lib/core/duration.dart
index af79aeb..9e7cdd8 100644
--- a/sdk/lib/core/duration.dart
+++ b/sdk/lib/core/duration.dart
@@ -25,6 +25,8 @@
 
   static const int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
 
+  static const Duration ZERO = const Duration(seconds: 0);
+
   /**
    * This [Duration] in milliseconds.
    */
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index 3584db5..4e5b950 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -449,7 +449,6 @@
     return string.substring(_position, _nextPosition);
   }
 
-
   bool moveNext() {
     _position = _nextPosition;
     if (_position == string.length) {
@@ -492,3 +491,16 @@
     return true;
   }
 }
+
+/**
+ * An [Iterable] of the UTF-16 code units of a [String] in index order.
+ */
+class CodeUnits extends ListIterable<int> {
+  /** The string that this is the code units of. */
+  String string;
+
+  CodeUnits(this.string);
+
+  int get length => string.length;
+  int elementAt(int i) => string.codeUnitAt(i);
+}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 2faa94c..71f7cce 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -72,12 +72,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  AbstractWorkerEvents get on =>
-    new AbstractWorkerEvents(this);
-
   @JSName('addEventListener')
   @DomName('AbstractWorker.addEventListener')
   @DocsEditable
@@ -96,16 +90,6 @@
   @DocsEditable
   Stream<Event> get onError => errorEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class AbstractWorkerEvents extends Events {
-  @DocsEditable
-  AbstractWorkerEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-}
 // 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.
@@ -257,12 +241,6 @@
   /// Checks if this type is supported on the current platform.
   static bool get supported => JS('bool', '!!(window.applicationCache)');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  ApplicationCacheEvents get on =>
-    new ApplicationCacheEvents(this);
-
   static const int CHECKING = 2;
 
   static const int DOWNLOADING = 3;
@@ -337,37 +315,6 @@
   @DocsEditable
   Stream<Event> get onUpdateReady => updateReadyEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class ApplicationCacheEvents extends Events {
-  @DocsEditable
-  ApplicationCacheEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get cached => this['cached'];
-
-  @DocsEditable
-  EventListenerList get checking => this['checking'];
-
-  @DocsEditable
-  EventListenerList get downloading => this['downloading'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get noUpdate => this['noupdate'];
-
-  @DocsEditable
-  EventListenerList get obsolete => this['obsolete'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-
-  @DocsEditable
-  EventListenerList get updateReady => this['updateready'];
-}
 // 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.
@@ -624,12 +571,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> levelChangeEvent = const EventStreamProvider<Event>('levelchange');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  BatteryManagerEvents get on =>
-    new BatteryManagerEvents(this);
-
   @DomName('BatteryManager.charging')
   @DocsEditable
   final bool charging;
@@ -676,25 +617,6 @@
   @DocsEditable
   Stream<Event> get onLevelChange => levelChangeEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class BatteryManagerEvents extends Events {
-  @DocsEditable
-  BatteryManagerEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get chargingChange => this['chargingchange'];
-
-  @DocsEditable
-  EventListenerList get chargingTimeChange => this['chargingtimechange'];
-
-  @DocsEditable
-  EventListenerList get dischargingTimeChange => this['dischargingtimechange'];
-
-  @DocsEditable
-  EventListenerList get levelChange => this['levelchange'];
-}
 // 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.
@@ -813,12 +735,6 @@
   @DocsEditable
   factory BodyElement() => document.$dom_createElement("body");
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  BodyElementEvents get on =>
-    new BodyElementEvents(this);
-
   @DomName('HTMLBodyElement.onbeforeunload')
   @DocsEditable
   Stream<Event> get onBeforeUnload => beforeUnloadEvent.forTarget(this);
@@ -871,52 +787,6 @@
   @DocsEditable
   Stream<Event> get onUnload => unloadEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class BodyElementEvents extends ElementEvents {
-  @DocsEditable
-  BodyElementEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get beforeUnload => this['beforeunload'];
-
-  @DocsEditable
-  EventListenerList get blur => this['blur'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get focus => this['focus'];
-
-  @DocsEditable
-  EventListenerList get hashChange => this['hashchange'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get offline => this['offline'];
-
-  @DocsEditable
-  EventListenerList get online => this['online'];
-
-  @DocsEditable
-  EventListenerList get popState => this['popstate'];
-
-  @DocsEditable
-  EventListenerList get resize => this['resize'];
-
-  @DocsEditable
-  EventListenerList get storage => this['storage'];
-
-  @DocsEditable
-  EventListenerList get unload => this['unload'];
-}
 // 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.
@@ -6169,12 +6039,6 @@
   @DocsEditable
   static const EventStreamProvider<MessageEvent> messageEvent = const EventStreamProvider<MessageEvent>('message');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  DedicatedWorkerContextEvents get on =>
-    new DedicatedWorkerContextEvents(this);
-
   @DomName('DedicatedWorkerContext.postMessage')
   @DocsEditable
   void postMessage(/*any*/ message, [List messagePorts]) {
@@ -6200,16 +6064,6 @@
   @DocsEditable
   Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class DedicatedWorkerContextEvents extends WorkerContextEvents {
-  @DocsEditable
-  DedicatedWorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-}
 // 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.
@@ -6521,12 +6375,6 @@
   @Experimental
   static const EventStreamProvider<Event> pointerLockErrorEvent = const EventStreamProvider<Event>('webkitpointerlockerror');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  DocumentEvents get on =>
-    new DocumentEvents(this);
-
   @JSName('body')
   /// Moved to [HtmlDocument].
   @DomName('Document.body')
@@ -7079,25 +6927,6 @@
     }
   }
 }
-
-@DocsEditable
-@deprecated
-class DocumentEvents extends ElementEvents {
-  @DocsEditable
-  DocumentEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get readyStateChange => this['readystatechange'];
-
-  @DocsEditable
-  EventListenerList get selectionChange => this['selectionchange'];
-
-  @DocsEditable
-  EventListenerList get pointerLockChange => this['webkitpointerlockchange'];
-
-  @DocsEditable
-  EventListenerList get pointerLockError => this['webkitpointerlockerror'];
-}
 // 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.
@@ -7183,12 +7012,6 @@
   }
 
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  ElementEvents get on =>
-    new ElementEvents(this);
-
   @JSName('querySelector')
   @DomName('DocumentFragment.querySelector')
   @DocsEditable
@@ -8967,6 +8790,42 @@
   @Creates('Null')  // Set from Dart code; does not instantiate a native type.
   var xtag;
 
+  /**
+   * Scrolls this element into view.
+   *
+   * Only one of of the alignment options may be specified at a time.
+   *
+   * If no options are specified then this will attempt to scroll the minimum
+   * amount needed to bring the element into view.
+   *
+   * Note that alignCenter is currently only supported on WebKit platforms. If
+   * alignCenter is specified but not supported then this will fall back to
+   * alignTop.
+   *
+   * See also:
+   *
+   * * [scrollIntoView](http://docs.webplatform.org/wiki/dom/methods/scrollIntoView)
+   * * [scrollIntoViewIfNeeded](http://docs.webplatform.org/wiki/dom/methods/scrollIntoViewIfNeeded)
+   */
+  void scrollIntoView([ScrollAlignment alignment]) {
+    var hasScrollIntoViewIfNeeded = false;
+    hasScrollIntoViewIfNeeded =
+        JS('bool', '!!(#.scrollIntoViewIfNeeded)', this);
+    if (alignment == ScrollAlignment.TOP) {
+      this.$dom_scrollIntoView(true);
+    } else if (alignment == ScrollAlignment.BOTTOM) {
+      this.$dom_scrollIntoView(false);
+    } else if (hasScrollIntoViewIfNeeded) {
+      if (alignment == ScrollAlignment.CENTER) {
+        this.$dom_scrollIntoViewIfNeeded(true);
+      } else {
+        this.$dom_scrollIntoViewIfNeeded();
+      }
+    } else {
+      this.$dom_scrollIntoView();
+    }
+  }
+
   @DomName('Element.mouseWheelEvent')
   static const EventStreamProvider<WheelEvent> mouseWheelEvent =
       const _CustomEventStreamProvider<WheelEvent>(
@@ -9303,12 +9162,6 @@
   @Experimental
   static const EventStreamProvider<Event> fullscreenErrorEvent = const EventStreamProvider<Event>('webkitfullscreenerror');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  ElementEvents get on =>
-    new ElementEvents(this);
-
   @JSName('children')
   @DomName('Element.children')
   @DocsEditable
@@ -9572,10 +9425,15 @@
   @DocsEditable
   void scrollByPages(int pages) native;
 
+  @JSName('scrollIntoView')
+  @DomName('Element.scrollIntoView')
+  @DocsEditable
+  void $dom_scrollIntoView([bool alignWithTop]) native;
+
   @JSName('scrollIntoViewIfNeeded')
   @DomName('Element.scrollIntoViewIfNeeded')
   @DocsEditable
-  void scrollIntoView([bool centerIfNeeded]) native;
+  void $dom_scrollIntoViewIfNeeded([bool centerIfNeeded]) native;
 
   @JSName('setAttribute')
   @DomName('Element.setAttribute')
@@ -9949,165 +9807,22 @@
       // Firefox may return a JS function for some types (Embed, Object).
       JS('Element|=Object', 'document.createElement(#)', tag);
 }
-// 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.
 
 
-@deprecated
-class ElementEvents extends Events {
-  ElementEvents(EventTarget _ptr) : super(_ptr);
+/**
+ * Options for Element.scrollIntoView.
+ */
+class ScrollAlignment {
+  final _value;
+  const ScrollAlignment._internal(this._value);
+  toString() => 'ScrollAlignment.$_value';
 
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get beforeCopy => this['beforecopy'];
-
-  @DocsEditable
-  EventListenerList get beforeCut => this['beforecut'];
-
-  @DocsEditable
-  EventListenerList get beforePaste => this['beforepaste'];
-
-  @DocsEditable
-  EventListenerList get blur => this['blur'];
-
-  @DocsEditable
-  EventListenerList get change => this['change'];
-
-  @DocsEditable
-  EventListenerList get click => this['click'];
-
-  @DocsEditable
-  EventListenerList get contextMenu => this['contextmenu'];
-
-  @DocsEditable
-  EventListenerList get copy => this['copy'];
-
-  @DocsEditable
-  EventListenerList get cut => this['cut'];
-
-  @DocsEditable
-  EventListenerList get doubleClick => this['dblclick'];
-
-  @DocsEditable
-  EventListenerList get drag => this['drag'];
-
-  @DocsEditable
-  EventListenerList get dragEnd => this['dragend'];
-
-  @DocsEditable
-  EventListenerList get dragEnter => this['dragenter'];
-
-  @DocsEditable
-  EventListenerList get dragLeave => this['dragleave'];
-
-  @DocsEditable
-  EventListenerList get dragOver => this['dragover'];
-
-  @DocsEditable
-  EventListenerList get dragStart => this['dragstart'];
-
-  @DocsEditable
-  EventListenerList get drop => this['drop'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get focus => this['focus'];
-
-  @DocsEditable
-  EventListenerList get input => this['input'];
-
-  @DocsEditable
-  EventListenerList get invalid => this['invalid'];
-
-  @DocsEditable
-  EventListenerList get keyDown => this['keydown'];
-
-  @DocsEditable
-  EventListenerList get keyPress => this['keypress'];
-
-  @DocsEditable
-  EventListenerList get keyUp => this['keyup'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get mouseDown => this['mousedown'];
-
-  @DocsEditable
-  EventListenerList get mouseMove => this['mousemove'];
-
-  @DocsEditable
-  EventListenerList get mouseOut => this['mouseout'];
-
-  @DocsEditable
-  EventListenerList get mouseOver => this['mouseover'];
-
-  @DocsEditable
-  EventListenerList get mouseUp => this['mouseup'];
-
-  @DocsEditable
-  EventListenerList get paste => this['paste'];
-
-  @DocsEditable
-  EventListenerList get reset => this['reset'];
-
-  @DocsEditable
-  EventListenerList get scroll => this['scroll'];
-
-  @DocsEditable
-  EventListenerList get search => this['search'];
-
-  @DocsEditable
-  EventListenerList get select => this['select'];
-
-  @DocsEditable
-  EventListenerList get selectStart => this['selectstart'];
-
-  @DocsEditable
-  EventListenerList get submit => this['submit'];
-
-  @DocsEditable
-  EventListenerList get touchCancel => this['touchcancel'];
-
-  @DocsEditable
-  EventListenerList get touchEnd => this['touchend'];
-
-  @DocsEditable
-  EventListenerList get touchEnter => this['touchenter'];
-
-  @DocsEditable
-  EventListenerList get touchLeave => this['touchleave'];
-
-  @DocsEditable
-  EventListenerList get touchMove => this['touchmove'];
-
-  @DocsEditable
-  EventListenerList get touchStart => this['touchstart'];
-
-  @DocsEditable
-  EventListenerList get fullscreenChange => this['webkitfullscreenchange'];
-
-  @DocsEditable
-  EventListenerList get fullscreenError => this['webkitfullscreenerror'];
-
-  EventListenerList get mouseWheel {
-    if (JS('bool', '#.onwheel !== undefined', _ptr)) {
-      // W3C spec, and should be IE9+, but IE has a bug exposing onwheel.
-      return this['wheel'];
-    } else if (JS('bool', '#.onmousewheel !== undefined', _ptr)) {
-      // Chrome & IE
-      return this['mousewheel'];
-    } else {
-      // Firefox
-      return this['DOMMouseScroll'];
-    }
-  }
+  /// Attempt to align the element to the top of the scrollable area.
+  static const TOP = const ScrollAlignment._internal('TOP');
+  /// Attempt to center the element in the scrollable area.
+  static const CENTER = const ScrollAlignment._internal('CENTER');
+  /// Attempt to align the element to the bottom of the scrollable area.
+  static const BOTTOM = const ScrollAlignment._internal('BOTTOM');
 }
 // 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
@@ -10551,12 +10266,6 @@
   static EventSource _create_1(url, eventSourceInit) => JS('EventSource', 'new EventSource(#,#)', url, eventSourceInit);
   static EventSource _create_2(url) => JS('EventSource', 'new EventSource(#)', url);
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  EventSourceEvents get on =>
-    new EventSourceEvents(this);
-
   static const int CLOSED = 2;
 
   static const int CONNECTING = 0;
@@ -10605,22 +10314,6 @@
   @DocsEditable
   Stream<Event> get onOpen => openEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class EventSourceEvents extends Events {
-  @DocsEditable
-  EventSourceEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get open => this['open'];
-}
 // 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.
@@ -10629,15 +10322,38 @@
 /**
  * Base class that supports listening for and dispatching browser events.
  *
- * Events can either be accessed by string name (using the indexed getter) or by
- * getters exposed by subclasses. Use the getters exposed by subclasses when
- * possible for better compile-time type checks.
+ * Normally events are accessed via the Stream getter:
  *
- * Using an indexed getter:
- *     events['mouseover'].add((e) => print("Mouse over!"));
+ *     element.onMouseOver.listen((e) => print('Mouse over!'));
  *
- * Using a getter provided by a subclass:
- *     elementEvents.mouseOver.add((e) => print("Mouse over!"));
+ * To access bubbling events which are declared on one element, but may bubble
+ * up to another element type (common for MediaElement events):
+ *
+ *     MediaElement.pauseEvent.forTarget(document.body).listen(...);
+ *
+ * To useCapture on events:
+ *
+ *     Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
+ *
+ * Custom events can be declared as:
+ *
+ *    class DataGenerator {
+ *      static EventStreamProvider<Event> dataEvent =
+ *          new EventStreamProvider('data');
+ *    }
+ *
+ * Then listeners should access the event with:
+ *
+ *     DataGenerator.dataEvent.forTarget(element).listen(...);
+ *
+ * Custom events can also be accessed as:
+ *
+ *     element.on['some_event'].listen(...);
+ *
+ * This approach is generally discouraged as it loses the event typing and
+ * some DOM events may have multiple platform-dependent event names under the
+ * covers. By using the standard Stream getters you will get the platform
+ * specific event name automatically.
  */
 class Events {
   /* Raw event target. */
@@ -10645,60 +10361,25 @@
 
   Events(this._ptr);
 
-  EventListenerList operator [](String type) {
-    return new EventListenerList(_ptr, type);
-  }
-}
-
-/**
- * Supports adding, removing, and dispatching events for a specific event type.
- */
-class EventListenerList {
-
-  final EventTarget _ptr;
-  final String _type;
-
-  EventListenerList(this._ptr, this._type);
-
-  // TODO(jacobr): implement equals.
-
-  EventListenerList add(EventListener listener,
-      [bool useCapture = false]) {
-    _add(listener, useCapture);
-    return this;
-  }
-
-  EventListenerList remove(EventListener listener,
-      [bool useCapture = false]) {
-    _remove(listener, useCapture);
-    return this;
-  }
-
-  bool dispatch(Event evt) {
-    return _ptr.dispatchEvent(evt);
-  }
-
-  void _add(EventListener listener, bool useCapture) {
-    _ptr.$dom_addEventListener(_type, listener, useCapture);
-  }
-
-  void _remove(EventListener listener, bool useCapture) {
-    _ptr.$dom_removeEventListener(_type, listener, useCapture);
+  Stream operator [](String type) {
+    return new _EventStream(_ptr, type, false);
   }
 }
 
 /**
  * Base class for all browser objects that support events.
  *
- * Use the [on] property to add, remove, and dispatch events (rather than
- * [$dom_addEventListener], [$dom_dispatchEvent], and
- * [$dom_removeEventListener]) for compile-time type checks and a more concise
- * API.
+ * Use the [on] property to add, and remove events (rather than
+ * [$dom_addEventListener] and [$dom_removeEventListener]
+ * for compile-time type checks and a more concise API.
  */
 @DomName('EventTarget')
 class EventTarget native "*EventTarget" {
 
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
+  /**
+   * This is an ease-of-use accessor for event streams which should only be
+   * used when an explicit accessor is not available.
+   */
   Events get on => new Events(this);
 
   @JSName('addEventListener')
@@ -11175,12 +10856,6 @@
   }
   static FileReader _create_1() => JS('FileReader', 'new FileReader()');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  FileReaderEvents get on =>
-    new FileReaderEvents(this);
-
   static const int DONE = 2;
 
   static const int EMPTY = 0;
@@ -11259,31 +10934,6 @@
   @DocsEditable
   Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class FileReaderEvents extends Events {
-  @DocsEditable
-  FileReaderEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get loadEnd => this['loadend'];
-
-  @DocsEditable
-  EventListenerList get loadStart => this['loadstart'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-}
 // 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.
@@ -11324,6 +10974,8 @@
 
 @DocsEditable
 @DomName('DOMFileSystem')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Experimental
 class FileSystem native "*DOMFileSystem" {
 
   /// Checks if this type is supported on the current platform.
@@ -11352,6 +11004,8 @@
 
 @DocsEditable
 @DomName('DOMFileSystemSync')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Experimental
 class FileSystemSync native "*DOMFileSystemSync" {
 
   @DomName('DOMFileSystemSync.name')
@@ -11395,12 +11049,6 @@
   @DocsEditable
   static const EventStreamProvider<ProgressEvent> writeStartEvent = const EventStreamProvider<ProgressEvent>('writestart');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  FileWriterEvents get on =>
-    new FileWriterEvents(this);
-
   static const int DONE = 2;
 
   static const int INIT = 0;
@@ -11477,31 +11125,6 @@
   @DocsEditable
   Stream<ProgressEvent> get onWriteStart => writeStartEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class FileWriterEvents extends Events {
-  @DocsEditable
-  FileWriterEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-
-  @DocsEditable
-  EventListenerList get write => this['write'];
-
-  @DocsEditable
-  EventListenerList get writeEnd => this['writeend'];
-
-  @DocsEditable
-  EventListenerList get writeStart => this['writestart'];
-}
 // 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.
@@ -13062,12 +12685,6 @@
   }
   static HttpRequest _create_1() => JS('HttpRequest', 'new XMLHttpRequest()');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  HttpRequestEvents get on =>
-    new HttpRequestEvents(this);
-
   static const int DONE = 4;
 
   static const int HEADERS_RECEIVED = 2;
@@ -13342,34 +12959,6 @@
   Stream<ProgressEvent> get onReadyStateChange => readyStateChangeEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class HttpRequestEvents extends Events {
-  @DocsEditable
-  HttpRequestEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get loadEnd => this['loadend'];
-
-  @DocsEditable
-  EventListenerList get loadStart => this['loadstart'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-
-  @DocsEditable
-  EventListenerList get readyStateChange => this['readystatechange'];
-}
 // 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.
@@ -13455,12 +13044,6 @@
   @DocsEditable
   static const EventStreamProvider<ProgressEvent> progressEvent = const EventStreamProvider<ProgressEvent>('progress');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  HttpRequestUploadEvents get on =>
-    new HttpRequestUploadEvents(this);
-
   @JSName('addEventListener')
   @DomName('XMLHttpRequestUpload.addEventListener')
   @DocsEditable
@@ -13499,31 +13082,6 @@
   @DocsEditable
   Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class HttpRequestUploadEvents extends Events {
-  @DocsEditable
-  HttpRequestUploadEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get loadEnd => this['loadend'];
-
-  @DocsEditable
-  EventListenerList get loadStart => this['loadstart'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-}
 // 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.
@@ -13715,12 +13273,6 @@
   @Experimental
   static const EventStreamProvider<Event> speechChangeEvent = const EventStreamProvider<Event>('webkitSpeechChange');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  InputElementEvents get on =>
-    new InputElementEvents(this);
-
   @DomName('HTMLInputElement.accept')
   @DocsEditable
   String accept;
@@ -14554,16 +14106,6 @@
   factory ButtonInputElement() => new InputElement(type: 'button');
 }
 
-
-@DocsEditable
-@deprecated
-class InputElementEvents extends ElementEvents {
-  @DocsEditable
-  InputElementEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get speechChange => this['webkitSpeechChange'];
-}
 // 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.
@@ -15853,12 +15395,6 @@
   @Experimental
   static const EventStreamProvider<MediaKeyEvent> needKeyEvent = const EventStreamProvider<MediaKeyEvent>('webkitneedkey');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  MediaElementEvents get on =>
-    new MediaElementEvents(this);
-
   static const int HAVE_CURRENT_DATA = 2;
 
   static const int HAVE_ENOUGH_DATA = 4;
@@ -16169,88 +15705,6 @@
   @DocsEditable
   Stream<MediaKeyEvent> get onNeedKey => needKeyEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class MediaElementEvents extends ElementEvents {
-  @DocsEditable
-  MediaElementEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get canPlay => this['canplay'];
-
-  @DocsEditable
-  EventListenerList get canPlayThrough => this['canplaythrough'];
-
-  @DocsEditable
-  EventListenerList get durationChange => this['durationchange'];
-
-  @DocsEditable
-  EventListenerList get emptied => this['emptied'];
-
-  @DocsEditable
-  EventListenerList get ended => this['ended'];
-
-  @DocsEditable
-  EventListenerList get loadedData => this['loadeddata'];
-
-  @DocsEditable
-  EventListenerList get loadedMetadata => this['loadedmetadata'];
-
-  @DocsEditable
-  EventListenerList get loadStart => this['loadstart'];
-
-  @DocsEditable
-  EventListenerList get pause => this['pause'];
-
-  @DocsEditable
-  EventListenerList get play => this['play'];
-
-  @DocsEditable
-  EventListenerList get playing => this['playing'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-
-  @DocsEditable
-  EventListenerList get rateChange => this['ratechange'];
-
-  @DocsEditable
-  EventListenerList get seeked => this['seeked'];
-
-  @DocsEditable
-  EventListenerList get seeking => this['seeking'];
-
-  @DocsEditable
-  EventListenerList get show => this['show'];
-
-  @DocsEditable
-  EventListenerList get stalled => this['stalled'];
-
-  @DocsEditable
-  EventListenerList get suspend => this['suspend'];
-
-  @DocsEditable
-  EventListenerList get timeUpdate => this['timeupdate'];
-
-  @DocsEditable
-  EventListenerList get volumeChange => this['volumechange'];
-
-  @DocsEditable
-  EventListenerList get waiting => this['waiting'];
-
-  @DocsEditable
-  EventListenerList get keyAdded => this['webkitkeyadded'];
-
-  @DocsEditable
-  EventListenerList get keyError => this['webkitkeyerror'];
-
-  @DocsEditable
-  EventListenerList get keyMessage => this['webkitkeymessage'];
-
-  @DocsEditable
-  EventListenerList get needKey => this['webkitneedkey'];
-}
 // 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.
@@ -16469,10 +15923,18 @@
 @Experimental
 class MediaStream extends EventTarget native "*MediaStream" {
 
+  @DomName('MediaStream.addtrackEvent')
+  @DocsEditable
+  static const EventStreamProvider<Event> addTrackEvent = const EventStreamProvider<Event>('addtrack');
+
   @DomName('MediaStream.endedEvent')
   @DocsEditable
   static const EventStreamProvider<Event> endedEvent = const EventStreamProvider<Event>('ended');
 
+  @DomName('MediaStream.removetrackEvent')
+  @DocsEditable
+  static const EventStreamProvider<Event> removeTrackEvent = const EventStreamProvider<Event>('removetrack');
+
   @DomName('MediaStream.MediaStream')
   @DocsEditable
   factory MediaStream([stream_OR_tracks]) {
@@ -16491,12 +15953,6 @@
   static MediaStream _create_2(stream_OR_tracks) => JS('MediaStream', 'new MediaStream(#)', stream_OR_tracks);
   static MediaStream _create_3(stream_OR_tracks) => JS('MediaStream', 'new MediaStream(#)', stream_OR_tracks);
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  MediaStreamEvents get on =>
-    new MediaStreamEvents(this);
-
   @DomName('MediaStream.ended')
   @DocsEditable
   final bool ended;
@@ -16543,10 +15999,18 @@
   @DocsEditable
   void removeTrack(MediaStreamTrack track) native;
 
+  @DomName('MediaStream.onaddtrack')
+  @DocsEditable
+  Stream<Event> get onAddTrack => addTrackEvent.forTarget(this);
+
   @DomName('MediaStream.onended')
   @DocsEditable
   Stream<Event> get onEnded => endedEvent.forTarget(this);
 
+  @DomName('MediaStream.onremovetrack')
+  @DocsEditable
+  Stream<Event> get onRemoveTrack => removeTrackEvent.forTarget(this);
+
 
   /**
    * Checks if the MediaStream APIs are supported on the current platform.
@@ -16563,22 +16027,6 @@
         window.navigator,
         window.navigator);
 }
-
-@DocsEditable
-@deprecated
-class MediaStreamEvents extends Events {
-  @DocsEditable
-  MediaStreamEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get addTrack => this['addtrack'];
-
-  @DocsEditable
-  EventListenerList get ended => this['ended'];
-
-  @DocsEditable
-  EventListenerList get removeTrack => this['removetrack'];
-}
 // 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.
@@ -16620,12 +16068,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> unmuteEvent = const EventStreamProvider<Event>('unmute');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  MediaStreamTrackEvents get on =>
-    new MediaStreamTrackEvents(this);
-
   @DomName('MediaStreamTrack.enabled')
   @DocsEditable
   bool enabled;
@@ -16672,22 +16114,6 @@
   @DocsEditable
   Stream<Event> get onUnmute => unmuteEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class MediaStreamTrackEvents extends Events {
-  @DocsEditable
-  MediaStreamTrackEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get ended => this['ended'];
-
-  @DocsEditable
-  EventListenerList get mute => this['mute'];
-
-  @DocsEditable
-  EventListenerList get unmute => this['unmute'];
-}
 // 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.
@@ -16844,12 +16270,6 @@
   @DocsEditable
   static const EventStreamProvider<MessageEvent> messageEvent = const EventStreamProvider<MessageEvent>('message');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  MessagePortEvents get on =>
-    new MessagePortEvents(this);
-
   @JSName('addEventListener')
   @DomName('MessagePort.addEventListener')
   @DocsEditable
@@ -16897,16 +16317,6 @@
   @DocsEditable
   Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class MessagePortEvents extends Events {
-  @DocsEditable
-  MessagePortEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-}
 // 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.
@@ -18300,12 +17710,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> showEvent = const EventStreamProvider<Event>('show');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  NotificationEvents get on =>
-    new NotificationEvents(this);
-
   @DomName('Notification.dir')
   @DocsEditable
   String dir;
@@ -18373,28 +17777,6 @@
   Stream<Event> get onShow => showEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class NotificationEvents extends Events {
-  @DocsEditable
-  NotificationEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get click => this['click'];
-
-  @DocsEditable
-  EventListenerList get close => this['close'];
-
-  @DocsEditable
-  EventListenerList get display => this['display'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get show => this['show'];
-}
 // 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.
@@ -19459,12 +18841,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> openEvent = const EventStreamProvider<Event>('open');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  RtcDataChannelEvents get on =>
-    new RtcDataChannelEvents(this);
-
   @DomName('RTCDataChannel.binaryType')
   @DocsEditable
   String binaryType;
@@ -19523,25 +18899,6 @@
   @DocsEditable
   Stream<Event> get onOpen => openEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class RtcDataChannelEvents extends Events {
-  @DocsEditable
-  RtcDataChannelEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get close => this['close'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get open => this['open'];
-}
 // 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.
@@ -19641,6 +18998,10 @@
   @DocsEditable
   static const EventStreamProvider<RtcDataChannelEvent> dataChannelEvent = const EventStreamProvider<RtcDataChannelEvent>('datachannel');
 
+  @DomName('RTCPeerConnection.gatheringchangeEvent')
+  @DocsEditable
+  static const EventStreamProvider<Event> gatheringChangeEvent = const EventStreamProvider<Event>('gatheringchange');
+
   @DomName('RTCPeerConnection.icecandidateEvent')
   @DocsEditable
   static const EventStreamProvider<RtcIceCandidateEvent> iceCandidateEvent = const EventStreamProvider<RtcIceCandidateEvent>('icecandidate');
@@ -19661,12 +19022,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> stateChangeEvent = const EventStreamProvider<Event>('statechange');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  RtcPeerConnectionEvents get on =>
-    new RtcPeerConnectionEvents(this);
-
   @DomName('RTCPeerConnection.iceConnectionState')
   @DocsEditable
   final String iceConnectionState;
@@ -19857,6 +19212,10 @@
   @DocsEditable
   Stream<RtcDataChannelEvent> get onDataChannel => dataChannelEvent.forTarget(this);
 
+  @DomName('RTCPeerConnection.ongatheringchange')
+  @DocsEditable
+  Stream<Event> get onGatheringChange => gatheringChangeEvent.forTarget(this);
+
   @DomName('RTCPeerConnection.onicecandidate')
   @DocsEditable
   Stream<RtcIceCandidateEvent> get onIceCandidate => iceCandidateEvent.forTarget(this);
@@ -19880,31 +19239,6 @@
 }
 
 
-
-@DocsEditable
-@deprecated
-class RtcPeerConnectionEvents extends Events {
-  @DocsEditable
-  RtcPeerConnectionEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get addStream => this['addstream'];
-
-  @DocsEditable
-  EventListenerList get iceCandidate => this['icecandidate'];
-
-  @DocsEditable
-  EventListenerList get iceChange => this['icechange'];
-
-  @DocsEditable
-  EventListenerList get negotiationNeeded => this['negotiationneeded'];
-
-  @DocsEditable
-  EventListenerList get removeStream => this['removestream'];
-
-  @DocsEditable
-  EventListenerList get stateChange => this['statechange'];
-}
 // 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.
@@ -20409,12 +19743,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> connectEvent = const EventStreamProvider<Event>('connect');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  SharedWorkerContextEvents get on =>
-    new SharedWorkerContextEvents(this);
-
   @DomName('SharedWorkerContext.name')
   @DocsEditable
   final String name;
@@ -20423,16 +19751,6 @@
   @DocsEditable
   Stream<Event> get onConnect => connectEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class SharedWorkerContextEvents extends WorkerContextEvents {
-  @DocsEditable
-  SharedWorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get connect => this['connect'];
-}
 // 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.
@@ -21038,12 +20356,6 @@
   /// Checks if this type is supported on the current platform.
   static bool get supported => JS('bool', '!!(window.SpeechRecognition || window.webkitSpeechRecognition)');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  SpeechRecognitionEvents get on =>
-    new SpeechRecognitionEvents(this);
-
   @DomName('SpeechRecognition.continuous')
   @DocsEditable
   bool continuous;
@@ -21139,46 +20451,6 @@
         'new (window.SpeechRecognition || window.webkitSpeechRecognition)()');
   }
 }
-
-@DocsEditable
-@deprecated
-class SpeechRecognitionEvents extends Events {
-  @DocsEditable
-  SpeechRecognitionEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get audioEnd => this['audioend'];
-
-  @DocsEditable
-  EventListenerList get audioStart => this['audiostart'];
-
-  @DocsEditable
-  EventListenerList get end => this['end'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get noMatch => this['nomatch'];
-
-  @DocsEditable
-  EventListenerList get result => this['result'];
-
-  @DocsEditable
-  EventListenerList get soundEnd => this['soundend'];
-
-  @DocsEditable
-  EventListenerList get soundStart => this['soundstart'];
-
-  @DocsEditable
-  EventListenerList get speechEnd => this['speechend'];
-
-  @DocsEditable
-  EventListenerList get speechStart => this['speechstart'];
-
-  @DocsEditable
-  EventListenerList get start => this['start'];
-}
 // 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.
@@ -22295,12 +21567,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> cueChangeEvent = const EventStreamProvider<Event>('cuechange');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  TextTrackEvents get on =>
-    new TextTrackEvents(this);
-
   @DomName('TextTrack.activeCues')
   @DocsEditable
   final TextTrackCueList activeCues;
@@ -22351,16 +21617,6 @@
   @DocsEditable
   Stream<Event> get onCueChange => cueChangeEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class TextTrackEvents extends Events {
-  @DocsEditable
-  TextTrackEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get cueChange => this['cuechange'];
-}
 // 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.
@@ -22385,12 +21641,6 @@
   }
   static TextTrackCue _create_1(startTime, endTime, text) => JS('TextTrackCue', 'new TextTrackCue(#,#,#)', startTime, endTime, text);
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  TextTrackCueEvents get on =>
-    new TextTrackCueEvents(this);
-
   @DomName('TextTrackCue.align')
   @DocsEditable
   String align;
@@ -22466,19 +21716,6 @@
   @DocsEditable
   Stream<Event> get onExit => exitEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class TextTrackCueEvents extends Events {
-  @DocsEditable
-  TextTrackCueEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get enter => this['enter'];
-
-  @DocsEditable
-  EventListenerList get exit => this['exit'];
-}
 // 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.
@@ -22696,12 +21933,6 @@
   @DocsEditable
   static const EventStreamProvider<TrackEvent> addTrackEvent = const EventStreamProvider<TrackEvent>('addtrack');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  TextTrackListEvents get on =>
-    new TextTrackListEvents(this);
-
   @DomName('TextTrackList.length')
   @DocsEditable
   int get length => JS("int", "#.length", this);
@@ -22911,16 +22142,6 @@
   @DocsEditable
   Stream<TrackEvent> get onAddTrack => addTrackEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class TextTrackListEvents extends Events {
-  @DocsEditable
-  TextTrackListEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get addTrack => this['addtrack'];
-}
 // 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.
@@ -26281,12 +25502,6 @@
   /// Checks if this type is supported on the current platform.
   static bool get supported => JS('bool', 'typeof window.WebSocket != "undefined"');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  WebSocketEvents get on =>
-    new WebSocketEvents(this);
-
   static const int CLOSED = 3;
 
   static const int CLOSING = 2;
@@ -26362,25 +25577,6 @@
   @DocsEditable
   Stream<Event> get onOpen => openEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class WebSocketEvents extends Events {
-  @DocsEditable
-  WebSocketEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get close => this['close'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get open => this['open'];
-}
 // 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.
@@ -26833,12 +26029,6 @@
   @Experimental
   static const EventStreamProvider<AnimationEvent> animationStartEvent = const EventStreamProvider<AnimationEvent>('webkitAnimationStart');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  WindowEvents get on =>
-    new WindowEvents(this);
-
   static const int PERSISTENT = 1;
 
   static const int TEMPORARY = 0;
@@ -27204,11 +26394,17 @@
   @JSName('webkitConvertPointFromNodeToPage')
   @DomName('DOMWindow.webkitConvertPointFromNodeToPage')
   @DocsEditable
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @Experimental
   DomPoint convertPointFromNodeToPage(Node node, DomPoint p) native;
 
   @JSName('webkitConvertPointFromPageToNode')
   @DomName('DOMWindow.webkitConvertPointFromPageToNode')
   @DocsEditable
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @Experimental
   DomPoint convertPointFromPageToNode(Node node, DomPoint p) native;
 
   @JSName('webkitRequestFileSystem')
@@ -27442,235 +26638,6 @@
   Stream<TransitionEvent> get onTransitionEnd => Element.transitionEndEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class WindowEvents extends Events {
-  @DocsEditable
-  WindowEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get contentLoaded => this['DOMContentLoaded'];
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get beforeUnload => this['beforeunload'];
-
-  @DocsEditable
-  EventListenerList get blur => this['blur'];
-
-  @DocsEditable
-  EventListenerList get canPlay => this['canplay'];
-
-  @DocsEditable
-  EventListenerList get canPlayThrough => this['canplaythrough'];
-
-  @DocsEditable
-  EventListenerList get change => this['change'];
-
-  @DocsEditable
-  EventListenerList get click => this['click'];
-
-  @DocsEditable
-  EventListenerList get contextMenu => this['contextmenu'];
-
-  @DocsEditable
-  EventListenerList get doubleClick => this['dblclick'];
-
-  @DocsEditable
-  EventListenerList get deviceMotion => this['devicemotion'];
-
-  @DocsEditable
-  EventListenerList get deviceOrientation => this['deviceorientation'];
-
-  @DocsEditable
-  EventListenerList get drag => this['drag'];
-
-  @DocsEditable
-  EventListenerList get dragEnd => this['dragend'];
-
-  @DocsEditable
-  EventListenerList get dragEnter => this['dragenter'];
-
-  @DocsEditable
-  EventListenerList get dragLeave => this['dragleave'];
-
-  @DocsEditable
-  EventListenerList get dragOver => this['dragover'];
-
-  @DocsEditable
-  EventListenerList get dragStart => this['dragstart'];
-
-  @DocsEditable
-  EventListenerList get drop => this['drop'];
-
-  @DocsEditable
-  EventListenerList get durationChange => this['durationchange'];
-
-  @DocsEditable
-  EventListenerList get emptied => this['emptied'];
-
-  @DocsEditable
-  EventListenerList get ended => this['ended'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get focus => this['focus'];
-
-  @DocsEditable
-  EventListenerList get hashChange => this['hashchange'];
-
-  @DocsEditable
-  EventListenerList get input => this['input'];
-
-  @DocsEditable
-  EventListenerList get invalid => this['invalid'];
-
-  @DocsEditable
-  EventListenerList get keyDown => this['keydown'];
-
-  @DocsEditable
-  EventListenerList get keyPress => this['keypress'];
-
-  @DocsEditable
-  EventListenerList get keyUp => this['keyup'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get loadedData => this['loadeddata'];
-
-  @DocsEditable
-  EventListenerList get loadedMetadata => this['loadedmetadata'];
-
-  @DocsEditable
-  EventListenerList get loadStart => this['loadstart'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get mouseDown => this['mousedown'];
-
-  @DocsEditable
-  EventListenerList get mouseMove => this['mousemove'];
-
-  @DocsEditable
-  EventListenerList get mouseOut => this['mouseout'];
-
-  @DocsEditable
-  EventListenerList get mouseOver => this['mouseover'];
-
-  @DocsEditable
-  EventListenerList get mouseUp => this['mouseup'];
-
-  @DocsEditable
-  EventListenerList get mouseWheel => this['mousewheel'];
-
-  @DocsEditable
-  EventListenerList get offline => this['offline'];
-
-  @DocsEditable
-  EventListenerList get online => this['online'];
-
-  @DocsEditable
-  EventListenerList get pageHide => this['pagehide'];
-
-  @DocsEditable
-  EventListenerList get pageShow => this['pageshow'];
-
-  @DocsEditable
-  EventListenerList get pause => this['pause'];
-
-  @DocsEditable
-  EventListenerList get play => this['play'];
-
-  @DocsEditable
-  EventListenerList get playing => this['playing'];
-
-  @DocsEditable
-  EventListenerList get popState => this['popstate'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-
-  @DocsEditable
-  EventListenerList get rateChange => this['ratechange'];
-
-  @DocsEditable
-  EventListenerList get reset => this['reset'];
-
-  @DocsEditable
-  EventListenerList get resize => this['resize'];
-
-  @DocsEditable
-  EventListenerList get scroll => this['scroll'];
-
-  @DocsEditable
-  EventListenerList get search => this['search'];
-
-  @DocsEditable
-  EventListenerList get seeked => this['seeked'];
-
-  @DocsEditable
-  EventListenerList get seeking => this['seeking'];
-
-  @DocsEditable
-  EventListenerList get select => this['select'];
-
-  @DocsEditable
-  EventListenerList get stalled => this['stalled'];
-
-  @DocsEditable
-  EventListenerList get storage => this['storage'];
-
-  @DocsEditable
-  EventListenerList get submit => this['submit'];
-
-  @DocsEditable
-  EventListenerList get suspend => this['suspend'];
-
-  @DocsEditable
-  EventListenerList get timeUpdate => this['timeupdate'];
-
-  @DocsEditable
-  EventListenerList get touchCancel => this['touchcancel'];
-
-  @DocsEditable
-  EventListenerList get touchEnd => this['touchend'];
-
-  @DocsEditable
-  EventListenerList get touchMove => this['touchmove'];
-
-  @DocsEditable
-  EventListenerList get touchStart => this['touchstart'];
-
-  @DocsEditable
-  EventListenerList get unload => this['unload'];
-
-  @DocsEditable
-  EventListenerList get volumeChange => this['volumechange'];
-
-  @DocsEditable
-  EventListenerList get waiting => this['waiting'];
-
-  @DocsEditable
-  EventListenerList get animationEnd => this['webkitAnimationEnd'];
-
-  @DocsEditable
-  EventListenerList get animationIteration => this['webkitAnimationIteration'];
-
-  @DocsEditable
-  EventListenerList get animationStart => this['webkitAnimationStart'];
-
-  @DocsEditable
-  EventListenerList get transitionEnd => this['webkitTransitionEnd'];
-}
 // 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.
@@ -27691,12 +26658,6 @@
   }
   static Worker _create_1(scriptUrl) => JS('Worker', 'new Worker(#)', scriptUrl);
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  WorkerEvents get on =>
-    new WorkerEvents(this);
-
   @DomName('Worker.postMessage')
   @DocsEditable
   void postMessage(/*SerializedScriptValue*/ message, [List messagePorts]) {
@@ -27726,16 +26687,6 @@
   @DocsEditable
   Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class WorkerEvents extends AbstractWorkerEvents {
-  @DocsEditable
-  WorkerEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-}
 // 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.
@@ -27748,12 +26699,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  WorkerContextEvents get on =>
-    new WorkerContextEvents(this);
-
   static const int PERSISTENT = 1;
 
   static const int TEMPORARY = 0;
@@ -27878,16 +26823,6 @@
          '#.indexedDB || #.webkitIndexedDB || #.mozIndexedDB',
          this, this, this);
 }
-
-@DocsEditable
-@deprecated
-class WorkerContextEvents extends Events {
-  @DocsEditable
-  WorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-}
 // 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.
@@ -29438,58 +28373,6 @@
 @DocsEditable
 @DomName('HTMLFrameSetElement')
 class _HTMLFrameSetElement extends Element native "*HTMLFrameSetElement" {
-
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  _HTMLFrameSetElementEvents get on =>
-    new _HTMLFrameSetElementEvents(this);
-}
-
-@DocsEditable
-@deprecated
-class _HTMLFrameSetElementEvents extends ElementEvents {
-  @DocsEditable
-  _HTMLFrameSetElementEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get beforeUnload => this['beforeunload'];
-
-  @DocsEditable
-  EventListenerList get blur => this['blur'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get focus => this['focus'];
-
-  @DocsEditable
-  EventListenerList get hashChange => this['hashchange'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get offline => this['offline'];
-
-  @DocsEditable
-  EventListenerList get online => this['online'];
-
-  @DocsEditable
-  EventListenerList get popState => this['popstate'];
-
-  @DocsEditable
-  EventListenerList get resize => this['resize'];
-
-  @DocsEditable
-  EventListenerList get storage => this['storage'];
-
-  @DocsEditable
-  EventListenerList get unload => this['unload'];
 }
 // 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
@@ -32632,12 +31515,10 @@
     // TODO(vsm): Set this up set once, on the first call.
     var source = '$target-result';
     var result = null;
-    var listener = (Event e) {
+    window.on[source].first.then((Event e) {
       result = json.parse(_getPortSyncEventData(e));
-    };
-    window.on[source].add(listener);
+    });
     _dispatchEvent(target, [source, message]);
-    window.on[source].remove(listener);
     return result;
   }
 
@@ -32692,7 +31573,7 @@
 
   num _portId;
   Function _callback;
-  EventListener _listener;
+  StreamSubscription _portSubscription;
 
   ReceivePortSync() {
     if (_portIdCount == null) {
@@ -32717,21 +31598,20 @@
 
   void receive(callback(var message)) {
     _callback = callback;
-    if (_listener == null) {
-      _listener = (Event e) {
+    if (_portSubscription == null) {
+      _portSubscription = window.on[_listenerName].listen((Event e) {
         var data = json.parse(_getPortSyncEventData(e));
         var replyTo = data[0];
         var message = _deserialize(data[1]);
         var result = _callback(message);
         _dispatchEvent(replyTo, _serialize(result));
-      };
-      window.on[_listenerName].add(_listener);
+      });
     }
   }
 
   void close() {
     _portMap.remove(_portId);
-    if (_listener != null) window.on[_listenerName].remove(_listener);
+    if (_portSubscription != null) _portSubscription.cancel();
   }
 
   SendPortSync toSendPort() {
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index c5cd920..dfe5485 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -54,9 +54,9 @@
 
 _callPortSync(num id, var message) {
   if (!_callPortInitialized) {
-    window.on['js-result'].add((event) {
+    window.on['js-result'].listen((event) {
       _callPortLastResult = json.parse(_getPortSyncEventData(event));
-    }, false);
+    });
     _callPortInitialized = true;
   }
   assert(_callPortLastResult == null);
@@ -81,12 +81,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  AbstractWorkerEvents get on =>
-    new AbstractWorkerEvents(this);
-
   @DomName('AbstractWorker.addEventListener')
   @DocsEditable
   void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native "AbstractWorker_addEventListener_Callback";
@@ -104,16 +98,6 @@
   Stream<Event> get onError => errorEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class AbstractWorkerEvents extends Events {
-  @DocsEditable
-  AbstractWorkerEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-}
 // 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.
@@ -336,12 +320,6 @@
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  ApplicationCacheEvents get on =>
-    new ApplicationCacheEvents(this);
-
   static const int CHECKING = 2;
 
   static const int DOWNLOADING = 3;
@@ -415,37 +393,6 @@
   Stream<Event> get onUpdateReady => updateReadyEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class ApplicationCacheEvents extends Events {
-  @DocsEditable
-  ApplicationCacheEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get cached => this['cached'];
-
-  @DocsEditable
-  EventListenerList get checking => this['checking'];
-
-  @DocsEditable
-  EventListenerList get downloading => this['downloading'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get noUpdate => this['noupdate'];
-
-  @DocsEditable
-  EventListenerList get obsolete => this['obsolete'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-
-  @DocsEditable
-  EventListenerList get updateReady => this['updateready'];
-}
 // 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.
@@ -751,12 +698,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> levelChangeEvent = const EventStreamProvider<Event>('levelchange');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  BatteryManagerEvents get on =>
-    new BatteryManagerEvents(this);
-
   @DomName('BatteryManager.charging')
   @DocsEditable
   bool get charging native "BatteryManager_charging_Getter";
@@ -802,25 +743,6 @@
   Stream<Event> get onLevelChange => levelChangeEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class BatteryManagerEvents extends Events {
-  @DocsEditable
-  BatteryManagerEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get chargingChange => this['chargingchange'];
-
-  @DocsEditable
-  EventListenerList get chargingTimeChange => this['chargingtimechange'];
-
-  @DocsEditable
-  EventListenerList get dischargingTimeChange => this['dischargingtimechange'];
-
-  @DocsEditable
-  EventListenerList get levelChange => this['levelchange'];
-}
 // 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.
@@ -958,12 +880,6 @@
   @DocsEditable
   factory BodyElement() => document.$dom_createElement("body");
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  BodyElementEvents get on =>
-    new BodyElementEvents(this);
-
   @DomName('HTMLBodyElement.onbeforeunload')
   @DocsEditable
   Stream<Event> get onBeforeUnload => beforeUnloadEvent.forTarget(this);
@@ -1017,52 +933,6 @@
   Stream<Event> get onUnload => unloadEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class BodyElementEvents extends ElementEvents {
-  @DocsEditable
-  BodyElementEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get beforeUnload => this['beforeunload'];
-
-  @DocsEditable
-  EventListenerList get blur => this['blur'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get focus => this['focus'];
-
-  @DocsEditable
-  EventListenerList get hashChange => this['hashchange'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get offline => this['offline'];
-
-  @DocsEditable
-  EventListenerList get online => this['online'];
-
-  @DocsEditable
-  EventListenerList get popState => this['popstate'];
-
-  @DocsEditable
-  EventListenerList get resize => this['resize'];
-
-  @DocsEditable
-  EventListenerList get storage => this['storage'];
-
-  @DocsEditable
-  EventListenerList get unload => this['unload'];
-}
 // 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.
@@ -6963,12 +6833,6 @@
   @DocsEditable
   static const EventStreamProvider<MessageEvent> messageEvent = const EventStreamProvider<MessageEvent>('message');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  DedicatedWorkerContextEvents get on =>
-    new DedicatedWorkerContextEvents(this);
-
   @DomName('DedicatedWorkerContext.postMessage')
   @DocsEditable
   void postMessage(Object message, [List messagePorts]) native "DedicatedWorkerContext_postMessage_Callback";
@@ -6978,16 +6842,6 @@
   Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class DedicatedWorkerContextEvents extends WorkerContextEvents {
-  @DocsEditable
-  DedicatedWorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-}
 // 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.
@@ -7248,12 +7102,6 @@
   @Experimental
   static const EventStreamProvider<Event> pointerLockErrorEvent = const EventStreamProvider<Event>('webkitpointerlockerror');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  DocumentEvents get on =>
-    new DocumentEvents(this);
-
   /// Moved to [HtmlDocument].
   @DomName('Document.body')
   @DocsEditable
@@ -7774,25 +7622,6 @@
     }
   }
 }
-
-@DocsEditable
-@deprecated
-class DocumentEvents extends ElementEvents {
-  @DocsEditable
-  DocumentEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get readyStateChange => this['readystatechange'];
-
-  @DocsEditable
-  EventListenerList get selectionChange => this['selectionchange'];
-
-  @DocsEditable
-  EventListenerList get pointerLockChange => this['webkitpointerlockchange'];
-
-  @DocsEditable
-  EventListenerList get pointerLockError => this['webkitpointerlockerror'];
-}
 // 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.
@@ -7876,12 +7705,6 @@
 
   DocumentFragment.internal() : super.internal();
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  ElementEvents get on =>
-    new ElementEvents(this);
-
   @DomName('DocumentFragment.querySelector')
   @DocsEditable
   Element $dom_querySelector(String selectors) native "DocumentFragment_querySelector_Callback";
@@ -9727,6 +9550,40 @@
    */
   var xtag;
 
+  /**
+   * Scrolls this element into view.
+   *
+   * Only one of of the alignment options may be specified at a time.
+   *
+   * If no options are specified then this will attempt to scroll the minimum
+   * amount needed to bring the element into view.
+   *
+   * Note that alignCenter is currently only supported on WebKit platforms. If
+   * alignCenter is specified but not supported then this will fall back to
+   * alignTop.
+   *
+   * See also:
+   *
+   * * [scrollIntoView](http://docs.webplatform.org/wiki/dom/methods/scrollIntoView)
+   * * [scrollIntoViewIfNeeded](http://docs.webplatform.org/wiki/dom/methods/scrollIntoViewIfNeeded)
+   */
+  void scrollIntoView([ScrollAlignment alignment]) {
+    var hasScrollIntoViewIfNeeded = false;
+    if (alignment == ScrollAlignment.TOP) {
+      this.$dom_scrollIntoView(true);
+    } else if (alignment == ScrollAlignment.BOTTOM) {
+      this.$dom_scrollIntoView(false);
+    } else if (hasScrollIntoViewIfNeeded) {
+      if (alignment == ScrollAlignment.CENTER) {
+        this.$dom_scrollIntoViewIfNeeded(true);
+      } else {
+        this.$dom_scrollIntoViewIfNeeded();
+      }
+    } else {
+      this.$dom_scrollIntoView();
+    }
+  }
+
 
   Element.internal() : super.internal();
 
@@ -9931,12 +9788,6 @@
   @Experimental
   static const EventStreamProvider<Event> fullscreenErrorEvent = const EventStreamProvider<Event>('webkitfullscreenerror');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  ElementEvents get on =>
-    new ElementEvents(this);
-
   HtmlCollection get $dom_children;
 
   String contentEditable;
@@ -10166,7 +10017,24 @@
   @DocsEditable
   void scrollByPages(int pages) native "Element_scrollByPages_Callback";
 
-  void scrollIntoView([bool centerIfNeeded]) {
+  void $dom_scrollIntoView([bool alignWithTop]) {
+    if (?alignWithTop) {
+      _scrollIntoView_1(alignWithTop);
+      return;
+    }
+    _scrollIntoView_2();
+    return;
+  }
+
+  @DomName('Element._scrollIntoView_1')
+  @DocsEditable
+  void _scrollIntoView_1(alignWithTop) native "Element__scrollIntoView_1_Callback";
+
+  @DomName('Element._scrollIntoView_2')
+  @DocsEditable
+  void _scrollIntoView_2() native "Element__scrollIntoView_2_Callback";
+
+  void $dom_scrollIntoViewIfNeeded([bool centerIfNeeded]) {
     if (?centerIfNeeded) {
       _scrollIntoViewIfNeeded_1(centerIfNeeded);
       return;
@@ -10552,155 +10420,21 @@
       document.$dom_createElement(tag);
 }
 
-@DocsEditable
-@deprecated
-class ElementEvents extends Events {
-  @DocsEditable
-  ElementEvents(EventTarget _ptr) : super(_ptr);
 
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
+/**
+ * Options for Element.scrollIntoView.
+ */
+class ScrollAlignment {
+  final _value;
+  const ScrollAlignment._internal(this._value);
+  toString() => 'ScrollAlignment.$_value';
 
-  @DocsEditable
-  EventListenerList get beforeCopy => this['beforecopy'];
-
-  @DocsEditable
-  EventListenerList get beforeCut => this['beforecut'];
-
-  @DocsEditable
-  EventListenerList get beforePaste => this['beforepaste'];
-
-  @DocsEditable
-  EventListenerList get blur => this['blur'];
-
-  @DocsEditable
-  EventListenerList get change => this['change'];
-
-  @DocsEditable
-  EventListenerList get click => this['click'];
-
-  @DocsEditable
-  EventListenerList get contextMenu => this['contextmenu'];
-
-  @DocsEditable
-  EventListenerList get copy => this['copy'];
-
-  @DocsEditable
-  EventListenerList get cut => this['cut'];
-
-  @DocsEditable
-  EventListenerList get doubleClick => this['dblclick'];
-
-  @DocsEditable
-  EventListenerList get drag => this['drag'];
-
-  @DocsEditable
-  EventListenerList get dragEnd => this['dragend'];
-
-  @DocsEditable
-  EventListenerList get dragEnter => this['dragenter'];
-
-  @DocsEditable
-  EventListenerList get dragLeave => this['dragleave'];
-
-  @DocsEditable
-  EventListenerList get dragOver => this['dragover'];
-
-  @DocsEditable
-  EventListenerList get dragStart => this['dragstart'];
-
-  @DocsEditable
-  EventListenerList get drop => this['drop'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get focus => this['focus'];
-
-  @DocsEditable
-  EventListenerList get input => this['input'];
-
-  @DocsEditable
-  EventListenerList get invalid => this['invalid'];
-
-  @DocsEditable
-  EventListenerList get keyDown => this['keydown'];
-
-  @DocsEditable
-  EventListenerList get keyPress => this['keypress'];
-
-  @DocsEditable
-  EventListenerList get keyUp => this['keyup'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get mouseDown => this['mousedown'];
-
-  @DocsEditable
-  EventListenerList get mouseMove => this['mousemove'];
-
-  @DocsEditable
-  EventListenerList get mouseOut => this['mouseout'];
-
-  @DocsEditable
-  EventListenerList get mouseOver => this['mouseover'];
-
-  @DocsEditable
-  EventListenerList get mouseUp => this['mouseup'];
-
-  @DocsEditable
-  EventListenerList get mouseWheel => this['mousewheel'];
-
-  @DocsEditable
-  EventListenerList get paste => this['paste'];
-
-  @DocsEditable
-  EventListenerList get reset => this['reset'];
-
-  @DocsEditable
-  EventListenerList get scroll => this['scroll'];
-
-  @DocsEditable
-  EventListenerList get search => this['search'];
-
-  @DocsEditable
-  EventListenerList get select => this['select'];
-
-  @DocsEditable
-  EventListenerList get selectStart => this['selectstart'];
-
-  @DocsEditable
-  EventListenerList get submit => this['submit'];
-
-  @DocsEditable
-  EventListenerList get touchCancel => this['touchcancel'];
-
-  @DocsEditable
-  EventListenerList get touchEnd => this['touchend'];
-
-  @DocsEditable
-  EventListenerList get touchEnter => this['touchenter'];
-
-  @DocsEditable
-  EventListenerList get touchLeave => this['touchleave'];
-
-  @DocsEditable
-  EventListenerList get touchMove => this['touchmove'];
-
-  @DocsEditable
-  EventListenerList get touchStart => this['touchstart'];
-
-  @DocsEditable
-  EventListenerList get transitionEnd => this['webkitTransitionEnd'];
-
-  @DocsEditable
-  EventListenerList get fullscreenChange => this['webkitfullscreenchange'];
-
-  @DocsEditable
-  EventListenerList get fullscreenError => this['webkitfullscreenerror'];
+  /// Attempt to align the element to the top of the scrollable area.
+  static const TOP = const ScrollAlignment._internal('TOP');
+  /// Attempt to center the element in the scrollable area.
+  static const CENTER = const ScrollAlignment._internal('CENTER');
+  /// Attempt to align the element to the bottom of the scrollable area.
+  static const BOTTOM = const ScrollAlignment._internal('BOTTOM');
 }
 // 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
@@ -11232,12 +10966,6 @@
   @DocsEditable
   static EventSource _create_1(url, eventSourceInit) native "EventSource__create_1constructorCallback";
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  EventSourceEvents get on =>
-    new EventSourceEvents(this);
-
   static const int CLOSED = 2;
 
   static const int CONNECTING = 0;
@@ -11285,22 +11013,6 @@
   Stream<Event> get onOpen => openEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class EventSourceEvents extends Events {
-  @DocsEditable
-  EventSourceEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get open => this['open'];
-}
 // 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.
@@ -11309,15 +11021,38 @@
 /**
  * Base class that supports listening for and dispatching browser events.
  *
- * Events can either be accessed by string name (using the indexed getter) or by
- * getters exposed by subclasses. Use the getters exposed by subclasses when
- * possible for better compile-time type checks.
+ * Normally events are accessed via the Stream getter:
  *
- * Using an indexed getter:
- *     events['mouseover'].add((e) => print("Mouse over!"));
+ *     element.onMouseOver.listen((e) => print('Mouse over!'));
  *
- * Using a getter provided by a subclass:
- *     elementEvents.mouseOver.add((e) => print("Mouse over!"));
+ * To access bubbling events which are declared on one element, but may bubble
+ * up to another element type (common for MediaElement events):
+ *
+ *     MediaElement.pauseEvent.forTarget(document.body).listen(...);
+ *
+ * To useCapture on events:
+ *
+ *     Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
+ *
+ * Custom events can be declared as:
+ *
+ *    class DataGenerator {
+ *      static EventStreamProvider<Event> dataEvent =
+ *          new EventStreamProvider('data');
+ *    }
+ *
+ * Then listeners should access the event with:
+ *
+ *     DataGenerator.dataEvent.forTarget(element).listen(...);
+ *
+ * Custom events can also be accessed as:
+ *
+ *     element.on['some_event'].listen(...);
+ *
+ * This approach is generally discouraged as it loses the event typing and
+ * some DOM events may have multiple platform-dependent event names under the
+ * covers. By using the standard Stream getters you will get the platform
+ * specific event name automatically.
  */
 class Events {
   /* Raw event target. */
@@ -11325,60 +11060,25 @@
 
   Events(this._ptr);
 
-  EventListenerList operator [](String type) {
-    return new EventListenerList(_ptr, type);
-  }
-}
-
-/**
- * Supports adding, removing, and dispatching events for a specific event type.
- */
-class EventListenerList {
-
-  final EventTarget _ptr;
-  final String _type;
-
-  EventListenerList(this._ptr, this._type);
-
-  // TODO(jacobr): implement equals.
-
-  EventListenerList add(EventListener listener,
-      [bool useCapture = false]) {
-    _add(listener, useCapture);
-    return this;
-  }
-
-  EventListenerList remove(EventListener listener,
-      [bool useCapture = false]) {
-    _remove(listener, useCapture);
-    return this;
-  }
-
-  bool dispatch(Event evt) {
-    return _ptr.dispatchEvent(evt);
-  }
-
-  void _add(EventListener listener, bool useCapture) {
-    _ptr.$dom_addEventListener(_type, listener, useCapture);
-  }
-
-  void _remove(EventListener listener, bool useCapture) {
-    _ptr.$dom_removeEventListener(_type, listener, useCapture);
+  Stream operator [](String type) {
+    return new _EventStream(_ptr, type, false);
   }
 }
 
 /**
  * Base class for all browser objects that support events.
  *
- * Use the [on] property to add, remove, and dispatch events (rather than
- * [$dom_addEventListener], [$dom_dispatchEvent], and
- * [$dom_removeEventListener]) for compile-time type checks and a more concise
- * API.
+ * Use the [on] property to add, and remove events (rather than
+ * [$dom_addEventListener] and [$dom_removeEventListener]
+ * for compile-time type checks and a more concise API.
  */
 @DomName('EventTarget')
 class EventTarget extends NativeFieldWrapperClass1 {
 
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
+  /**
+   * This is an ease-of-use accessor for event streams which should only be
+   * used when an explicit accessor is not available.
+   */
   Events get on => new Events(this);
   EventTarget.internal();
 
@@ -11898,12 +11598,6 @@
   @DocsEditable
   static FileReader _create_1() native "FileReader__create_1constructorCallback";
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  FileReaderEvents get on =>
-    new FileReaderEvents(this);
-
   static const int DONE = 2;
 
   static const int EMPTY = 0;
@@ -11992,31 +11686,6 @@
   Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class FileReaderEvents extends Events {
-  @DocsEditable
-  FileReaderEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get loadEnd => this['loadend'];
-
-  @DocsEditable
-  EventListenerList get loadStart => this['loadstart'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-}
 // 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.
@@ -12075,6 +11744,8 @@
 
 @DocsEditable
 @DomName('DOMFileSystem')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Experimental
 class FileSystem extends NativeFieldWrapperClass1 {
   FileSystem.internal();
 
@@ -12107,6 +11778,8 @@
 
 @DocsEditable
 @DomName('DOMFileSystemSync')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Experimental
 class FileSystemSync extends NativeFieldWrapperClass1 {
   FileSystemSync.internal();
 
@@ -12155,12 +11828,6 @@
   @DocsEditable
   static const EventStreamProvider<ProgressEvent> writeStartEvent = const EventStreamProvider<ProgressEvent>('writestart');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  FileWriterEvents get on =>
-    new FileWriterEvents(this);
-
   static const int DONE = 2;
 
   static const int INIT = 0;
@@ -12236,31 +11903,6 @@
   Stream<ProgressEvent> get onWriteStart => writeStartEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class FileWriterEvents extends Events {
-  @DocsEditable
-  FileWriterEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-
-  @DocsEditable
-  EventListenerList get write => this['write'];
-
-  @DocsEditable
-  EventListenerList get writeEnd => this['writeend'];
-
-  @DocsEditable
-  EventListenerList get writeStart => this['writestart'];
-}
 // 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.
@@ -13944,12 +13586,6 @@
   @DocsEditable
   static HttpRequest _create_1() native "XMLHttpRequest__create_1constructorCallback";
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  HttpRequestEvents get on =>
-    new HttpRequestEvents(this);
-
   static const int DONE = 4;
 
   static const int HEADERS_RECEIVED = 2;
@@ -14244,34 +13880,6 @@
   Stream<ProgressEvent> get onReadyStateChange => readyStateChangeEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class HttpRequestEvents extends Events {
-  @DocsEditable
-  HttpRequestEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get loadEnd => this['loadend'];
-
-  @DocsEditable
-  EventListenerList get loadStart => this['loadstart'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-
-  @DocsEditable
-  EventListenerList get readyStateChange => this['readystatechange'];
-}
 // 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.
@@ -14368,12 +13976,6 @@
   @DocsEditable
   static const EventStreamProvider<ProgressEvent> progressEvent = const EventStreamProvider<ProgressEvent>('progress');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  HttpRequestUploadEvents get on =>
-    new HttpRequestUploadEvents(this);
-
   @DomName('XMLHttpRequestUpload.addEventListener')
   @DocsEditable
   void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native "XMLHttpRequestUpload_addEventListener_Callback";
@@ -14411,31 +14013,6 @@
   Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class HttpRequestUploadEvents extends Events {
-  @DocsEditable
-  HttpRequestUploadEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get loadEnd => this['loadend'];
-
-  @DocsEditable
-  EventListenerList get loadStart => this['loadstart'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-}
 // 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.
@@ -14701,12 +14278,6 @@
   @Experimental
   static const EventStreamProvider<Event> speechChangeEvent = const EventStreamProvider<Event>('webkitSpeechChange');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  InputElementEvents get on =>
-    new InputElementEvents(this);
-
   @DomName('HTMLInputElement.accept')
   @DocsEditable
   String get accept native "HTMLInputElement_accept_Getter";
@@ -15749,16 +15320,6 @@
   factory ButtonInputElement() => new InputElement(type: 'button');
 }
 
-
-@DocsEditable
-@deprecated
-class InputElementEvents extends ElementEvents {
-  @DocsEditable
-  InputElementEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get speechChange => this['webkitSpeechChange'];
-}
 // 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.
@@ -17244,12 +16805,6 @@
   @Experimental
   static const EventStreamProvider<MediaKeyEvent> needKeyEvent = const EventStreamProvider<MediaKeyEvent>('webkitneedkey');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  MediaElementEvents get on =>
-    new MediaElementEvents(this);
-
   static const int HAVE_CURRENT_DATA = 2;
 
   static const int HAVE_ENOUGH_DATA = 4;
@@ -17657,88 +17212,6 @@
   Stream<MediaKeyEvent> get onNeedKey => needKeyEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class MediaElementEvents extends ElementEvents {
-  @DocsEditable
-  MediaElementEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get canPlay => this['canplay'];
-
-  @DocsEditable
-  EventListenerList get canPlayThrough => this['canplaythrough'];
-
-  @DocsEditable
-  EventListenerList get durationChange => this['durationchange'];
-
-  @DocsEditable
-  EventListenerList get emptied => this['emptied'];
-
-  @DocsEditable
-  EventListenerList get ended => this['ended'];
-
-  @DocsEditable
-  EventListenerList get loadedData => this['loadeddata'];
-
-  @DocsEditable
-  EventListenerList get loadedMetadata => this['loadedmetadata'];
-
-  @DocsEditable
-  EventListenerList get loadStart => this['loadstart'];
-
-  @DocsEditable
-  EventListenerList get pause => this['pause'];
-
-  @DocsEditable
-  EventListenerList get play => this['play'];
-
-  @DocsEditable
-  EventListenerList get playing => this['playing'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-
-  @DocsEditable
-  EventListenerList get rateChange => this['ratechange'];
-
-  @DocsEditable
-  EventListenerList get seeked => this['seeked'];
-
-  @DocsEditable
-  EventListenerList get seeking => this['seeking'];
-
-  @DocsEditable
-  EventListenerList get show => this['show'];
-
-  @DocsEditable
-  EventListenerList get stalled => this['stalled'];
-
-  @DocsEditable
-  EventListenerList get suspend => this['suspend'];
-
-  @DocsEditable
-  EventListenerList get timeUpdate => this['timeupdate'];
-
-  @DocsEditable
-  EventListenerList get volumeChange => this['volumechange'];
-
-  @DocsEditable
-  EventListenerList get waiting => this['waiting'];
-
-  @DocsEditable
-  EventListenerList get keyAdded => this['webkitkeyadded'];
-
-  @DocsEditable
-  EventListenerList get keyError => this['webkitkeyerror'];
-
-  @DocsEditable
-  EventListenerList get keyMessage => this['webkitkeymessage'];
-
-  @DocsEditable
-  EventListenerList get needKey => this['webkitneedkey'];
-}
 // 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.
@@ -17996,10 +17469,18 @@
 class MediaStream extends EventTarget {
   MediaStream.internal() : super.internal();
 
+  @DomName('MediaStream.addtrackEvent')
+  @DocsEditable
+  static const EventStreamProvider<Event> addTrackEvent = const EventStreamProvider<Event>('addtrack');
+
   @DomName('MediaStream.endedEvent')
   @DocsEditable
   static const EventStreamProvider<Event> endedEvent = const EventStreamProvider<Event>('ended');
 
+  @DomName('MediaStream.removetrackEvent')
+  @DocsEditable
+  static const EventStreamProvider<Event> removeTrackEvent = const EventStreamProvider<Event>('removetrack');
+
   @DomName('MediaStream.MediaStream')
   @DocsEditable
   factory MediaStream([stream_OR_tracks]) {
@@ -18024,12 +17505,6 @@
   @DocsEditable
   static MediaStream _create_3(stream_OR_tracks) native "MediaStream__create_3constructorCallback";
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  MediaStreamEvents get on =>
-    new MediaStreamEvents(this);
-
   @DomName('MediaStream.ended')
   @DocsEditable
   bool get ended native "MediaStream_ended_Getter";
@@ -18074,10 +17549,18 @@
   @DocsEditable
   void removeTrack(MediaStreamTrack track) native "MediaStream_removeTrack_Callback";
 
+  @DomName('MediaStream.onaddtrack')
+  @DocsEditable
+  Stream<Event> get onAddTrack => addTrackEvent.forTarget(this);
+
   @DomName('MediaStream.onended')
   @DocsEditable
   Stream<Event> get onEnded => endedEvent.forTarget(this);
 
+  @DomName('MediaStream.onremovetrack')
+  @DocsEditable
+  Stream<Event> get onRemoveTrack => removeTrackEvent.forTarget(this);
+
 
   /**
    * Checks if the MediaStream APIs are supported on the current platform.
@@ -18088,22 +17571,6 @@
    */
   static bool get supported => true;
 }
-
-@DocsEditable
-@deprecated
-class MediaStreamEvents extends Events {
-  @DocsEditable
-  MediaStreamEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get addTrack => this['addtrack'];
-
-  @DocsEditable
-  EventListenerList get ended => this['ended'];
-
-  @DocsEditable
-  EventListenerList get removeTrack => this['removetrack'];
-}
 // 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.
@@ -18152,12 +17619,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> unmuteEvent = const EventStreamProvider<Event>('unmute');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  MediaStreamTrackEvents get on =>
-    new MediaStreamTrackEvents(this);
-
   @DomName('MediaStreamTrack.enabled')
   @DocsEditable
   bool get enabled native "MediaStreamTrack_enabled_Getter";
@@ -18207,22 +17668,6 @@
   Stream<Event> get onUnmute => unmuteEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class MediaStreamTrackEvents extends Events {
-  @DocsEditable
-  MediaStreamTrackEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get ended => this['ended'];
-
-  @DocsEditable
-  EventListenerList get mute => this['mute'];
-
-  @DocsEditable
-  EventListenerList get unmute => this['unmute'];
-}
 // 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.
@@ -18391,12 +17836,6 @@
   @DocsEditable
   static const EventStreamProvider<MessageEvent> messageEvent = const EventStreamProvider<MessageEvent>('message');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  MessagePortEvents get on =>
-    new MessagePortEvents(this);
-
   @DomName('MessagePort.addEventListener')
   @DocsEditable
   void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native "MessagePort_addEventListener_Callback";
@@ -18426,16 +17865,6 @@
   Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class MessagePortEvents extends Events {
-  @DocsEditable
-  MessagePortEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-}
 // 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.
@@ -19826,12 +19255,6 @@
   @DocsEditable
   static Notification _create_1(title, options) native "Notification__create_1constructorCallback";
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  NotificationEvents get on =>
-    new NotificationEvents(this);
-
   @DomName('Notification.dir')
   @DocsEditable
   String get dir native "Notification_dir_Getter";
@@ -19909,28 +19332,6 @@
   Stream<Event> get onShow => showEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class NotificationEvents extends Events {
-  @DocsEditable
-  NotificationEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get click => this['click'];
-
-  @DocsEditable
-  EventListenerList get close => this['close'];
-
-  @DocsEditable
-  EventListenerList get display => this['display'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get show => this['show'];
-}
 // 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.
@@ -21198,12 +20599,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> openEvent = const EventStreamProvider<Event>('open');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  RtcDataChannelEvents get on =>
-    new RtcDataChannelEvents(this);
-
   @DomName('RTCDataChannel.binaryType')
   @DocsEditable
   String get binaryType native "RTCDataChannel_binaryType_Getter";
@@ -21297,25 +20692,6 @@
   Stream<Event> get onOpen => openEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class RtcDataChannelEvents extends Events {
-  @DocsEditable
-  RtcDataChannelEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get close => this['close'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get open => this['open'];
-}
 // 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.
@@ -21411,6 +20787,10 @@
   @DocsEditable
   static const EventStreamProvider<RtcDataChannelEvent> dataChannelEvent = const EventStreamProvider<RtcDataChannelEvent>('datachannel');
 
+  @DomName('RTCPeerConnection.gatheringchangeEvent')
+  @DocsEditable
+  static const EventStreamProvider<Event> gatheringChangeEvent = const EventStreamProvider<Event>('gatheringchange');
+
   @DomName('RTCPeerConnection.icecandidateEvent')
   @DocsEditable
   static const EventStreamProvider<RtcIceCandidateEvent> iceCandidateEvent = const EventStreamProvider<RtcIceCandidateEvent>('icecandidate');
@@ -21440,12 +20820,6 @@
   @DocsEditable
   static RtcPeerConnection _create_1(rtcIceServers, mediaConstraints) native "RTCPeerConnection__create_1constructorCallback";
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  RtcPeerConnectionEvents get on =>
-    new RtcPeerConnectionEvents(this);
-
   @DomName('RTCPeerConnection.iceConnectionState')
   @DocsEditable
   String get iceConnectionState native "RTCPeerConnection_iceConnectionState_Getter";
@@ -21542,6 +20916,10 @@
   @DocsEditable
   Stream<RtcDataChannelEvent> get onDataChannel => dataChannelEvent.forTarget(this);
 
+  @DomName('RTCPeerConnection.ongatheringchange')
+  @DocsEditable
+  Stream<Event> get onGatheringChange => gatheringChangeEvent.forTarget(this);
+
   @DomName('RTCPeerConnection.onicecandidate')
   @DocsEditable
   Stream<RtcIceCandidateEvent> get onIceCandidate => iceCandidateEvent.forTarget(this);
@@ -21565,31 +20943,6 @@
 }
 
 
-
-@DocsEditable
-@deprecated
-class RtcPeerConnectionEvents extends Events {
-  @DocsEditable
-  RtcPeerConnectionEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get addStream => this['addstream'];
-
-  @DocsEditable
-  EventListenerList get iceCandidate => this['icecandidate'];
-
-  @DocsEditable
-  EventListenerList get iceChange => this['icechange'];
-
-  @DocsEditable
-  EventListenerList get negotiationNeeded => this['negotiationneeded'];
-
-  @DocsEditable
-  EventListenerList get removeStream => this['removestream'];
-
-  @DocsEditable
-  EventListenerList get stateChange => this['statechange'];
-}
 // 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.
@@ -22221,12 +21574,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> connectEvent = const EventStreamProvider<Event>('connect');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  SharedWorkerContextEvents get on =>
-    new SharedWorkerContextEvents(this);
-
   @DomName('SharedWorkerContext.name')
   @DocsEditable
   String get name native "SharedWorkerContext_name_Getter";
@@ -22236,16 +21583,6 @@
   Stream<Event> get onConnect => connectEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class SharedWorkerContextEvents extends WorkerContextEvents {
-  @DocsEditable
-  SharedWorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get connect => this['connect'];
-}
 // 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.
@@ -22946,12 +22283,6 @@
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  SpeechRecognitionEvents get on =>
-    new SpeechRecognitionEvents(this);
-
   @DomName('SpeechRecognition.continuous')
   @DocsEditable
   bool get continuous native "SpeechRecognition_continuous_Getter";
@@ -23061,46 +22392,6 @@
   Stream<Event> get onStart => startEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class SpeechRecognitionEvents extends Events {
-  @DocsEditable
-  SpeechRecognitionEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get audioEnd => this['audioend'];
-
-  @DocsEditable
-  EventListenerList get audioStart => this['audiostart'];
-
-  @DocsEditable
-  EventListenerList get end => this['end'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get noMatch => this['nomatch'];
-
-  @DocsEditable
-  EventListenerList get result => this['result'];
-
-  @DocsEditable
-  EventListenerList get soundEnd => this['soundend'];
-
-  @DocsEditable
-  EventListenerList get soundStart => this['soundstart'];
-
-  @DocsEditable
-  EventListenerList get speechEnd => this['speechend'];
-
-  @DocsEditable
-  EventListenerList get speechStart => this['speechstart'];
-
-  @DocsEditable
-  EventListenerList get start => this['start'];
-}
 // 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.
@@ -24427,12 +23718,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> cueChangeEvent = const EventStreamProvider<Event>('cuechange');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  TextTrackEvents get on =>
-    new TextTrackEvents(this);
-
   @DomName('TextTrack.activeCues')
   @DocsEditable
   TextTrackCueList get activeCues native "TextTrack_activeCues_Getter";
@@ -24486,16 +23771,6 @@
   Stream<Event> get onCueChange => cueChangeEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class TextTrackEvents extends Events {
-  @DocsEditable
-  TextTrackEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get cueChange => this['cuechange'];
-}
 // 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.
@@ -24525,12 +23800,6 @@
   @DocsEditable
   static TextTrackCue _create_1(startTime, endTime, text) native "TextTrackCue__create_1constructorCallback";
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  TextTrackCueEvents get on =>
-    new TextTrackCueEvents(this);
-
   @DomName('TextTrackCue.align')
   @DocsEditable
   String get align native "TextTrackCue_align_Getter";
@@ -24648,19 +23917,6 @@
   Stream<Event> get onExit => exitEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class TextTrackCueEvents extends Events {
-  @DocsEditable
-  TextTrackCueEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get enter => this['enter'];
-
-  @DocsEditable
-  EventListenerList get exit => this['exit'];
-}
 // 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.
@@ -24885,12 +24141,6 @@
   @DocsEditable
   static const EventStreamProvider<TrackEvent> addTrackEvent = const EventStreamProvider<TrackEvent>('addtrack');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  TextTrackListEvents get on =>
-    new TextTrackListEvents(this);
-
   @DomName('TextTrackList.length')
   @DocsEditable
   int get length native "TextTrackList_length_Getter";
@@ -25099,16 +24349,6 @@
   Stream<TrackEvent> get onAddTrack => addTrackEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class TextTrackListEvents extends Events {
-  @DocsEditable
-  TextTrackListEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get addTrack => this['addtrack'];
-}
 // 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.
@@ -28775,12 +28015,6 @@
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  WebSocketEvents get on =>
-    new WebSocketEvents(this);
-
   static const int CLOSED = 3;
 
   static const int CLOSING = 2;
@@ -28879,25 +28113,6 @@
   Stream<Event> get onOpen => openEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class WebSocketEvents extends Events {
-  @DocsEditable
-  WebSocketEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get close => this['close'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get open => this['open'];
-}
 // 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.
@@ -29087,12 +28302,6 @@
   @Experimental
   static const EventStreamProvider<AnimationEvent> animationStartEvent = const EventStreamProvider<AnimationEvent>('webkitAnimationStart');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  WindowEvents get on =>
-    new WindowEvents(this);
-
   static const int PERSISTENT = 1;
 
   static const int TEMPORARY = 0;
@@ -29459,10 +28668,16 @@
 
   @DomName('DOMWindow.webkitConvertPointFromNodeToPage')
   @DocsEditable
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @Experimental
   DomPoint convertPointFromNodeToPage(Node node, DomPoint p) native "DOMWindow_webkitConvertPointFromNodeToPage_Callback";
 
   @DomName('DOMWindow.webkitConvertPointFromPageToNode')
   @DocsEditable
+  @SupportedBrowser(SupportedBrowser.CHROME)
+  @SupportedBrowser(SupportedBrowser.SAFARI)
+  @Experimental
   DomPoint convertPointFromPageToNode(Node node, DomPoint p) native "DOMWindow_webkitConvertPointFromPageToNode_Callback";
 
   @DomName('DOMWindow.webkitRequestFileSystem')
@@ -29694,235 +28909,6 @@
   Stream<TransitionEvent> get onTransitionEnd => Element.transitionEndEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class WindowEvents extends Events {
-  @DocsEditable
-  WindowEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get contentLoaded => this['DOMContentLoaded'];
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get beforeUnload => this['beforeunload'];
-
-  @DocsEditable
-  EventListenerList get blur => this['blur'];
-
-  @DocsEditable
-  EventListenerList get canPlay => this['canplay'];
-
-  @DocsEditable
-  EventListenerList get canPlayThrough => this['canplaythrough'];
-
-  @DocsEditable
-  EventListenerList get change => this['change'];
-
-  @DocsEditable
-  EventListenerList get click => this['click'];
-
-  @DocsEditable
-  EventListenerList get contextMenu => this['contextmenu'];
-
-  @DocsEditable
-  EventListenerList get doubleClick => this['dblclick'];
-
-  @DocsEditable
-  EventListenerList get deviceMotion => this['devicemotion'];
-
-  @DocsEditable
-  EventListenerList get deviceOrientation => this['deviceorientation'];
-
-  @DocsEditable
-  EventListenerList get drag => this['drag'];
-
-  @DocsEditable
-  EventListenerList get dragEnd => this['dragend'];
-
-  @DocsEditable
-  EventListenerList get dragEnter => this['dragenter'];
-
-  @DocsEditable
-  EventListenerList get dragLeave => this['dragleave'];
-
-  @DocsEditable
-  EventListenerList get dragOver => this['dragover'];
-
-  @DocsEditable
-  EventListenerList get dragStart => this['dragstart'];
-
-  @DocsEditable
-  EventListenerList get drop => this['drop'];
-
-  @DocsEditable
-  EventListenerList get durationChange => this['durationchange'];
-
-  @DocsEditable
-  EventListenerList get emptied => this['emptied'];
-
-  @DocsEditable
-  EventListenerList get ended => this['ended'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get focus => this['focus'];
-
-  @DocsEditable
-  EventListenerList get hashChange => this['hashchange'];
-
-  @DocsEditable
-  EventListenerList get input => this['input'];
-
-  @DocsEditable
-  EventListenerList get invalid => this['invalid'];
-
-  @DocsEditable
-  EventListenerList get keyDown => this['keydown'];
-
-  @DocsEditable
-  EventListenerList get keyPress => this['keypress'];
-
-  @DocsEditable
-  EventListenerList get keyUp => this['keyup'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get loadedData => this['loadeddata'];
-
-  @DocsEditable
-  EventListenerList get loadedMetadata => this['loadedmetadata'];
-
-  @DocsEditable
-  EventListenerList get loadStart => this['loadstart'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get mouseDown => this['mousedown'];
-
-  @DocsEditable
-  EventListenerList get mouseMove => this['mousemove'];
-
-  @DocsEditable
-  EventListenerList get mouseOut => this['mouseout'];
-
-  @DocsEditable
-  EventListenerList get mouseOver => this['mouseover'];
-
-  @DocsEditable
-  EventListenerList get mouseUp => this['mouseup'];
-
-  @DocsEditable
-  EventListenerList get mouseWheel => this['mousewheel'];
-
-  @DocsEditable
-  EventListenerList get offline => this['offline'];
-
-  @DocsEditable
-  EventListenerList get online => this['online'];
-
-  @DocsEditable
-  EventListenerList get pageHide => this['pagehide'];
-
-  @DocsEditable
-  EventListenerList get pageShow => this['pageshow'];
-
-  @DocsEditable
-  EventListenerList get pause => this['pause'];
-
-  @DocsEditable
-  EventListenerList get play => this['play'];
-
-  @DocsEditable
-  EventListenerList get playing => this['playing'];
-
-  @DocsEditable
-  EventListenerList get popState => this['popstate'];
-
-  @DocsEditable
-  EventListenerList get progress => this['progress'];
-
-  @DocsEditable
-  EventListenerList get rateChange => this['ratechange'];
-
-  @DocsEditable
-  EventListenerList get reset => this['reset'];
-
-  @DocsEditable
-  EventListenerList get resize => this['resize'];
-
-  @DocsEditable
-  EventListenerList get scroll => this['scroll'];
-
-  @DocsEditable
-  EventListenerList get search => this['search'];
-
-  @DocsEditable
-  EventListenerList get seeked => this['seeked'];
-
-  @DocsEditable
-  EventListenerList get seeking => this['seeking'];
-
-  @DocsEditable
-  EventListenerList get select => this['select'];
-
-  @DocsEditable
-  EventListenerList get stalled => this['stalled'];
-
-  @DocsEditable
-  EventListenerList get storage => this['storage'];
-
-  @DocsEditable
-  EventListenerList get submit => this['submit'];
-
-  @DocsEditable
-  EventListenerList get suspend => this['suspend'];
-
-  @DocsEditable
-  EventListenerList get timeUpdate => this['timeupdate'];
-
-  @DocsEditable
-  EventListenerList get touchCancel => this['touchcancel'];
-
-  @DocsEditable
-  EventListenerList get touchEnd => this['touchend'];
-
-  @DocsEditable
-  EventListenerList get touchMove => this['touchmove'];
-
-  @DocsEditable
-  EventListenerList get touchStart => this['touchstart'];
-
-  @DocsEditable
-  EventListenerList get unload => this['unload'];
-
-  @DocsEditable
-  EventListenerList get volumeChange => this['volumechange'];
-
-  @DocsEditable
-  EventListenerList get waiting => this['waiting'];
-
-  @DocsEditable
-  EventListenerList get animationEnd => this['webkitAnimationEnd'];
-
-  @DocsEditable
-  EventListenerList get animationIteration => this['webkitAnimationIteration'];
-
-  @DocsEditable
-  EventListenerList get animationStart => this['webkitAnimationStart'];
-
-  @DocsEditable
-  EventListenerList get transitionEnd => this['webkitTransitionEnd'];
-}
 // 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.
@@ -29948,12 +28934,6 @@
   @DocsEditable
   static Worker _create_1(scriptUrl) native "Worker__create_1constructorCallback";
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  WorkerEvents get on =>
-    new WorkerEvents(this);
-
   @DomName('Worker.postMessage')
   @DocsEditable
   void postMessage(/*SerializedScriptValue*/ message, [List messagePorts]) native "Worker_postMessage_Callback";
@@ -29967,16 +28947,6 @@
   Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class WorkerEvents extends AbstractWorkerEvents {
-  @DocsEditable
-  WorkerEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-}
 // 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.
@@ -29993,12 +28963,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  WorkerContextEvents get on =>
-    new WorkerContextEvents(this);
-
   static const int PERSISTENT = 1;
 
   static const int TEMPORARY = 0;
@@ -30109,16 +29073,6 @@
   Stream<Event> get onError => errorEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class WorkerContextEvents extends Events {
-  @DocsEditable
-  WorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-}
 // 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.
@@ -31901,58 +30855,6 @@
 class _HTMLFrameSetElement extends _Element_Merged {
   _HTMLFrameSetElement.internal() : super.internal();
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  _HTMLFrameSetElementEvents get on =>
-    new _HTMLFrameSetElementEvents(this);
-
-}
-
-@DocsEditable
-@deprecated
-class _HTMLFrameSetElementEvents extends ElementEvents {
-  @DocsEditable
-  _HTMLFrameSetElementEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get beforeUnload => this['beforeunload'];
-
-  @DocsEditable
-  EventListenerList get blur => this['blur'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get focus => this['focus'];
-
-  @DocsEditable
-  EventListenerList get hashChange => this['hashchange'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get message => this['message'];
-
-  @DocsEditable
-  EventListenerList get offline => this['offline'];
-
-  @DocsEditable
-  EventListenerList get online => this['online'];
-
-  @DocsEditable
-  EventListenerList get popState => this['popstate'];
-
-  @DocsEditable
-  EventListenerList get resize => this['resize'];
-
-  @DocsEditable
-  EventListenerList get storage => this['storage'];
-
-  @DocsEditable
-  EventListenerList get unload => this['unload'];
 }
 // 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
@@ -35368,12 +34270,10 @@
     // TODO(vsm): Set this up set once, on the first call.
     var source = '$target-result';
     var result = null;
-    var listener = (Event e) {
+    window.on[source].first.then((Event e) {
       result = json.parse(_getPortSyncEventData(e));
-    };
-    window.on[source].add(listener);
+    });
     _dispatchEvent(target, [source, message]);
-    window.on[source].remove(listener);
     return result;
   }
 
@@ -35428,7 +34328,7 @@
 
   num _portId;
   Function _callback;
-  EventListener _listener;
+  StreamSubscription _portSubscription;
 
   ReceivePortSync() {
     if (_portIdCount == null) {
@@ -35453,21 +34353,20 @@
 
   void receive(callback(var message)) {
     _callback = callback;
-    if (_listener == null) {
-      _listener = (Event e) {
+    if (_portSubscription == null) {
+      _portSubscription = window.on[_listenerName].listen((Event e) {
         var data = json.parse(_getPortSyncEventData(e));
         var replyTo = data[0];
         var message = _deserialize(data[1]);
         var result = _callback(message);
         _dispatchEvent(replyTo, _serialize(result));
-      };
-      window.on[_listenerName].add(_listener);
+      });
     }
   }
 
   void close() {
     _portMap.remove(_portId);
-    if (_listener != null) window.on[_listenerName].remove(_listener);
+    if (_portSubscription != null) _portSubscription.cancel();
   }
 
   SendPortSync toSendPort() {
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index 318b36b..76547dd 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -190,11 +190,13 @@
 @DomName('IDBCursorWithValue')
 class CursorWithValue extends Cursor native "*IDBCursorWithValue" {
 
+  dynamic get value => _convertNativeToDart_IDBAny(this._value);
+  @JSName('value')
   @DomName('IDBCursorWithValue.value')
   @DocsEditable
   @annotation_Creates_SerializedScriptValue
   @annotation_Returns_SerializedScriptValue
-  final Object value;
+  final dynamic _value;
 }
 // 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
@@ -238,12 +240,6 @@
   @DocsEditable
   static const EventStreamProvider<VersionChangeEvent> versionChangeEvent = const EventStreamProvider<VersionChangeEvent>('versionchange');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  DatabaseEvents get on =>
-    new DatabaseEvents(this);
-
   @DomName('IDBDatabase.name')
   @DocsEditable
   final String name;
@@ -310,22 +306,6 @@
   @DocsEditable
   Stream<VersionChangeEvent> get onVersionChange => versionChangeEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class DatabaseEvents extends Events {
-  @DocsEditable
-  DatabaseEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get versionChange => this['versionchange'];
-}
 // 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.
@@ -616,7 +596,7 @@
    * the current transaction.
    */
   @DomName('IDBObjectStore.openCursor')
-  Stream<Cursor> openCursor({key, KeyRange range, String direction,
+  Stream<CursorWithValue> openCursor({key, KeyRange range, String direction,
       bool autoAdvance}) {
     var key_OR_range = null;
     if (key != null) {
@@ -702,29 +682,31 @@
   @DocsEditable
   Index createIndex(String name, keyPath, [Map options]) {
     if ((keyPath is List<String> || keyPath == null) && !?options) {
-      return _createIndex_1(name, keyPath);
+      List keyPath_1 = convertDartToNative_StringArray(keyPath);
+      return _createIndex_1(name, keyPath_1);
     }
     if ((keyPath is List<String> || keyPath == null)) {
-      var options_1 = convertDartToNative_Dictionary(options);
-      return _createIndex_2(name, keyPath, options_1);
+      List keyPath_2 = convertDartToNative_StringArray(keyPath);
+      var options_3 = convertDartToNative_Dictionary(options);
+      return _createIndex_2(name, keyPath_2, options_3);
     }
     if ((keyPath is String || keyPath == null) && !?options) {
       return _createIndex_3(name, keyPath);
     }
     if ((keyPath is String || keyPath == null)) {
-      var options_2 = convertDartToNative_Dictionary(options);
-      return _createIndex_4(name, keyPath, options_2);
+      var options_4 = convertDartToNative_Dictionary(options);
+      return _createIndex_4(name, keyPath, options_4);
     }
     throw new ArgumentError("Incorrect number or type of arguments");
   }
   @JSName('createIndex')
   @DomName('IDBObjectStore.createIndex')
   @DocsEditable
-  Index _createIndex_1(name, List<String> keyPath) native;
+  Index _createIndex_1(name, List keyPath) native;
   @JSName('createIndex')
   @DomName('IDBObjectStore.createIndex')
   @DocsEditable
-  Index _createIndex_2(name, List<String> keyPath, options) native;
+  Index _createIndex_2(name, List keyPath, options) native;
   @JSName('createIndex')
   @DomName('IDBObjectStore.createIndex')
   @DocsEditable
@@ -800,7 +782,7 @@
     // TODO: need to guarantee that the controller provides the values
     // immediately as waiting until the next tick will cause the transaction to
     // close.
-    var controller = new StreamController<Cursor>();
+    var controller = new StreamController();
 
     request.onError.listen((e) {
       //TODO: Report stacktrace once issue 4061 is resolved.
@@ -838,12 +820,6 @@
   @DocsEditable
   static const EventStreamProvider<VersionChangeEvent> upgradeNeededEvent = const EventStreamProvider<VersionChangeEvent>('upgradeneeded');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  OpenDBRequestEvents get on =>
-    new OpenDBRequestEvents(this);
-
   @DomName('IDBOpenDBRequest.onblocked')
   @DocsEditable
   Stream<Event> get onBlocked => blockedEvent.forTarget(this);
@@ -852,19 +828,6 @@
   @DocsEditable
   Stream<VersionChangeEvent> get onUpgradeNeeded => upgradeNeededEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class OpenDBRequestEvents extends RequestEvents {
-  @DocsEditable
-  OpenDBRequestEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get blocked => this['blocked'];
-
-  @DocsEditable
-  EventListenerList get upgradeNeeded => this['upgradeneeded'];
-}
 // 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.
@@ -882,12 +845,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> successEvent = const EventStreamProvider<Event>('success');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  RequestEvents get on =>
-    new RequestEvents(this);
-
   @DomName('IDBRequest.error')
   @DocsEditable
   final DomError error;
@@ -942,19 +899,6 @@
   @DocsEditable
   Stream<Event> get onSuccess => successEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class RequestEvents extends Events {
-  @DocsEditable
-  RequestEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get success => this['success'];
-}
 // 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.
@@ -1001,12 +945,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  TransactionEvents get on =>
-    new TransactionEvents(this);
-
   @DomName('IDBTransaction.db')
   @DocsEditable
   final Database db;
@@ -1062,22 +1000,6 @@
   Stream<Event> get onError => errorEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class TransactionEvents extends Events {
-  @DocsEditable
-  TransactionEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get complete => this['complete'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-}
 // 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.
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index a19e78f..5aa80a1a 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -136,12 +136,6 @@
   @DocsEditable
   static const EventStreamProvider<VersionChangeEvent> versionChangeEvent = const EventStreamProvider<VersionChangeEvent>('versionchange');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  DatabaseEvents get on =>
-    new DatabaseEvents(this);
-
   @DomName('IDBDatabase.name')
   @DocsEditable
   String get name native "IDBDatabase_name_Getter";
@@ -216,22 +210,6 @@
   Stream<VersionChangeEvent> get onVersionChange => versionChangeEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class DatabaseEvents extends Events {
-  @DocsEditable
-  DatabaseEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get versionChange => this['versionchange'];
-}
 // 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.
@@ -672,7 +650,7 @@
    * the current transaction.
    */
   @DomName('IDBObjectStore.openCursor')
-  Stream<Cursor> openCursor({key, KeyRange range, String direction,
+  Stream<CursorWithValue> openCursor({key, KeyRange range, String direction,
       bool autoAdvance}) {
     var key_OR_range = null;
     if (key != null) {
@@ -885,7 +863,7 @@
     // TODO: need to guarantee that the controller provides the values
     // immediately as waiting until the next tick will cause the transaction to
     // close.
-    var controller = new StreamController<Cursor>();
+    var controller = new StreamController();
 
     request.onError.listen((e) {
       //TODO: Report stacktrace once issue 4061 is resolved.
@@ -926,12 +904,6 @@
   @DocsEditable
   static const EventStreamProvider<VersionChangeEvent> upgradeNeededEvent = const EventStreamProvider<VersionChangeEvent>('upgradeneeded');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  OpenDBRequestEvents get on =>
-    new OpenDBRequestEvents(this);
-
   @DomName('IDBOpenDBRequest.onblocked')
   @DocsEditable
   Stream<Event> get onBlocked => blockedEvent.forTarget(this);
@@ -941,19 +913,6 @@
   Stream<VersionChangeEvent> get onUpgradeNeeded => upgradeNeededEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class OpenDBRequestEvents extends RequestEvents {
-  @DocsEditable
-  OpenDBRequestEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get blocked => this['blocked'];
-
-  @DocsEditable
-  EventListenerList get upgradeNeeded => this['upgradeneeded'];
-}
 // 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.
@@ -974,12 +933,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> successEvent = const EventStreamProvider<Event>('success');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  RequestEvents get on =>
-    new RequestEvents(this);
-
   @DomName('IDBRequest.error')
   @DocsEditable
   DomError get error native "IDBRequest_error_Getter";
@@ -1028,19 +981,6 @@
   Stream<Event> get onSuccess => successEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class RequestEvents extends Events {
-  @DocsEditable
-  RequestEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get success => this['success'];
-}
 // 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.
@@ -1088,12 +1028,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  TransactionEvents get on =>
-    new TransactionEvents(this);
-
   @DomName('IDBTransaction.db')
   @DocsEditable
   Database get db native "IDBTransaction_db_Getter";
@@ -1146,22 +1080,6 @@
   Stream<Event> get onError => errorEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class TransactionEvents extends Events {
-  @DocsEditable
-  TransactionEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get complete => this['complete'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-}
 // 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.
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index 9f47721..09a63ec 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -1043,12 +1043,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> unloadEvent = const EventStreamProvider<Event>('unload');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  ElementInstanceEvents get on =>
-    new ElementInstanceEvents(this);
-
   @DomName('SVGElementInstance.childNodes')
   @DocsEditable
   @Returns('_ElementInstanceList')
@@ -1243,133 +1237,6 @@
   @DocsEditable
   Stream<Event> get onUnload => unloadEvent.forTarget(this);
 }
-
-@DocsEditable
-@deprecated
-class ElementInstanceEvents extends Events {
-  @DocsEditable
-  ElementInstanceEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get beforeCopy => this['beforecopy'];
-
-  @DocsEditable
-  EventListenerList get beforeCut => this['beforecut'];
-
-  @DocsEditable
-  EventListenerList get beforePaste => this['beforepaste'];
-
-  @DocsEditable
-  EventListenerList get blur => this['blur'];
-
-  @DocsEditable
-  EventListenerList get change => this['change'];
-
-  @DocsEditable
-  EventListenerList get click => this['click'];
-
-  @DocsEditable
-  EventListenerList get contextMenu => this['contextmenu'];
-
-  @DocsEditable
-  EventListenerList get copy => this['copy'];
-
-  @DocsEditable
-  EventListenerList get cut => this['cut'];
-
-  @DocsEditable
-  EventListenerList get doubleClick => this['dblclick'];
-
-  @DocsEditable
-  EventListenerList get drag => this['drag'];
-
-  @DocsEditable
-  EventListenerList get dragEnd => this['dragend'];
-
-  @DocsEditable
-  EventListenerList get dragEnter => this['dragenter'];
-
-  @DocsEditable
-  EventListenerList get dragLeave => this['dragleave'];
-
-  @DocsEditable
-  EventListenerList get dragOver => this['dragover'];
-
-  @DocsEditable
-  EventListenerList get dragStart => this['dragstart'];
-
-  @DocsEditable
-  EventListenerList get drop => this['drop'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get focus => this['focus'];
-
-  @DocsEditable
-  EventListenerList get input => this['input'];
-
-  @DocsEditable
-  EventListenerList get keyDown => this['keydown'];
-
-  @DocsEditable
-  EventListenerList get keyPress => this['keypress'];
-
-  @DocsEditable
-  EventListenerList get keyUp => this['keyup'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get mouseDown => this['mousedown'];
-
-  @DocsEditable
-  EventListenerList get mouseMove => this['mousemove'];
-
-  @DocsEditable
-  EventListenerList get mouseOut => this['mouseout'];
-
-  @DocsEditable
-  EventListenerList get mouseOver => this['mouseover'];
-
-  @DocsEditable
-  EventListenerList get mouseUp => this['mouseup'];
-
-  @DocsEditable
-  EventListenerList get mouseWheel => this['mousewheel'];
-
-  @DocsEditable
-  EventListenerList get paste => this['paste'];
-
-  @DocsEditable
-  EventListenerList get reset => this['reset'];
-
-  @DocsEditable
-  EventListenerList get resize => this['resize'];
-
-  @DocsEditable
-  EventListenerList get scroll => this['scroll'];
-
-  @DocsEditable
-  EventListenerList get search => this['search'];
-
-  @DocsEditable
-  EventListenerList get select => this['select'];
-
-  @DocsEditable
-  EventListenerList get selectStart => this['selectstart'];
-
-  @DocsEditable
-  EventListenerList get submit => this['submit'];
-
-  @DocsEditable
-  EventListenerList get unload => this['unload'];
-}
 // 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.
@@ -2326,6 +2193,10 @@
 
 @DocsEditable
 @DomName('SVGFEMorphologyElement')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
 class FEMorphologyElement extends StyledElement implements FilterPrimitiveStandardAttributes native "*SVGFEMorphologyElement" {
 
   static const int SVG_MORPHOLOGY_OPERATOR_DILATE = 2;
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index 70fbe36..debc991 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -1158,12 +1158,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> unloadEvent = const EventStreamProvider<Event>('unload');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  ElementInstanceEvents get on =>
-    new ElementInstanceEvents(this);
-
   @DomName('SVGElementInstance.childNodes')
   @DocsEditable
   List<ElementInstance> get childNodes native "SVGElementInstance_childNodes_Getter";
@@ -1357,133 +1351,6 @@
   Stream<Event> get onUnload => unloadEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class ElementInstanceEvents extends Events {
-  @DocsEditable
-  ElementInstanceEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get abort => this['abort'];
-
-  @DocsEditable
-  EventListenerList get beforeCopy => this['beforecopy'];
-
-  @DocsEditable
-  EventListenerList get beforeCut => this['beforecut'];
-
-  @DocsEditable
-  EventListenerList get beforePaste => this['beforepaste'];
-
-  @DocsEditable
-  EventListenerList get blur => this['blur'];
-
-  @DocsEditable
-  EventListenerList get change => this['change'];
-
-  @DocsEditable
-  EventListenerList get click => this['click'];
-
-  @DocsEditable
-  EventListenerList get contextMenu => this['contextmenu'];
-
-  @DocsEditable
-  EventListenerList get copy => this['copy'];
-
-  @DocsEditable
-  EventListenerList get cut => this['cut'];
-
-  @DocsEditable
-  EventListenerList get doubleClick => this['dblclick'];
-
-  @DocsEditable
-  EventListenerList get drag => this['drag'];
-
-  @DocsEditable
-  EventListenerList get dragEnd => this['dragend'];
-
-  @DocsEditable
-  EventListenerList get dragEnter => this['dragenter'];
-
-  @DocsEditable
-  EventListenerList get dragLeave => this['dragleave'];
-
-  @DocsEditable
-  EventListenerList get dragOver => this['dragover'];
-
-  @DocsEditable
-  EventListenerList get dragStart => this['dragstart'];
-
-  @DocsEditable
-  EventListenerList get drop => this['drop'];
-
-  @DocsEditable
-  EventListenerList get error => this['error'];
-
-  @DocsEditable
-  EventListenerList get focus => this['focus'];
-
-  @DocsEditable
-  EventListenerList get input => this['input'];
-
-  @DocsEditable
-  EventListenerList get keyDown => this['keydown'];
-
-  @DocsEditable
-  EventListenerList get keyPress => this['keypress'];
-
-  @DocsEditable
-  EventListenerList get keyUp => this['keyup'];
-
-  @DocsEditable
-  EventListenerList get load => this['load'];
-
-  @DocsEditable
-  EventListenerList get mouseDown => this['mousedown'];
-
-  @DocsEditable
-  EventListenerList get mouseMove => this['mousemove'];
-
-  @DocsEditable
-  EventListenerList get mouseOut => this['mouseout'];
-
-  @DocsEditable
-  EventListenerList get mouseOver => this['mouseover'];
-
-  @DocsEditable
-  EventListenerList get mouseUp => this['mouseup'];
-
-  @DocsEditable
-  EventListenerList get mouseWheel => this['mousewheel'];
-
-  @DocsEditable
-  EventListenerList get paste => this['paste'];
-
-  @DocsEditable
-  EventListenerList get reset => this['reset'];
-
-  @DocsEditable
-  EventListenerList get resize => this['resize'];
-
-  @DocsEditable
-  EventListenerList get scroll => this['scroll'];
-
-  @DocsEditable
-  EventListenerList get search => this['search'];
-
-  @DocsEditable
-  EventListenerList get select => this['select'];
-
-  @DocsEditable
-  EventListenerList get selectStart => this['selectstart'];
-
-  @DocsEditable
-  EventListenerList get submit => this['submit'];
-
-  @DocsEditable
-  EventListenerList get unload => this['unload'];
-}
 // 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.
@@ -2510,6 +2377,10 @@
 
 @DocsEditable
 @DomName('SVGFEMorphologyElement')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
 class FEMorphologyElement extends StyledElement implements FilterPrimitiveStandardAttributes {
   FEMorphologyElement.internal() : super.internal();
 
diff --git a/sdk/lib/uri/uri.dart b/sdk/lib/uri/uri.dart
index 3b1af61..abd1223 100644
--- a/sdk/lib/uri/uri.dart
+++ b/sdk/lib/uri/uri.dart
@@ -92,7 +92,7 @@
   /**
    * Returns `true` if the URI is absolute.
    */
-  bool isAbsolute() {
+  bool get isAbsolute {
     if ("" == scheme) return false;
     if ("" != fragment) return false;
     return true;
@@ -143,7 +143,7 @@
       targetPath = removeDotSegments(reference.path);
       targetQuery = reference.query;
     } else {
-      if (reference.hasAuthority()) {
+      if (reference.hasAuthority) {
         targetUserInfo = reference.userInfo;
         targetDomain = reference.domain;
         targetPort = reference.port;
@@ -180,7 +180,7 @@
                                   fragment: reference.fragment);
   }
 
-  bool hasAuthority() {
+  bool get hasAuthority {
     return (userInfo != "") || (domain != "") || (port != 0);
   }
 
@@ -219,7 +219,7 @@
   String toString() {
     StringBuffer sb = new StringBuffer();
     _addIfNonEmpty(sb, scheme, scheme, ':');
-    if (hasAuthority() || (scheme == "file")) {
+    if (hasAuthority || (scheme == "file")) {
       sb.add("//");
       _addIfNonEmpty(sb, userInfo, userInfo, "@");
       sb.add(domain == null ? "null" : domain);
diff --git a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
index 6857253..6680a44 100644
--- a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
+++ b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
@@ -180,12 +180,6 @@
   @DocsEditable
   static const EventStreamProvider<Event> completeEvent = const EventStreamProvider<Event>('complete');
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  AudioContextEvents get on =>
-    new AudioContextEvents(this);
-
   @DomName('AudioContext.activeSourceCount')
   @DocsEditable
   final int activeSourceCount;
@@ -309,16 +303,6 @@
     }
   }
 }
-
-@DocsEditable
-@deprecated
-class AudioContextEvents extends Events {
-  @DocsEditable
-  AudioContextEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get complete => this['complete'];
-}
 // 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.
diff --git a/sdk/lib/web_audio/dartium/web_audio_dartium.dart b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
index 765c957..23ad0a3 100644
--- a/sdk/lib/web_audio/dartium/web_audio_dartium.dart
+++ b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
@@ -235,12 +235,6 @@
   @DocsEditable
   static AudioContext _create() native "AudioContext_constructorCallback";
 
-  @DocsEditable
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
-  @deprecated
-  AudioContextEvents get on =>
-    new AudioContextEvents(this);
-
   @DomName('AudioContext.activeSourceCount')
   @DocsEditable
   int get activeSourceCount native "AudioContext_activeSourceCount_Getter";
@@ -411,16 +405,6 @@
   Stream<Event> get onComplete => completeEvent.forTarget(this);
 
 }
-
-@DocsEditable
-@deprecated
-class AudioContextEvents extends Events {
-  @DocsEditable
-  AudioContextEvents(EventTarget _ptr) : super(_ptr);
-
-  @DocsEditable
-  EventListenerList get complete => this['complete'];
-}
 // 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.
diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart
index 2e8e529..8aa2bae 100644
--- a/tests/compiler/dart2js/cpa_inference_test.dart
+++ b/tests/compiler/dart2js/cpa_inference_test.dart
@@ -53,7 +53,7 @@
   BaseType nullType;
 
   AnalysisResult(MockCompiler compiler) : this.compiler = compiler {
-    inferrer = compiler.typesTask.concreteTypesInferrer;
+    inferrer = compiler.typesTask.typesInferrer;
     int = inferrer.baseTypes.intBaseType;
     double = inferrer.baseTypes.doubleBaseType;
     num = inferrer.baseTypes.numBaseType;
@@ -177,7 +177,7 @@
       enableConcreteTypeInference: true,
       maxConcreteTypeSize: maxConcreteTypeSize);
   compiler.sourceFiles[uri.toString()] = new SourceFile(uri.toString(), code);
-  compiler.typesTask.concreteTypesInferrer.testMode = true;
+  compiler.typesTask.typesInferrer.testMode = true;
   compiler.runCompiler(uri);
   return new AnalysisResult(compiler);
 }
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 319c028..39ab912 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -69,23 +69,25 @@
     toString() {}
   }
   class JSNumber {
-    operator-() {}
-    operator +(other) {}
-    operator -(other) {}
-    operator ~/(other) {}
-    operator /(other) {}
-    operator *(other) {}
-    operator <<(other) {}
-    operator >>(other) {}
-    operator |(other) {}
-    operator &(other) {}
-    operator ^(other) {}
-    operator >(other) {}
-    operator >=(other) {}
-    operator <(other) {}
-    operator <=(other) {}
-    operator ==(other) {}
-    operator %(other) {}
+    // All these methods return a number to please type inferencing.
+    operator-() => (this is JSInt) ? 42 : 42.0;
+    operator +(other) => (this is JSInt) ? 42 : 42.0;
+    operator -(other) => (this is JSInt) ? 42 : 42.0;
+    operator ~/(other) => 42;
+    operator /(other) => (this is JSInt) ? 42 : 42.0;
+    operator *(other) => (this is JSInt) ? 42 : 42.0;
+    operator %(other) => (this is JSInt) ? 42 : 42.0;
+    operator <<(other) => 42;
+    operator >>(other) => 42;
+    operator |(other) => 42;
+    operator &(other) => 42;
+    operator ^(other) => 42;
+
+    operator >(other) => true;
+    operator >=(other) => true;
+    operator <(other) => true;
+    operator <=(other) => true;
+    operator ==(other) => true;
   }
   class JSInt {
   }
diff --git a/tests/compiler/dart2js_extra/typevariable_factory_test.dart b/tests/compiler/dart2js_extra/typevariable_factory_test.dart
new file mode 100644
index 0000000..5618cae
--- /dev/null
+++ b/tests/compiler/dart2js_extra/typevariable_factory_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.
+
+// Regression test to ensure that we can use type variable in factories.
+
+class A<T> {
+  factory A.foo(o) {
+    Expect.isTrue(o is A<T>);
+    return new A();
+  }
+  A();
+}
+
+main() => new A<int>.foo(new A<int>());
diff --git a/tests/compiler/dart2js_extra/typevariable_substitution_test.dart b/tests/compiler/dart2js_extra/typevariable_substitution_test.dart
new file mode 100644
index 0000000..8a40a82
--- /dev/null
+++ b/tests/compiler/dart2js_extra/typevariable_substitution_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+// Regression test to ensure that we substitute type variables in is-tests.
+
+class A<T> {
+  A.foo(o) {
+    Expect.isTrue(o is A<T>);
+  }
+  A();
+}
+
+class B extends A<int> {
+  B.foo(o) : super.foo(o);
+}
+
+main() => new B.foo(new A<int>());
diff --git a/tests/corelib/string_codeunits_test.dart b/tests/corelib/string_codeunits_test.dart
new file mode 100644
index 0000000..81625c5
--- /dev/null
+++ b/tests/corelib/string_codeunits_test.dart
@@ -0,0 +1,44 @@
+// 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.
+
+main() {
+  test(String s) {
+    Iterable<int> units = s.codeUnits;
+    List<int> expectedUnits = <int>[];
+    for (int i = 0; i < s.length; i++) {
+      expectedUnits.add(s.codeUnitAt(i));
+    }
+
+    Expect.equals(s.length, units.length);
+    for (int i = 0; i < s.length; i++) {
+      Expect.equals(s.codeUnitAt(i), units.elementAt(i));
+    }
+
+    // for-in
+    var res = [];
+    for (int unit in units) {
+      res.add(unit);
+    }
+    Expect.listEquals(expectedUnits, res);
+
+    // .map
+    Expect.listEquals(expectedUnits.map((x) => x.toRadixString(16)).toList(),
+                      units.map((x) => x.toRadixString(16)).toList());
+  }
+
+  test("abc");
+  test("\x00\u0000\u{000000}");
+  test("\u{ffff}\u{10000}\u{10ffff}");
+  String string = new String.fromCharCodes(
+      [0xdc00, 0xd800, 61, 0xd800, 0xdc00, 62, 0xdc00, 0xd800]);
+  test(string);
+
+  // Setting position in the middle of a surrogate pair is not allowed.
+  var r = new CodeUnits("\u{10000}");
+  var it = r.iterator;
+  Expect.isTrue(it.moveNext());
+  Expect.equals(0xD800, it.current);
+  Expect.isTrue(it.moveNext());
+  Expect.equals(0xDC00, it.current);
+}
diff --git a/tests/html/element_test.dart b/tests/html/element_test.dart
index 981db6d..d838efa 100644
--- a/tests/html/element_test.dart
+++ b/tests/html/element_test.dart
@@ -618,6 +618,18 @@
     testUnsupported('removeLast', () => getQueryAll().removeLast());
   });
 
+  group('functional', () {
+    test('scrollIntoView', () {
+      var child = new DivElement();
+      document.body.append(child);
+
+      child.scrollIntoView(ScrollAlignment.TOP);
+      child.scrollIntoView(ScrollAlignment.BOTTOM);
+      child.scrollIntoView(ScrollAlignment.CENTER);
+      child.scrollIntoView();
+    });
+  });
+
   group('_ElementList', () {
     List<Element> makeElList() => makeElementWithChildren().children;
 
diff --git a/tests/html/indexeddb_2_test.dart b/tests/html/indexeddb_2_test.dart
index f762d14..2ec96a5 100644
--- a/tests/html/indexeddb_2_test.dart
+++ b/tests/html/indexeddb_2_test.dart
@@ -24,22 +24,18 @@
   var db;
   // Delete any existing DBs.
   return html.window.indexedDB.deleteDatabase(dbName).then((_) {
-      html.window.console.log('open');
       return html.window.indexedDB.open(dbName, version: version,
         onUpgradeNeeded: createObjectStore);
     }).then((result) {
-      html.window.console.log('write');
       db = result;
       var transaction = db.transaction([storeName], 'readwrite');
       transaction.objectStore(storeName).put(value, key);
 
       return transaction.completed;
     }).then((db) {
-      html.window.console.log('read');
       var transaction = db.transaction(storeName, 'readonly');
       return transaction.objectStore(storeName).getObject(key);
     }).then((object) {
-      html.window.console.log('got close');
       db.close();
       check(value, object);
     }).catchError((e) {
diff --git a/tests/html/indexeddb_4_test.dart b/tests/html/indexeddb_4_test.dart
index ff2f4b5..e331734 100644
--- a/tests/html/indexeddb_4_test.dart
+++ b/tests/html/indexeddb_4_test.dart
@@ -25,7 +25,8 @@
 Future<Database> writeItems(Database db) {
   Future<Object> write(index) {
     var transaction = db.transaction([STORE_NAME], 'readwrite');
-    return transaction.objectStore(STORE_NAME).put('Item $index', index);
+    return transaction.objectStore(STORE_NAME).put(
+        {'content': 'Item $index'}, index);
   }
 
   var future = write(0);
@@ -50,6 +51,8 @@
   int lastKey;
   cursors.listen((cursor) {
     lastKey = cursor.key;
+    var value = cursor.value;
+    expect(value['content'], 'Item ${cursor.key}');
   });
 
   if (expectedFirst != null) {
diff --git a/tests/language/branch_canonicalization_test.dart b/tests/language/branch_canonicalization_test.dart
index 7e39572..0735076 100644
--- a/tests/language/branch_canonicalization_test.dart
+++ b/tests/language/branch_canonicalization_test.dart
@@ -1,6 +1,7 @@
 // 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 branch fusion correctly sets branch environment for comparisons
 // that require unboxing and does not fuse branches that can deoptimize.
 
@@ -60,6 +61,3 @@
   Expect.equals(1, fooPoly(z, z));
   Expect.isTrue(sideEffect);
 }
-
-
-
diff --git a/tests/language/language.status b/tests/language/language.status
index 342fb06..c64f4c5 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -56,26 +56,11 @@
 
 type_parameter_literal_test: Fail # Issue 7551
 
-mixin_field_test: Fail
-mixin_is_test: Fail
-mixin_method_test: Fail
-mixin_naming_test: Fail
-mixin_extends_field_test: Fail
-mixin_extends_is_test: Fail
-mixin_extends_method_test: Fail
-mixin_mixin_test: Fail
 mixin_illegal_syntax_test/none: Fail
-mixin_illegal_superclass_test/none: Fail
-mixin_illegal_constructor_test/none: Fail
-mixin_illegal_static_access_test: Fail
-mixin_illegal_super_use_test/none: Fail
-mixin_implements_test: Fail
 mixin_type_parameters_mixin_test: Fail
 mixin_type_parameters_super_test: Fail
 mixin_type_parameters_mixin_extends_test: Fail
 mixin_type_parameters_super_extends_test: Fail
-mixin_this_use_test: Fail
-mixin_lib_extends_method_test: Fail
 mixin_lib_extends_field_test: Fail
 
 [ $compiler == none && ($system == macos || $system == linux) && $arch == ia32 && $checked ]
@@ -365,26 +350,12 @@
 overridden_no_such_method_test: Fail, Pass, OK # Fails in minified mode, test depends on method names.
 
 # Mixins fail on the VM.
-mixin_field_test: Fail                          # VM issue
-mixin_is_test: Fail                             # VM issue
-mixin_method_test: Fail                         # VM issue
-mixin_naming_test: Fail                         # VM issue
-mixin_extends_field_test: Fail                  # VM issue
-mixin_extends_is_test: Fail                     # VM issue
-mixin_extends_method_test: Fail                 # VM issue
-mixin_mixin_test: Fail                          # VM issue
 mixin_illegal_syntax_test/none: Fail            # VM issue
-mixin_illegal_superclass_test/none: Fail        # VM issue
 mixin_illegal_constructor_test/none: Fail       # VM issue
-mixin_illegal_super_use_test/none: Fail         # VM issue
-mixin_implements_test: Fail                     # VM issue
 mixin_type_parameters_mixin_test: Fail          # VM issue
 mixin_type_parameters_super_test: Fail          # VM issue
 mixin_type_parameters_mixin_extends_test: Fail  # VM issue
 mixin_type_parameters_super_extends_test: Fail  # VM issue
-mixin_this_use_test: Fail                       # VM issue
-mixin_lib_extends_method_test: Fail             # VM issue
-mixin_lib_extends_field_test: Fail              # VM issue
 
 # Malformed types not handled as unresolved:
 import_core_prefix_test: Fail
@@ -573,6 +544,7 @@
 type_parameter_literal_test: Fail
 
 [ $compiler == dart2dart && $minified ]
+
 # TODO(tball): Assign proper bug numbers.
 class_literal_test/none: Fail
 
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 4ca2c13..14bbc37 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -89,6 +89,7 @@
 compile_time_constant_checked3_test/06: Fail, OK
 
 [ $compiler == dart2js ]
+branch_canonicalization_test: Fail # Issue 638.
 div_with_power_of_two_test: Fail # Issue 8301.
 call_operator_test: Fail # Issue 7622.
 class_literal_test: Fail # Issue 7626.
diff --git a/tests/language/large_implicit_getter_test.dart b/tests/language/large_implicit_getter_test.dart
new file mode 100644
index 0000000..2eefe28
--- /dev/null
+++ b/tests/language/large_implicit_getter_test.dart
@@ -0,0 +1,1376 @@
+// 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 compilation of large implicit getters.
+
+List<List> panels = [
+[6853.940039224797,6050.837897021371]
+,[6953.240039224797,6050.837897021371]
+,[7052.5400392247975,5885.237897021371]
+,[7052.5400392247975,5719.637897021372]
+,[7151.840039224798,5885.237897021371]
+,[7052.5400392247975,6050.837897021371]
+,[7052.5400392247975,6216.43789702137]
+,[7052.5400392247975,6382.03789702137]
+,[6953.240039224797,6382.03789702137]
+,[6953.240039224797,6216.43789702137]
+,[6853.940039224797,6216.43789702137]
+,[6853.940039224797,6382.03789702137]
+,[6754.640039224797,6216.43789702137]
+,[6754.640039224797,6382.03789702137]
+,[6754.640039224797,6547.637897021369]
+,[6754.640039224797,6713.237897021369]
+,[6655.340039224797,6713.237897021369]
+,[6754.640039224797,6878.837897021368]
+,[6853.940039224797,6713.237897021369]
+,[6853.940039224797,6878.837897021368]
+,[6953.240039224797,6713.237897021369]
+,[7052.5400392247975,6547.637897021369]
+,[7151.840039224798,6713.237897021369]
+,[7151.840039224798,6547.637897021369]
+,[7151.840039224798,6382.03789702137]
+,[7251.140039224798,6547.637897021369]
+,[7251.140039224798,6713.237897021369]
+,[7350.440039224798,6878.837897021368]
+,[7449.740039224798,6878.837897021368]
+,[7449.740039224798,6713.237897021369]
+,[7549.040039224798,6547.637897021369]
+,[7449.740039224798,6382.03789702137]
+,[7449.740039224798,6216.43789702137]
+,[7549.040039224798,6050.837897021371]
+,[7648.340039224799,6216.43789702137]
+,[7549.040039224798,6382.03789702137]
+,[7648.340039224799,6382.03789702137]
+,[7747.640039224799,6216.43789702137]
+,[7846.940039224799,6382.03789702137]
+,[7946.240039224799,6382.03789702137]
+,[7946.240039224799,6547.637897021369]
+,[7846.940039224799,6713.237897021369]
+,[7946.240039224799,6713.237897021369]
+,[8045.540039224799,6547.637897021369]
+,[8045.540039224799,6713.237897021369]
+,[7946.240039224799,6878.837897021368]
+,[7946.240039224799,7044.4378970213675]
+,[8045.540039224799,7210.037897021367]
+,[8144.8400392247995,7375.637897021366]
+,[8144.8400392247995,7541.237897021366]
+,[8045.540039224799,7375.637897021366]
+,[8144.8400392247995,7210.037897021367]
+,[8045.540039224799,7044.4378970213675]
+,[7946.240039224799,7210.037897021367]
+,[7846.940039224799,7210.037897021367]
+,[7946.240039224799,7375.637897021366]
+,[8045.540039224799,7541.237897021366]
+,[8144.8400392247995,7706.837897021365]
+,[8244.1400392248,7541.237897021366]
+,[8343.4400392248,7541.237897021366]
+,[8343.4400392248,7706.837897021365]
+,[8244.1400392248,7706.837897021365]
+,[4735.523842661975,3503.497768214323]
+,[4636.223842661975,3337.897768214323]
+,[4536.923842661975,3337.897768214323]
+,[4437.623842661975,3172.2977682143232]
+,[4338.323842661975,3172.2977682143232]
+,[4239.023842661974,3172.2977682143232]
+,[4338.323842661975,3006.6977682143233]
+,[4437.623842661975,2841.0977682143234]
+,[4338.323842661975,2675.4977682143235]
+,[4338.323842661975,2509.8977682143236]
+,[4239.023842661974,2675.4977682143235]
+,[4139.723842661974,2509.8977682143236]
+,[4040.4238426619745,2344.2977682143237]
+,[4139.723842661974,2178.697768214324]
+,[4239.023842661974,2178.697768214324]
+,[4139.723842661974,2344.2977682143237]
+,[4040.4238426619745,2178.697768214324]
+,[4139.723842661974,2013.0977682143237]
+,[4139.723842661974,1847.4977682143235]
+,[4239.023842661974,2013.0977682143237]
+,[4239.023842661974,1847.4977682143235]
+,[4338.323842661975,1847.4977682143235]
+,[4437.623842661975,1847.4977682143235]
+,[4536.923842661975,1681.8977682143234]
+,[4437.623842661975,1516.2977682143232]
+,[4536.923842661975,1516.2977682143232]
+,[4536.923842661975,1350.697768214323]
+,[4437.623842661975,1350.697768214323]
+,[4536.923842661975,1185.097768214323]
+,[4636.223842661975,1019.497768214323]
+,[4536.923842661975,853.897768214323]
+,[4636.223842661975,853.897768214323]
+,[4735.523842661975,688.2977682143231]
+,[4636.223842661975,522.6977682143232]
+,[4636.223842661975,357.09776821432325]
+,[4735.523842661975,357.09776821432325]
+,[4735.523842661975,522.6977682143232]
+,[4636.223842661975,688.2977682143231]
+,[4735.523842661975,853.897768214323]
+,[4834.8238426619755,853.897768214323]
+,[4735.523842661975,1019.497768214323]
+,[4735.523842661975,1185.097768214323]
+,[4735.523842661975,1350.697768214323]
+,[4834.8238426619755,1516.2977682143232]
+,[4735.523842661975,1516.2977682143232]
+,[4834.8238426619755,1350.697768214323]
+,[4834.8238426619755,1185.097768214323]
+,[4934.123842661976,1350.697768214323]
+,[5033.423842661976,1185.097768214323]
+,[5033.423842661976,1019.497768214323]
+,[5033.423842661976,853.897768214323]
+,[4934.123842661976,853.897768214323]
+,[4934.123842661976,1019.497768214323]
+,[4834.8238426619755,1019.497768214323]
+,[4934.123842661976,1185.097768214323]
+,[5033.423842661976,1350.697768214323]
+,[5132.723842661976,1350.697768214323]
+,[5132.723842661976,1185.097768214323]
+,[5232.023842661976,1019.497768214323]
+,[5232.023842661976,1185.097768214323]
+,[5331.323842661976,1019.497768214323]
+,[5430.623842661977,1019.497768214323]
+,[5529.923842661977,1185.097768214323]
+,[5430.623842661977,1350.697768214323]
+,[5430.623842661977,1516.2977682143232]
+,[5529.923842661977,1350.697768214323]
+,[5629.223842661977,1350.697768214323]
+,[5728.523842661977,1350.697768214323]
+,[5728.523842661977,1516.2977682143232]
+,[5728.523842661977,1681.8977682143234]
+,[5629.223842661977,1516.2977682143232]
+,[5529.923842661977,1516.2977682143232]
+,[5629.223842661977,1681.8977682143234]
+,[5529.923842661977,1681.8977682143234]
+,[5430.623842661977,1847.4977682143235]
+,[5331.323842661976,1847.4977682143235]
+,[5331.323842661976,2013.0977682143237]
+,[5232.023842661976,2178.697768214324]
+,[5132.723842661976,2013.0977682143237]
+,[5132.723842661976,2178.697768214324]
+,[5232.023842661976,2013.0977682143237]
+,[5232.023842661976,1847.4977682143235]
+,[5232.023842661976,1681.8977682143234]
+,[5331.323842661976,1681.8977682143234]
+,[5331.323842661976,1516.2977682143232]
+,[5331.323842661976,1350.697768214323]
+,[5232.023842661976,1350.697768214323]
+,[5232.023842661976,1516.2977682143232]
+,[5132.723842661976,1516.2977682143232]
+,[5132.723842661976,1681.8977682143234]
+,[5033.423842661976,1847.4977682143235]
+,[5132.723842661976,1847.4977682143235]
+,[5033.423842661976,2013.0977682143237]
+,[4934.123842661976,2178.697768214324]
+,[5033.423842661976,2344.2977682143237]
+,[4934.123842661976,2344.2977682143237]
+,[4834.8238426619755,2178.697768214324]
+,[4834.8238426619755,2344.2977682143237]
+,[4735.523842661975,2344.2977682143237]
+,[4636.223842661975,2344.2977682143237]
+,[4536.923842661975,2178.697768214324]
+,[4437.623842661975,2013.0977682143237]
+,[4338.323842661975,2178.697768214324]
+,[4437.623842661975,2344.2977682143237]
+,[4536.923842661975,2509.8977682143236]
+,[4636.223842661975,2675.4977682143235]
+,[4636.223842661975,2509.8977682143236]
+,[4536.923842661975,2675.4977682143235]
+,[4636.223842661975,2841.0977682143234]
+,[4536.923842661975,2841.0977682143234]
+,[4636.223842661975,3006.6977682143233]
+,[4735.523842661975,3172.2977682143232]
+,[4834.8238426619755,3006.6977682143233]
+,[4735.523842661975,2841.0977682143234]
+,[4735.523842661975,3006.6977682143233]
+,[4636.223842661975,3172.2977682143232]
+,[4735.523842661975,3337.897768214323]
+,[4834.8238426619755,3503.497768214323]
+,[4735.523842661975,3669.097768214323]
+,[4834.8238426619755,3834.697768214323]
+,[4834.8238426619755,3669.097768214323]
+,[4934.123842661976,3503.497768214323]
+,[5033.423842661976,3503.497768214323]
+,[5033.423842661976,3337.897768214323]
+,[4934.123842661976,3337.897768214323]
+,[4834.8238426619755,3172.2977682143232]
+,[4834.8238426619755,3337.897768214323]
+,[4934.123842661976,3172.2977682143232]
+,[5033.423842661976,3006.6977682143233]
+,[5132.723842661976,2841.0977682143234]
+,[5132.723842661976,3006.6977682143233]
+,[5232.023842661976,3172.2977682143232]
+,[5232.023842661976,3337.897768214323]
+,[5132.723842661976,3337.897768214323]
+,[5232.023842661976,3503.497768214323]
+,[5331.323842661976,3337.897768214323]
+,[5331.323842661976,3503.497768214323]
+,[5430.623842661977,3669.097768214323]
+,[5331.323842661976,3669.097768214323]
+,[5430.623842661977,3503.497768214323]
+,[5430.623842661977,3337.897768214323]
+,[5529.923842661977,3172.2977682143232]
+,[5529.923842661977,3337.897768214323]
+,[5629.223842661977,3337.897768214323]
+,[5728.523842661977,3337.897768214323]
+,[5728.523842661977,3503.497768214323]
+,[5827.823842661977,3503.497768214323]
+,[5927.1238426619775,3669.097768214323]
+,[6026.423842661978,3669.097768214323]
+,[6125.723842661978,3503.497768214323]
+,[6125.723842661978,3669.097768214323]
+,[6225.023842661978,3503.497768214323]
+,[6225.023842661978,3337.897768214323]
+,[6324.323842661978,3337.897768214323]
+,[6423.623842661978,3503.497768214323]
+,[6324.323842661978,3669.097768214323]
+,[6225.023842661978,3669.097768214323]
+,[6324.323842661978,3834.697768214323]
+,[6423.623842661978,3834.697768214323]
+,[6324.323842661978,4000.297768214323]
+,[6225.023842661978,3834.697768214323]
+,[6125.723842661978,3834.697768214323]
+,[6125.723842661978,4000.297768214323]
+,[6225.023842661978,4000.297768214323]
+,[6225.023842661978,4165.897768214322]
+,[6225.023842661978,4331.497768214322]
+,[6125.723842661978,4165.897768214322]
+,[6026.423842661978,4000.2977682143223]
+,[5927.1238426619775,4165.897768214322]
+,[6026.423842661978,4331.497768214322]
+,[6026.423842661978,4497.097768214321]
+,[5927.1238426619775,4497.097768214321]
+,[5827.823842661977,4662.697768214321]
+,[5728.523842661977,4828.29776821432]
+,[5827.823842661977,4828.29776821432]
+,[5927.1238426619775,4828.29776821432]
+,[5927.1238426619775,4662.697768214321]
+,[5827.823842661977,4497.097768214321]
+,[5927.1238426619775,4331.497768214322]
+,[5827.823842661977,4165.897768214322]
+,[5728.523842661977,4331.497768214322]
+,[5728.523842661977,4165.897768214322]
+,[5629.223842661977,4000.2977682143223]
+,[5629.223842661977,3834.6977682143224]
+,[5529.923842661977,3669.0977682143225]
+,[5629.223842661977,3503.4977682143226]
+,[5728.523842661977,3669.0977682143225]
+,[5827.823842661977,3669.0977682143225]
+,[5927.1238426619775,3834.6977682143224]
+,[5927.1238426619775,4000.2977682143223]
+,[6026.423842661978,4165.897768214322]
+,[6125.723842661978,4331.497768214322]
+,[6225.023842661978,4497.097768214321]
+,[6225.023842661978,4662.697768214321]
+,[6324.323842661978,4662.697768214321]
+,[6225.023842661978,4828.29776821432]
+,[6324.323842661978,4828.29776821432]
+,[6423.623842661978,4828.29776821432]
+,[6324.323842661978,4993.8977682143195]
+,[6225.023842661978,5159.497768214319]
+,[6125.723842661978,5159.497768214319]
+,[6026.423842661978,5325.097768214318]
+,[5927.1238426619775,5490.697768214318]
+,[6026.423842661978,5656.297768214317]
+,[5927.1238426619775,5821.897768214317]
+,[5927.1238426619775,5987.497768214316]
+,[6026.423842661978,5987.497768214316]
+,[6026.423842661978,5821.897768214317]
+,[5927.1238426619775,5656.297768214317]
+,[5827.823842661977,5656.297768214317]
+,[5827.823842661977,5490.697768214318]
+,[5728.523842661977,5490.697768214318]
+,[5629.223842661977,5325.097768214318]
+,[5629.223842661977,5159.497768214319]
+,[5529.923842661977,4993.8977682143195]
+,[5529.923842661977,5159.497768214319]
+,[5629.223842661977,4993.8977682143195]
+,[5629.223842661977,4828.29776821432]
+,[5529.923842661977,4662.697768214321]
+,[5430.623842661977,4828.29776821432]
+,[5529.923842661977,4828.29776821432]
+,[5629.223842661977,4662.697768214321]
+,[5728.523842661977,4662.697768214321]
+,[5629.223842661977,4497.097768214321]
+,[5728.523842661977,4497.097768214321]
+,[5827.823842661977,4331.497768214322]
+,[10216.161365168813,2951.605409896135]
+,[10116.861365168812,2951.605409896135]
+,[10017.56136516881,3117.205409896135]
+,[9918.26136516881,3117.205409896135]
+,[9818.961365168809,3117.205409896135]
+,[9719.661365168808,3282.8054098961347]
+,[9620.361365168807,3282.8054098961347]
+,[9620.361365168807,3117.205409896135]
+,[9521.061365168805,2951.605409896135]
+,[9521.061365168805,2786.005409896135]
+,[9620.361365168807,2786.005409896135]
+,[9719.661365168808,2786.005409896135]
+,[9818.961365168809,2620.405409896135]
+,[9918.26136516881,2786.005409896135]
+,[9818.961365168809,2951.605409896135]
+,[9818.961365168809,2786.005409896135]
+,[9719.661365168808,2620.405409896135]
+,[9719.661365168808,2454.805409896135]
+,[9620.361365168807,2289.2054098961353]
+,[9521.061365168805,2123.6054098961354]
+,[9620.361365168807,1958.0054098961352]
+,[9719.661365168808,2123.6054098961354]
+,[9818.961365168809,2289.2054098961353]
+,[9818.961365168809,2123.6054098961354]
+,[9818.961365168809,1958.0054098961352]
+,[9719.661365168808,1958.0054098961352]
+,[9620.361365168807,1792.405409896135]
+,[9620.361365168807,1626.805409896135]
+,[9521.061365168805,1461.2054098961348]
+,[9421.761365168804,1295.6054098961347]
+,[9521.061365168805,1130.0054098961346]
+,[9521.061365168805,964.4054098961345]
+,[9421.761365168804,964.4054098961345]
+,[9521.061365168805,798.8054098961346]
+,[9620.361365168807,798.8054098961346]
+,[9620.361365168807,964.4054098961345]
+,[9620.361365168807,1130.0054098961346]
+,[9620.361365168807,1295.6054098961347]
+,[9620.361365168807,1461.2054098961348]
+,[9719.661365168808,1295.6054098961347]
+,[9818.961365168809,1130.0054098961346]
+,[9918.26136516881,964.4054098961345]
+,[9818.961365168809,964.4054098961345]
+,[9918.26136516881,798.8054098961346]
+,[10017.56136516881,633.2054098961347]
+,[9918.26136516881,467.60540989613474]
+,[9918.26136516881,302.0054098961348]
+,[10017.56136516881,302.0054098961348]
+,[10116.861365168812,136.40540989613478]
+,[10116.861365168812,302.0054098961348]
+,[10116.861365168812,467.60540989613474]
+,[10116.861365168812,633.2054098961347]
+,[10216.161365168813,633.2054098961347]
+,[10216.161365168813,798.8054098961346]
+,[10315.461365168814,633.2054098961347]
+,[10315.461365168814,798.8054098961346]
+,[10414.761365168815,798.8054098961346]
+,[10514.061365168816,633.2054098961347]
+,[10514.061365168816,798.8054098961346]
+,[10414.761365168815,964.4054098961345]
+,[10315.461365168814,964.4054098961345]
+,[10216.161365168813,964.4054098961345]
+,[10116.861365168812,798.8054098961346]
+,[10017.56136516881,798.8054098961346]
+,[10116.861365168812,964.4054098961345]
+,[10216.161365168813,1130.0054098961346]
+,[10116.861365168812,1130.0054098961346]
+,[10216.161365168813,1295.6054098961347]
+,[10216.161365168813,1461.2054098961348]
+,[10315.461365168814,1626.805409896135]
+,[10315.461365168814,1792.405409896135]
+,[10216.161365168813,1958.0054098961352]
+,[10216.161365168813,1792.405409896135]
+,[10116.861365168812,1792.405409896135]
+,[10017.56136516881,1958.0054098961352]
+,[9918.26136516881,2123.6054098961354]
+,[9918.26136516881,1958.0054098961352]
+,[10017.56136516881,2123.6054098961354]
+,[10116.861365168812,2123.6054098961354]
+,[10017.56136516881,2289.2054098961353]
+,[10017.56136516881,2454.805409896135]
+,[10116.861365168812,2289.2054098961353]
+,[10216.161365168813,2454.805409896135]
+,[10315.461365168814,2620.405409896135]
+,[10315.461365168814,2454.805409896135]
+,[10315.461365168814,2289.2054098961353]
+,[10414.761365168815,2454.805409896135]
+,[10514.061365168816,2620.405409896135]
+,[10613.361365168817,2786.005409896135]
+,[10514.061365168816,2786.005409896135]
+,[10613.361365168817,2620.405409896135]
+,[10514.061365168816,2454.805409896135]
+,[10514.061365168816,2289.2054098961353]
+,[10613.361365168817,2289.2054098961353]
+,[10712.661365168819,2289.2054098961353]
+,[10811.96136516882,2454.805409896135]
+,[10911.26136516882,2289.2054098961353]
+,[10811.96136516882,2289.2054098961353]
+,[10712.661365168819,2454.805409896135]
+,[10712.661365168819,2620.405409896135]
+,[10811.96136516882,2786.005409896135]
+,[10911.26136516882,2620.405409896135]
+,[10911.26136516882,2786.005409896135]
+,[11010.561365168822,2620.405409896135]
+,[10911.26136516882,2454.805409896135]
+,[10811.96136516882,2620.405409896135]
+,[10712.661365168819,2786.005409896135]
+,[10811.96136516882,2951.605409896135]
+,[10911.26136516882,2951.605409896135]
+,[10811.96136516882,3117.205409896135]
+,[10712.661365168819,2951.605409896135]
+,[10613.361365168817,2951.605409896135]
+,[10514.061365168816,2951.605409896135]
+,[10414.761365168815,3117.205409896135]
+,[10414.761365168815,2951.605409896135]
+,[10315.461365168814,2786.005409896135]
+,[10216.161365168813,2620.405409896135]
+,[10216.161365168813,2786.005409896135]
+,[10315.461365168814,2951.605409896135]
+,[10315.461365168814,3117.205409896135]
+,[10216.161365168813,3117.205409896135]
+,[10116.861365168812,3117.205409896135]
+,[10017.56136516881,3282.8054098961347]
+,[9918.26136516881,3448.4054098961346]
+,[9818.961365168809,3448.4054098961346]
+,[9818.961365168809,3614.0054098961346]
+,[9719.661365168808,3448.4054098961346]
+,[9818.961365168809,3282.8054098961347]
+,[9719.661365168808,3117.205409896135]
+,[9620.361365168807,2951.605409896135]
+,[9521.061365168805,3117.205409896135]
+,[9521.061365168805,3282.8054098961347]
+,[9421.761365168804,3117.205409896135]
+,[9421.761365168804,3282.8054098961347]
+,[9322.461365168803,3117.205409896135]
+,[9421.761365168804,2951.605409896135]
+,[9322.461365168803,2951.605409896135]
+,[9223.161365168802,2786.005409896135]
+,[9322.461365168803,2620.405409896135]
+,[9421.761365168804,2454.805409896135]
+,[9521.061365168805,2289.2054098961353]
+,[9421.761365168804,2123.6054098961354]
+,[9421.761365168804,1958.0054098961352]
+,[9421.761365168804,1792.405409896135]
+,[9521.061365168805,1626.805409896135]
+,[9421.761365168804,1626.805409896135]
+,[9322.461365168803,1792.405409896135]
+,[9322.461365168803,1626.805409896135]
+,[9322.461365168803,1461.2054098961348]
+,[9421.761365168804,1461.2054098961348]
+,[9521.061365168805,1295.6054098961347]
+,[9421.761365168804,1130.0054098961346]
+,[9322.461365168803,964.4054098961345]
+,[9223.161365168802,964.4054098961345]
+,[9223.161365168802,798.8054098961346]
+,[9322.461365168803,633.2054098961347]
+,[9421.761365168804,798.8054098961346]
+,[9421.761365168804,633.2054098961347]
+,[9521.061365168805,633.2054098961347]
+,[9421.761365168804,467.60540989613474]
+,[9421.761365168804,302.0054098961348]
+,[9322.461365168803,136.40540989613478]
+,[9223.161365168802,302.0054098961348]
+,[9123.861365168801,302.0054098961348]
+,[9024.5613651688,136.40540989613478]
+,[9123.861365168801,136.40540989613478]
+,[9223.161365168802,136.40540989613478]
+,[9322.461365168803,302.0054098961348]
+,[9421.761365168804,136.40540989613478]
+,[9521.061365168805,136.40540989613478]
+,[9620.361365168807,136.40540989613478]
+,[9620.361365168807,302.0054098961348]
+,[9521.061365168805,302.0054098961348]
+,[9521.061365168805,467.60540989613474]
+,[9620.361365168807,467.60540989613474]
+,[9719.661365168808,302.0054098961348]
+,[9719.661365168808,136.40540989613478]
+,[9818.961365168809,136.40540989613478]
+,[9918.26136516881,136.40540989613478]
+,[10017.56136516881,136.40540989613478]
+,[366.07287160549004,5394.185440937868]
+,[465.37287160549005,5394.185440937868]
+,[465.37287160549005,5559.785440937868]
+,[366.0728716054901,5559.785440937868]
+,[366.0728716054901,5725.385440937867]
+,[266.77287160549014,5725.385440937867]
+,[167.47287160549016,5559.785440937868]
+,[266.77287160549014,5559.785440937868]
+,[266.77287160549014,5394.185440937868]
+,[266.77287160549014,5228.585440937869]
+,[167.47287160549016,5394.185440937868]
+,[68.17287160549016,5228.585440937869]
+,[167.47287160549013,5062.9854409378695]
+,[68.17287160549013,4897.38544093787]
+,[167.47287160549013,4731.785440937871]
+,[266.77287160549014,4731.785440937871]
+,[167.47287160549016,4566.185440937871]
+,[68.17287160549016,4566.185440937871]
+,[68.17287160549016,4731.785440937871]
+,[167.47287160549013,4897.38544093787]
+,[68.17287160549013,5062.9854409378695]
+,[167.47287160549013,5228.585440937869]
+,[266.77287160549014,5062.9854409378695]
+,[366.0728716054901,4897.38544093787]
+,[266.77287160549014,4897.38544093787]
+,[366.0728716054901,4731.785440937871]
+,[465.37287160549005,4897.38544093787]
+,[366.0728716054901,5062.9854409378695]
+,[465.37287160549005,5062.9854409378695]
+,[366.0728716054901,5228.585440937869]
+,[465.37287160549005,5228.585440937869]
+,[564.6728716054901,5394.185440937868]
+,[663.9728716054901,5228.585440937869]
+,[564.6728716054901,5062.9854409378695]
+,[663.9728716054901,4897.38544093787]
+,[763.2728716054902,4731.785440937871]
+,[862.5728716054903,4566.185440937871]
+,[961.8728716054903,4731.785440937871]
+,[862.5728716054903,4731.785440937871]
+,[961.8728716054903,4566.185440937871]
+,[862.5728716054903,4400.585440937872]
+,[961.8728716054903,4234.985440937872]
+,[1061.1728716054904,4400.585440937872]
+,[1160.4728716054904,4234.985440937872]
+,[1160.4728716054904,4400.585440937872]
+,[1259.7728716054903,4234.985440937872]
+,[1359.0728716054903,4069.3854409378723]
+,[1458.3728716054902,4069.3854409378723]
+,[1557.6728716054902,4234.985440937872]
+,[1656.9728716054901,4400.585440937872]
+,[1557.6728716054902,4400.585440937872]
+,[1458.3728716054902,4400.585440937872]
+,[1359.0728716054903,4566.185440937871]
+,[1359.0728716054903,4731.785440937871]
+,[1259.7728716054903,4731.785440937871]
+,[1359.0728716054903,4897.38544093787]
+,[1458.3728716054902,4731.785440937871]
+,[1458.3728716054902,4897.38544093787]
+,[1359.0728716054903,5062.9854409378695]
+,[1259.7728716054903,5228.585440937869]
+,[1259.7728716054903,5062.9854409378695]
+,[1259.7728716054903,4897.38544093787]
+,[1160.4728716054904,5062.9854409378695]
+,[1160.4728716054904,5228.585440937869]
+,[1061.1728716054904,5228.585440937869]
+,[1061.1728716054904,5062.9854409378695]
+,[961.8728716054903,5228.585440937869]
+,[862.5728716054903,5062.9854409378695]
+,[961.8728716054903,5062.9854409378695]
+,[961.8728716054903,4897.38544093787]
+,[1061.1728716054904,4897.38544093787]
+,[1160.4728716054904,4731.785440937871]
+,[1259.7728716054903,4566.185440937871]
+,[1359.0728716054903,4400.585440937872]
+,[1458.3728716054902,4566.185440937871]
+,[1557.6728716054902,4566.185440937871]
+,[1656.9728716054901,4731.785440937871]
+,[1557.6728716054902,4897.38544093787]
+,[1458.3728716054902,5062.9854409378695]
+,[1557.6728716054902,5228.585440937869]
+,[1656.9728716054901,5062.9854409378695]
+,[1756.27287160549,5062.9854409378695]
+,[1756.27287160549,4897.38544093787]
+,[1855.57287160549,5062.9854409378695]
+,[1954.87287160549,4897.38544093787]
+,[2054.17287160549,5062.9854409378695]
+,[1954.87287160549,5062.9854409378695]
+,[2054.17287160549,5228.585440937869]
+,[2153.4728716054897,5228.585440937869]
+,[2252.7728716054894,5062.9854409378695]
+,[2352.072871605489,5228.585440937869]
+,[2451.372871605489,5394.185440937868]
+,[2352.072871605489,5394.185440937868]
+,[2252.7728716054894,5228.585440937869]
+,[2153.4728716054897,5062.9854409378695]
+,[2153.4728716054897,4897.38544093787]
+,[2252.7728716054894,4897.38544093787]
+,[2352.072871605489,4731.785440937871]
+,[2252.7728716054894,4731.785440937871]
+,[2153.4728716054897,4731.785440937871]
+,[2054.17287160549,4566.185440937871]
+,[1954.87287160549,4731.785440937871]
+,[1855.57287160549,4897.38544093787]
+,[1756.27287160549,4731.785440937871]
+,[1855.57287160549,4731.785440937871]
+,[1855.57287160549,4566.185440937871]
+,[1756.27287160549,4566.185440937871]
+,[1656.9728716054901,4566.185440937871]
+,[1557.6728716054902,4731.785440937871]
+,[1656.9728716054901,4897.38544093787]
+,[1557.6728716054902,5062.9854409378695]
+,[1458.3728716054902,5228.585440937869]
+,[1359.0728716054903,5228.585440937869]
+,[1259.7728716054903,5394.185440937868]
+,[1259.7728716054903,5559.785440937868]
+,[1160.4728716054904,5559.785440937868]
+,[1061.1728716054904,5559.785440937868]
+,[1160.4728716054904,5725.385440937867]
+,[1259.7728716054903,5725.385440937867]
+,[1359.0728716054903,5559.785440937868]
+,[1458.3728716054902,5725.385440937867]
+,[1458.3728716054902,5559.785440937868]
+,[1359.0728716054903,5725.385440937867]
+,[1259.7728716054903,5890.985440937867]
+,[1359.0728716054903,5890.985440937867]
+,[1259.7728716054903,6056.585440937866]
+,[1359.0728716054903,6222.185440937866]
+,[1458.3728716054902,6222.185440937866]
+,[1458.3728716054902,6387.785440937865]
+,[1557.6728716054902,6222.185440937866]
+,[1557.6728716054902,6387.785440937865]
+,[1656.9728716054901,6222.185440937866]
+,[1756.27287160549,6056.585440937866]
+,[1855.57287160549,5890.985440937867]
+,[1756.27287160549,5890.985440937867]
+,[1656.9728716054901,6056.585440937866]
+,[1557.6728716054902,5890.985440937867]
+,[1458.3728716054902,5890.985440937867]
+,[1359.0728716054903,6056.585440937866]
+,[1259.7728716054903,6222.185440937866]
+,[1160.4728716054904,6056.585440937866]
+,[1061.1728716054904,5890.985440937867]
+,[1061.1728716054904,6056.585440937866]
+,[1160.4728716054904,6222.185440937866]
+,[1061.1728716054904,6222.185440937866]
+,[961.8728716054903,6222.185440937866]
+,[961.8728716054903,6056.585440937866]
+,[961.8728716054903,5890.985440937867]
+,[961.8728716054903,5725.385440937867]
+,[862.5728716054903,5559.785440937868]
+,[763.2728716054902,5725.385440937867]
+,[862.5728716054903,5725.385440937867]
+,[763.2728716054902,5890.985440937867]
+,[663.9728716054901,5725.385440937867]
+,[763.2728716054902,5559.785440937868]
+,[763.2728716054902,5394.185440937868]
+,[862.5728716054903,5228.585440937869]
+,[961.8728716054903,5394.185440937868]
+,[1061.1728716054904,5394.185440937868]
+,[961.8728716054903,5559.785440937868]
+,[862.5728716054903,5394.185440937868]
+,[763.2728716054902,5228.585440937869]
+,[663.9728716054901,5062.9854409378695]
+,[763.2728716054902,5062.9854409378695]
+,[763.2728716054902,4897.38544093787]
+,[663.9728716054901,4731.785440937871]
+,[564.6728716054901,4731.785440937871]
+,[465.37287160549005,4566.185440937871]
+,[366.0728716054901,4566.185440937871]
+,[465.37287160549005,4731.785440937871]
+,[564.6728716054901,4566.185440937871]
+,[465.37287160549005,4400.585440937872]
+,[366.0728716054901,4400.585440937872]
+,[266.77287160549014,4234.985440937872]
+,[167.47287160549016,4234.985440937872]
+,[266.77287160549014,4400.585440937872]
+,[266.77287160549014,4566.185440937871]
+,[167.47287160549016,4400.585440937872]
+,[68.17287160549016,4234.985440937872]
+,[167.47287160549013,4069.3854409378723]
+,[68.17287160549013,3903.7854409378724]
+,[68.17287160549013,4069.3854409378723]
+,[167.47287160549013,3903.7854409378724]
+,[266.77287160549014,3903.7854409378724]
+,[366.0728716054901,3738.1854409378725]
+,[266.77287160549014,3738.1854409378725]
+,[266.77287160549014,3572.5854409378726]
+,[167.47287160549016,3406.9854409378727]
+,[167.47287160549016,3241.3854409378728]
+,[266.77287160549014,3241.3854409378728]
+,[266.77287160549014,3406.9854409378727]
+,[366.0728716054901,3572.5854409378726]
+,[465.37287160549005,3738.1854409378725]
+,[465.37287160549005,3903.7854409378724]
+,[366.0728716054901,4069.3854409378723]
+,[366.0728716054901,4234.985440937872]
+,[465.37287160549005,4234.985440937872]
+,[564.6728716054901,4069.3854409378723]
+,[465.37287160549005,4069.3854409378723]
+,[564.6728716054901,4234.985440937872]
+,[663.9728716054901,4069.3854409378723]
+,[663.9728716054901,4234.985440937872]
+,[663.9728716054901,4400.585440937872]
+,[763.2728716054902,4566.185440937871]
+,[763.2728716054902,4400.585440937872]
+,[663.9728716054901,4566.185440937871]
+,[564.6728716054901,4400.585440937872]
+,[19431.915041401327,3495.506142643713]
+,[19332.61504140133,3661.1061426437127]
+,[19431.915041401327,3661.1061426437127]
+,[19531.215041401327,3661.1061426437127]
+,[19630.515041401326,3495.506142643713]
+,[19630.515041401326,3661.1061426437127]
+,[19729.815041401325,3826.7061426437126]
+,[19630.515041401326,3826.7061426437126]
+,[19729.815041401325,3992.3061426437125]
+,[19630.515041401326,3992.3061426437125]
+,[19630.515041401326,4157.906142643712]
+,[19630.515041401326,4323.506142643711]
+,[19531.215041401327,4157.906142643712]
+,[19431.915041401327,4323.506142643711]
+,[19531.215041401327,4489.106142643711]
+,[19431.915041401327,4654.70614264371]
+,[19332.61504140133,4654.70614264371]
+,[19332.61504140133,4820.30614264371]
+,[19332.61504140133,4985.906142643709]
+,[19233.31504140133,4985.906142643709]
+,[19134.01504140133,5151.506142643709]
+,[19034.71504140133,5151.506142643709]
+,[19134.01504140133,5317.106142643708]
+,[19034.71504140133,5317.106142643708]
+,[19034.71504140133,5482.706142643708]
+,[18935.41504140133,5648.306142643707]
+,[18836.115041401332,5813.9061426437065]
+,[18836.115041401332,5979.506142643706]
+,[18935.41504140133,5979.506142643706]
+,[19034.71504140133,6145.106142643705]
+,[19034.71504140133,5979.506142643706]
+,[19034.71504140133,5813.9061426437065]
+,[19134.01504140133,5648.306142643707]
+,[19233.31504140133,5648.306142643707]
+,[19134.01504140133,5813.9061426437065]
+,[19134.01504140133,5979.506142643706]
+,[19233.31504140133,5813.9061426437065]
+,[19233.31504140133,5979.506142643706]
+,[19332.61504140133,6145.106142643705]
+,[19332.61504140133,6310.706142643705]
+,[19233.31504140133,6310.706142643705]
+,[19233.31504140133,6476.306142643704]
+,[19332.61504140133,6476.306142643704]
+,[19431.915041401327,6641.906142643704]
+,[19332.61504140133,6807.506142643703]
+,[19332.61504140133,6641.906142643704]
+,[19431.915041401327,6476.306142643704]
+,[19431.915041401327,6310.706142643705]
+,[19531.215041401327,6145.106142643705]
+,[19431.915041401327,5979.506142643706]
+,[19431.915041401327,6145.106142643705]
+,[19531.215041401327,5979.506142643706]
+,[19630.515041401326,5813.9061426437065]
+,[19630.515041401326,5979.506142643706]
+,[19729.815041401325,5813.9061426437065]
+,[19829.115041401325,5979.506142643706]
+,[19729.815041401325,5979.506142643706]
+,[19729.815041401325,6145.106142643705]
+,[19729.815041401325,6310.706142643705]
+,[19630.515041401326,6476.306142643704]
+,[19729.815041401325,6476.306142643704]
+,[19630.515041401326,6310.706142643705]
+,[19531.215041401327,6310.706142643705]
+,[19531.215041401327,6476.306142643704]
+,[19630.515041401326,6641.906142643704]
+,[19729.815041401325,6807.506142643703]
+,[19829.115041401325,6973.106142643703]
+,[19928.415041401324,6973.106142643703]
+,[19928.415041401324,7138.706142643702]
+,[20027.715041401323,7138.706142643702]
+,[20027.715041401323,7304.306142643702]
+,[19928.415041401324,7304.306142643702]
+,[19829.115041401325,7304.306142643702]
+,[19829.115041401325,7469.906142643701]
+,[19928.415041401324,7469.906142643701]
+,[19928.415041401324,7635.5061426437005]
+,[19928.415041401324,7801.1061426437]
+,[20027.715041401323,7635.5061426437005]
+,[20027.715041401323,7801.1061426437]
+,[20127.015041401322,7801.1061426437]
+,[20226.31504140132,7801.1061426437]
+,[20325.61504140132,7801.1061426437]
+,[20226.31504140132,7635.5061426437005]
+,[20226.31504140132,7469.906142643701]
+,[20226.31504140132,7304.306142643702]
+,[20127.015041401322,7304.306142643702]
+,[20027.715041401323,7469.906142643701]
+,[20127.015041401322,7469.906142643701]
+,[20127.015041401322,7635.5061426437005]
+,[2748.790306732237,2362.9553147492866]
+,[2848.0903067322365,2528.5553147492865]
+,[2748.790306732237,2694.1553147492864]
+,[2649.490306732237,2859.7553147492863]
+,[2748.790306732237,3025.355314749286]
+,[2848.0903067322365,2859.7553147492863]
+,[2848.0903067322365,2694.1553147492864]
+,[2947.3903067322362,2694.1553147492864]
+,[3046.690306732236,2859.7553147492863]
+,[3145.9903067322357,2694.1553147492864]
+,[3145.9903067322357,2528.5553147492865]
+,[3046.690306732236,2694.1553147492864]
+,[3145.9903067322357,2859.7553147492863]
+,[3046.690306732236,3025.355314749286]
+,[3145.9903067322357,3025.355314749286]
+,[3245.2903067322354,3190.955314749286]
+,[3245.2903067322354,3356.555314749286]
+,[3344.590306732235,3522.155314749286]
+,[3443.890306732235,3356.555314749286]
+,[3543.1903067322346,3356.555314749286]
+,[3642.4903067322343,3190.955314749286]
+,[3741.790306732234,3025.355314749286]
+,[3741.790306732234,2859.7553147492863]
+,[3841.090306732234,3025.355314749286]
+,[3841.090306732234,3190.955314749286]
+,[3741.790306732234,3190.955314749286]
+,[3642.4903067322343,3025.355314749286]
+,[3543.1903067322346,3025.355314749286]
+,[3543.1903067322346,2859.7553147492863]
+,[3443.890306732235,3025.355314749286]
+,[3443.890306732235,3190.955314749286]
+,[3543.1903067322346,3190.955314749286]
+,[3642.4903067322343,3356.555314749286]
+,[3543.1903067322346,3522.155314749286]
+,[3443.890306732235,3687.755314749286]
+,[3443.890306732235,3853.3553147492858]
+,[3344.590306732235,3687.755314749286]
+,[3245.2903067322354,3853.3553147492858]
+,[3245.2903067322354,3687.755314749286]
+,[3145.9903067322357,3687.755314749286]
+,[3046.690306732236,3853.3553147492858]
+,[3145.9903067322357,4018.9553147492857]
+,[3145.9903067322357,3853.3553147492858]
+,[3046.690306732236,3687.755314749286]
+,[3145.9903067322357,3522.155314749286]
+,[3145.9903067322357,3356.555314749286]
+,[3145.9903067322357,3190.955314749286]
+,[3046.690306732236,3190.955314749286]
+,[3046.690306732236,3356.555314749286]
+,[2947.3903067322362,3356.555314749286]
+,[2848.0903067322365,3190.955314749286]
+,[2947.3903067322362,3025.355314749286]
+,[2848.0903067322365,3025.355314749286]
+,[2748.790306732237,2859.7553147492863]
+,[2649.490306732237,2694.1553147492864]
+,[2748.790306732237,2528.5553147492865]
+,[2848.0903067322365,2362.9553147492866]
+,[2748.790306732237,2197.3553147492867]
+,[2649.490306732237,2362.9553147492866]
+,[2649.490306732237,2197.3553147492867]
+,[2550.1903067322373,2362.9553147492866]
+,[2450.8903067322376,2362.9553147492866]
+,[2351.590306732238,2528.5553147492865]
+,[2252.290306732238,2528.5553147492865]
+,[2351.590306732238,2362.9553147492866]
+,[2252.290306732238,2197.3553147492867]
+,[2351.590306732238,2197.3553147492867]
+,[2351.590306732238,2031.7553147492865]
+,[2351.590306732238,1866.1553147492864]
+,[2252.290306732238,1866.1553147492864]
+,[2351.590306732238,1700.5553147492863]
+,[2450.8903067322376,1534.9553147492861]
+,[2351.590306732238,1369.355314749286]
+,[2252.290306732238,1203.7553147492858]
+,[2252.290306732238,1369.355314749286]
+,[2252.290306732238,1534.9553147492861]
+,[2152.9903067322384,1369.355314749286]
+,[2053.6903067322387,1369.355314749286]
+,[1954.3903067322387,1203.7553147492858]
+,[1855.0903067322388,1203.7553147492858]
+,[1755.7903067322388,1038.1553147492857]
+,[1656.4903067322389,1038.1553147492857]
+,[1557.190306732239,872.5553147492857]
+,[1457.890306732239,1038.1553147492857]
+,[1457.890306732239,872.5553147492857]
+,[1457.890306732239,706.9553147492858]
+,[1557.190306732239,706.9553147492858]
+,[1656.4903067322389,872.5553147492857]
+,[1656.4903067322389,706.9553147492858]
+,[1755.7903067322388,706.9553147492858]
+,[1656.4903067322389,541.3553147492859]
+,[1557.190306732239,375.7553147492859]
+,[1656.4903067322389,210.1553147492859]
+,[1755.7903067322388,44.55531474928592]
+,[1656.4903067322389,44.55531474928592]
+,[1557.190306732239,210.1553147492859]
+,[1457.890306732239,210.1553147492859]
+,[1457.890306732239,44.55531474928592]
+,[1358.590306732239,210.1553147492859]
+,[1358.590306732239,375.75531474928584]
+,[1259.290306732239,210.15531474928585]
+,[1259.290306732239,375.75531474928584]
+,[1259.290306732239,541.3553147492859]
+,[1358.590306732239,706.9553147492858]
+,[1358.590306732239,872.5553147492857]
+,[1259.290306732239,706.9553147492858]
+,[1259.290306732239,872.5553147492857]
+,[1259.290306732239,1038.1553147492857]
+,[1358.590306732239,1203.7553147492858]
+,[1358.590306732239,1038.1553147492857]
+,[1457.890306732239,1203.7553147492858]
+,[1557.190306732239,1369.355314749286]
+,[1656.4903067322389,1203.7553147492858]
+,[1557.190306732239,1203.7553147492858]
+,[1557.190306732239,1038.1553147492857]
+,[17254.572515546668,1460.5807801244923]
+,[17353.872515546667,1626.1807801244925]
+,[17453.172515546667,1791.7807801244926]
+,[17552.472515546666,1791.7807801244926]
+,[17453.172515546667,1626.1807801244925]
+,[17353.872515546667,1791.7807801244926]
+,[17453.172515546667,1957.3807801244927]
+,[17353.872515546667,2122.980780124493]
+,[17453.172515546667,2288.580780124493]
+,[17353.872515546667,2454.1807801244927]
+,[17453.172515546667,2619.7807801244926]
+,[17552.472515546666,2619.7807801244926]
+,[17453.172515546667,2785.3807801244925]
+,[17353.872515546667,2619.7807801244926]
+,[17254.572515546668,2454.1807801244927]
+,[17254.572515546668,2288.580780124493]
+,[17353.872515546667,2288.580780124493]
+,[17453.172515546667,2122.980780124493]
+,[17552.472515546666,2288.580780124493]
+,[17552.472515546666,2454.1807801244927]
+,[17453.172515546667,2454.1807801244927]
+,[4447.67624466283,4761.1416826913]
+,[4546.97624466283,4595.541682691301]
+,[4546.97624466283,4429.941682691301]
+,[4447.67624466283,4429.941682691301]
+,[4447.67624466283,4595.541682691301]
+,[4348.37624466283,4595.541682691301]
+,[4249.07624466283,4595.541682691301]
+,[4348.37624466283,4761.1416826913]
+,[4249.07624466283,4761.1416826913]
+,[4348.37624466283,4926.7416826912995]
+,[4348.37624466283,5092.341682691299]
+,[4447.67624466283,5257.941682691298]
+,[4546.97624466283,5257.941682691298]
+,[4646.27624466283,5092.341682691299]
+,[4546.97624466283,5092.341682691299]
+,[4646.27624466283,4926.7416826912995]
+,[4646.27624466283,4761.1416826913]
+,[4546.97624466283,4761.1416826913]
+,[4646.27624466283,4595.541682691301]
+,[4745.5762446628305,4595.541682691301]
+,[4646.27624466283,4429.941682691301]
+,[4745.5762446628305,4429.941682691301]
+,[4844.876244662831,4595.541682691301]
+,[4745.5762446628305,4761.1416826913]
+,[4745.5762446628305,4926.7416826912995]
+,[4844.876244662831,4761.1416826913]
+,[4944.176244662831,4761.1416826913]
+,[5043.476244662831,4926.7416826912995]
+,[5043.476244662831,4761.1416826913]
+,[5142.776244662831,4926.7416826912995]
+,[5142.776244662831,4761.1416826913]
+,[5242.076244662831,4595.541682691301]
+,[5142.776244662831,4595.541682691301]
+,[5242.076244662831,4429.941682691301]
+,[5242.076244662831,4264.341682691302]
+,[5142.776244662831,4429.941682691301]
+,[5043.476244662831,4595.541682691301]
+,[5043.476244662831,4429.941682691301]
+,[5043.476244662831,4264.341682691302]
+,[5142.776244662831,4098.741682691302]
+,[5043.476244662831,4098.741682691302]
+,[4944.176244662831,3933.1416826913023]
+,[4944.176244662831,4098.741682691302]
+,[4944.176244662831,4264.341682691302]
+,[4844.876244662831,4098.741682691302]
+,[4745.5762446628305,4264.341682691302]
+,[4646.27624466283,4098.741682691302]
+,[4546.97624466283,3933.1416826913023]
+,[4447.67624466283,4098.741682691302]
+,[4546.97624466283,4264.341682691302]
+,[4447.67624466283,4264.341682691302]
+,[4546.97624466283,4098.741682691302]
+,[4646.27624466283,3933.1416826913023]
+,[4546.97624466283,3767.5416826913024]
+,[4447.67624466283,3601.9416826913025]
+,[4447.67624466283,3767.5416826913024]
+,[4348.37624466283,3767.5416826913024]
+,[4348.37624466283,3933.1416826913023]
+,[4249.07624466283,3767.5416826913024]
+,[4249.07624466283,3933.1416826913023]
+,[4149.776244662829,3933.1416826913023]
+,[4050.4762446628297,4098.741682691302]
+,[4050.4762446628297,3933.1416826913023]
+,[3951.17624466283,3933.1416826913023]
+,[3951.17624466283,4098.741682691302]
+,[3851.8762446628302,4264.341682691302]
+,[3851.8762446628302,4098.741682691302]
+,[3752.5762446628305,4098.741682691302]
+,[3653.276244662831,4264.341682691302]
+,[3553.976244662831,4429.941682691301]
+,[3553.976244662831,4595.541682691301]
+,[3454.6762446628313,4429.941682691301]
+,[3553.976244662831,4264.341682691302]
+,[3653.276244662831,4429.941682691301]
+,[3752.5762446628305,4264.341682691302]
+,[3752.5762446628305,4429.941682691301]
+,[3851.8762446628302,4595.541682691301]
+,[3851.8762446628302,4429.941682691301]
+,[3951.17624466283,4429.941682691301]
+,[4050.4762446628297,4264.341682691302]
+,[4149.776244662829,4098.741682691302]
+,[4249.07624466283,4264.341682691302]
+,[4348.37624466283,4098.741682691302]
+,[4447.67624466283,3933.1416826913023]
+,[9574.088902135607,7352.26293905581]
+,[9474.788902135606,7352.26293905581]
+,[9375.488902135605,7186.662939055811]
+,[9474.788902135606,7021.0629390558115]
+,[9574.088902135607,7021.0629390558115]
+,[9474.788902135606,7186.662939055811]
+,[9574.088902135607,7186.662939055811]
+,[9673.388902135608,7021.0629390558115]
+,[9673.388902135608,6855.462939055812]
+,[9772.68890213561,6689.862939055813]
+,[9673.388902135608,6689.862939055813]
+,[9772.68890213561,6524.262939055813]
+,[9871.98890213561,6358.662939055814]
+,[9971.288902135611,6524.262939055813]
+,[10070.588902135612,6358.662939055814]
+,[10070.588902135612,6193.062939055814]
+,[9971.288902135611,6027.462939055815]
+,[9971.288902135611,5861.862939055815]
+,[9871.98890213561,5861.862939055815]
+,[9871.98890213561,5696.262939055816]
+,[9971.288902135611,5530.662939055816]
+,[10070.588902135612,5530.662939055816]
+,[10070.588902135612,5696.262939055816]
+,[10169.888902135614,5861.862939055815]
+,[10169.888902135614,5696.262939055816]
+,[10070.588902135612,5861.862939055815]
+,[10169.888902135614,6027.462939055815]
+,[10169.888902135614,6193.062939055814]
+,[10269.188902135615,6027.462939055815]
+,[10269.188902135615,5861.862939055815]
+,[10368.488902135616,6027.462939055815]
+,[10269.188902135615,6193.062939055814]
+,[10269.188902135615,6358.662939055814]
+,[10169.888902135614,6358.662939055814]
+,[10070.588902135612,6524.262939055813]
+,[10070.588902135612,6689.862939055813]
+,[9971.288902135611,6855.462939055812]
+,[9971.288902135611,7021.0629390558115]
+,[10070.588902135612,7186.662939055811]
+,[10169.888902135614,7186.662939055811]
+,[10269.188902135615,7186.662939055811]
+,[10169.888902135614,7352.26293905581]
+,[10070.588902135612,7352.26293905581]
+,[10169.888902135614,7517.86293905581]
+,[10169.888902135614,7683.462939055809]
+,[10269.188902135615,7517.86293905581]
+,[10368.488902135616,7683.462939055809]
+,[10467.788902135617,7683.462939055809]
+,[10368.488902135616,7517.86293905581]
+,[10269.188902135615,7352.26293905581]
+,[10368.488902135616,7352.26293905581]
+,[10368.488902135616,7186.662939055811]
+,[10368.488902135616,7021.0629390558115]
+,[10368.488902135616,6855.462939055812]
+,[10269.188902135615,6855.462939055812]
+,[10169.888902135614,6855.462939055812]
+,[10169.888902135614,7021.0629390558115]
+,[10070.588902135612,7021.0629390558115]
+,[10070.588902135612,6855.462939055812]
+,[10169.888902135614,6689.862939055813]
+,[10269.188902135615,6689.862939055813]
+,[10169.888902135614,6524.262939055813]
+,[10269.188902135615,6524.262939055813]
+,[10368.488902135616,6524.262939055813]
+,[10368.488902135616,6358.662939055814]
+,[10467.788902135617,6358.662939055814]
+,[10467.788902135617,6193.062939055814]
+,[10567.088902135618,6358.662939055814]
+,[10567.088902135618,6193.062939055814]
+,[10666.388902135619,6193.062939055814]
+,[10666.388902135619,6358.662939055814]
+,[10567.088902135618,6524.262939055813]
+,[10467.788902135617,6524.262939055813]
+,[10567.088902135618,6689.862939055813]
+,[10467.788902135617,6855.462939055812]
+,[10567.088902135618,7021.0629390558115]
+,[10467.788902135617,7021.0629390558115]
+,[10567.088902135618,6855.462939055812]
+,[10467.788902135617,6689.862939055813]
+,[10368.488902135616,6689.862939055813]
+,[1073.6944354374714,1154.3681204032646]
+,[974.3944354374713,1319.9681204032647]
+,[875.0944354374712,1319.9681204032647]
+,[775.7944354374712,1154.3681204032646]
+,[775.7944354374712,988.7681204032646]
+,[875.0944354374712,823.1681204032647]
+,[875.0944354374712,657.5681204032647]
+,[775.7944354374712,823.1681204032647]
+,[676.4944354374711,657.5681204032647]
+,[676.4944354374711,491.9681204032648]
+,[775.7944354374712,657.5681204032647]
+,[676.4944354374711,823.1681204032647]
+,[676.4944354374711,988.7681204032646]
+,[577.194435437471,823.1681204032647]
+,[577.194435437471,988.7681204032646]
+,[577.194435437471,1154.3681204032646]
+,[676.4944354374711,1319.9681204032647]
+,[577.194435437471,1319.9681204032647]
+,[477.89443543747103,1319.9681204032647]
+,[577.194435437471,1485.5681204032649]
+,[477.89443543747103,1651.168120403265]
+,[577.194435437471,1816.7681204032651]
+,[477.89443543747103,1816.7681204032651]
+,[378.5944354374711,1982.3681204032653]
+,[378.5944354374711,2147.9681204032654]
+,[279.2944354374711,2313.5681204032653]
+,[179.99443543747114,2147.9681204032654]
+,[80.69443543747114,2313.5681204032653]
+,[80.69443543747114,2479.168120403265]
+,[179.9944354374711,2644.768120403265]
+,[179.9944354374711,2479.168120403265]
+,[179.9944354374711,2313.5681204032653]
+,[80.69443543747111,2147.9681204032654]
+,[80.69443543747111,1982.3681204032653]
+,[179.9944354374711,1982.3681204032653]
+,[179.9944354374711,1816.7681204032651]
+,[80.69443543747111,1816.7681204032651]
+,[179.9944354374711,1651.168120403265]
+,[80.69443543747111,1485.5681204032649]
+,[80.69443543747111,1319.9681204032647]
+,[179.9944354374711,1154.3681204032646]
+,[80.69443543747111,1154.3681204032646]
+,[179.9944354374711,988.7681204032646]
+,[279.2944354374711,823.1681204032647]
+,[378.5944354374711,657.5681204032647]
+,[378.5944354374711,823.1681204032647]
+,[477.89443543747103,823.1681204032647]
+,[477.89443543747103,657.5681204032647]
+,[378.5944354374711,491.9681204032648]
+,[477.89443543747103,326.3681204032648]
+,[477.89443543747103,160.76812040326482]
+,[378.5944354374711,160.76812040326482]
+,[279.2944354374711,326.3681204032648]
+,[179.99443543747114,491.9681204032648]
+,[179.99443543747114,326.3681204032648]
+,[279.2944354374711,491.9681204032648]
+,[279.2944354374711,657.5681204032647]
+,[179.99443543747114,823.1681204032647]
+,[279.2944354374711,988.7681204032646]
+,[279.2944354374711,1154.3681204032646]
+,[378.5944354374711,1319.9681204032647]
+,[477.89443543747103,1485.5681204032649]
+,[577.194435437471,1651.168120403265]
+,[676.4944354374711,1651.168120403265]
+,[775.7944354374712,1816.7681204032651]
+,[676.4944354374711,1816.7681204032651]
+,[775.7944354374712,1651.168120403265]
+,[875.0944354374712,1651.168120403265]
+,[974.3944354374713,1651.168120403265]
+,[875.0944354374712,1485.5681204032649]
+,[775.7944354374712,1485.5681204032649]
+,[676.4944354374711,1485.5681204032649]
+,[775.7944354374712,1319.9681204032647]
+,[676.4944354374711,1154.3681204032646]
+,[3138.413562431697,2355.845602060523]
+,[3039.113562431697,2521.445602060523]
+,[3039.113562431697,2355.845602060523]
+,[3039.113562431697,2190.245602060523]
+,[3138.413562431697,2024.645602060523]
+,[3237.7135624316966,1859.045602060523]
+,[3237.7135624316966,2024.645602060523]
+,[3337.0135624316963,1859.045602060523]
+,[3337.0135624316963,1693.4456020605228]
+,[3436.313562431696,1527.8456020605227]
+,[3535.6135624316958,1693.4456020605228]
+,[3535.6135624316958,1859.045602060523]
+,[3634.9135624316955,2024.645602060523]
+,[3734.213562431695,2190.245602060523]
+,[3634.9135624316955,2190.245602060523]
+,[3535.6135624316958,2190.245602060523]
+,[3535.6135624316958,2355.845602060523]
+,[3535.6135624316958,2521.445602060523]
+,[3436.313562431696,2687.045602060523]
+,[3436.313562431696,2852.645602060523]
+,[3535.6135624316958,2687.045602060523]
+,[3634.9135624316955,2521.445602060523]
+,[3634.9135624316955,2355.845602060523]
+,[3734.213562431695,2355.845602060523]
+,[3833.513562431695,2190.245602060523]
+,[3932.8135624316947,2024.645602060523]
+,[3833.513562431695,1859.045602060523]
+,[3833.513562431695,1693.4456020605228]
+,[3734.213562431695,1859.045602060523]
+,[3734.213562431695,1693.4456020605228]
+,[3734.213562431695,1527.8456020605227]
+,[3634.9135624316955,1527.8456020605227]
+,[3634.9135624316955,1693.4456020605228]
+,[3535.6135624316958,1527.8456020605227]
+,[3634.9135624316955,1362.2456020605225]
+,[3535.6135624316958,1362.2456020605225]
+,[3436.313562431696,1196.6456020605224]
+,[3535.6135624316958,1196.6456020605224]
+,[3535.6135624316958,1031.0456020605222]
+,[3436.313562431696,1031.0456020605222]
+,[3535.6135624316958,865.4456020605222]
+,[3436.313562431696,865.4456020605222]
+,[3535.6135624316958,699.8456020605223]
+,[3634.9135624316955,699.8456020605223]
+,[3535.6135624316958,534.2456020605224]
+,[3436.313562431696,368.64560206052244]
+,[3436.313562431696,203.04560206052244]
+,[3337.0135624316963,37.445602060522454]
+,[3436.313562431696,37.445602060522454]
+,[3337.0135624316963,203.04560206052244]
+,[3237.7135624316966,37.445602060522454]
+,[3138.413562431697,37.445602060522454]
+,[3237.7135624316966,203.04560206052244]
+,[3337.0135624316963,368.6456020605224]
+,[3436.313562431696,534.2456020605224]
+,[3337.0135624316963,699.8456020605223]
+,[3237.7135624316966,534.2456020605224]
+,[3337.0135624316963,534.2456020605224]
+,[3436.313562431696,699.8456020605223]
+,[3337.0135624316963,865.4456020605222]
+,[3237.7135624316966,865.4456020605222]
+,[3337.0135624316963,1031.0456020605222]
+,[3237.7135624316966,1196.6456020605224]
+,[3138.413562431697,1362.2456020605225]
+,[3039.113562431697,1527.8456020605227]
+,[3138.413562431697,1527.8456020605227]
+,[3039.113562431697,1693.4456020605228]
+,[2939.8135624316974,1527.8456020605227]
+,[2840.5135624316977,1362.2456020605225]
+,[2840.5135624316977,1527.8456020605227]
+,[2840.5135624316977,1693.4456020605228]
+,[2939.8135624316974,1859.045602060523]
+,[2840.5135624316977,2024.645602060523]
+,[2840.5135624316977,1859.045602060523]
+,[2939.8135624316974,1693.4456020605228]
+,[3039.113562431697,1859.045602060523]
+,[3039.113562431697,2024.645602060523]
+,[2939.8135624316974,2190.245602060523]
+,[2939.8135624316974,2024.645602060523]
+,[16388.412117675925,1839.818884803299]
+,[16289.112117675924,1839.818884803299]
+,[16388.412117675925,1674.2188848032988]
+,[16487.712117675925,1508.6188848032987]
+,[16487.712117675925,1674.2188848032988]
+,[16388.412117675925,1508.6188848032987]
+,[16289.112117675924,1343.0188848032985]
+,[16289.112117675924,1508.6188848032987]
+,[16189.812117675923,1674.2188848032988]
+,[16090.512117675922,1839.818884803299]
+,[16090.512117675922,2005.418884803299]
+,[15991.212117675921,2171.018884803299]
+,[16090.512117675922,2336.618884803299]
+,[16090.512117675922,2502.218884803299]
+,[16090.512117675922,2667.8188848032987]
+,[15991.212117675921,2833.4188848032986]
+,[15991.212117675921,2999.0188848032985]
+,[15891.91211767592,3164.6188848032984]
+,[15891.91211767592,3330.2188848032984]
+,[15991.212117675921,3330.2188848032984]
+,[16090.512117675922,3330.2188848032984]
+,[16189.812117675923,3495.8188848032983]
+,[16289.112117675924,3495.8188848032983]
+,[16189.812117675923,3330.2188848032984]
+,[16189.812117675923,3164.6188848032984]
+,[16289.112117675924,3164.6188848032984]
+,[16388.412117675925,3164.6188848032984]
+,[16388.412117675925,3330.2188848032984]
+,[16487.712117675925,3330.2188848032984]
+,[16587.012117675924,3495.8188848032983]
+,[16587.012117675924,3661.418884803298]
+,[16686.312117675923,3661.418884803298]
+,[16785.612117675922,3661.418884803298]
+,[16884.91211767592,3661.418884803298]
+,[16984.21211767592,3661.418884803298]
+,[16884.91211767592,3827.018884803298]
+,[16884.91211767592,3992.618884803298]
+,[16984.21211767592,3827.018884803298]
+,[17083.51211767592,3661.418884803298]
+,[17182.81211767592,3495.8188848032983]
+,[17182.81211767592,3330.2188848032984]
+,[17282.11211767592,3164.6188848032984]
+,[17282.11211767592,3330.2188848032984]
+,[17182.81211767592,3164.6188848032984]
+,[17083.51211767592,3164.6188848032984]
+,[16984.21211767592,3330.2188848032984]
+,[16984.21211767592,3495.8188848032983]
+,[17083.51211767592,3330.2188848032984]
+,[16984.21211767592,3164.6188848032984]
+,[16984.21211767592,2999.0188848032985]
+,[17083.51211767592,2833.4188848032986]
+,[17083.51211767592,2667.8188848032987]
+,[17182.81211767592,2667.8188848032987]
+,[17182.81211767592,2833.4188848032986]
+,[17083.51211767592,2999.0188848032985]
+,[16984.21211767592,2833.4188848032986]
+,[16884.91211767592,2833.4188848032986]
+,[16884.91211767592,2999.0188848032985]
+,[16785.612117675922,2999.0188848032985]
+,[16884.91211767592,3164.6188848032984]
+,[16785.612117675922,3164.6188848032984]
+,[16686.312117675923,3164.6188848032984]
+,[16587.012117675924,3164.6188848032984]
+,[16587.012117675924,2999.0188848032985]
+,[16487.712117675925,3164.6188848032984]
+,[16587.012117675924,3330.2188848032984]
+,[16686.312117675923,3495.8188848032983]
+,[16686.312117675923,3330.2188848032984]
+,[16785.612117675922,3330.2188848032984]
+,[16884.91211767592,3495.8188848032983]
+,[16785.612117675922,3495.8188848032983]
+,[16884.91211767592,3330.2188848032984]
+,[1272.175991128079,3842.7700224365044]
+,[1371.475991128079,3842.7700224365044]
+,[1272.175991128079,3677.1700224365045]
+,[1172.875991128079,3511.5700224365046]
+,[1272.175991128079,3511.5700224365046]
+,[1172.875991128079,3345.9700224365047]
+,[1073.575991128079,3180.3700224365048]
+,[1073.575991128079,3014.770022436505]
+,[974.275991128079,3014.770022436505]
+,[874.9759911280789,3014.770022436505]
+,[775.6759911280789,2849.170022436505]
+,[775.6759911280789,3014.770022436505]
+,[775.6759911280789,3180.3700224365048]
+,[676.3759911280788,3345.9700224365047]
+,[676.3759911280788,3511.5700224365046]
+,[775.6759911280789,3677.1700224365045]
+,[676.3759911280788,3842.7700224365044]
+,[577.0759911280787,3842.7700224365044]
+,[577.0759911280787,3677.1700224365045]
+,[676.3759911280788,3677.1700224365045]
+,[775.6759911280789,3511.5700224365046]
+,[775.6759911280789,3345.9700224365047]
+,[874.9759911280789,3345.9700224365047]
+,[874.9759911280789,3180.3700224365048]
+,[974.275991128079,3180.3700224365048]
+,[974.275991128079,3345.9700224365047]
+,[1073.575991128079,3511.5700224365046]
+,[1073.575991128079,3677.1700224365045]
+,[1172.875991128079,3677.1700224365045]
+,[1172.875991128079,3842.7700224365044]
+,[1073.575991128079,3842.7700224365044]
+,[1172.875991128079,4008.3700224365043]
+,[1073.575991128079,4008.3700224365043]
+,[974.275991128079,3842.7700224365044]
+,[974.275991128079,4008.3700224365043]
+,[874.9759911280789,4008.3700224365043]
+,[775.6759911280789,4008.3700224365043]
+,[874.9759911280789,3842.7700224365044]
+,[974.275991128079,3677.1700224365045]
+,[974.275991128079,3511.5700224365046]
+,[1073.575991128079,3345.9700224365047]
+,[1172.875991128079,3180.3700224365048]
+,[1272.175991128079,3180.3700224365048]
+,[1272.175991128079,3345.9700224365047]
+,[1371.475991128079,3180.3700224365048]
+,[1470.7759911280789,3345.9700224365047]
+,[1371.475991128079,3345.9700224365047]
+,[1371.475991128079,3511.5700224365046]
+,[1470.7759911280789,3511.5700224365046]
+,[1570.0759911280788,3677.1700224365045]
+,[1470.7759911280789,3677.1700224365045]
+,[1570.0759911280788,3511.5700224365046]
+,[1669.3759911280788,3511.5700224365046]
+,[1669.3759911280788,3677.1700224365045]
+,[1768.6759911280787,3842.7700224365044]
+,[1669.3759911280788,3842.7700224365044]
+,[1768.6759911280787,4008.3700224365043]
+,[1867.9759911280787,3842.7700224365044]
+,[1967.2759911280787,3677.1700224365045]
+,[2066.5759911280784,3842.7700224365044]
+,[2165.875991128078,3677.1700224365045]
+,[2066.5759911280784,3511.5700224365046]
+,[2165.875991128078,3511.5700224365046]
+,[2066.5759911280784,3677.1700224365045]
+,[2165.875991128078,3842.7700224365044]
+,[2265.175991128078,4008.3700224365043]
+,[2364.4759911280776,4008.3700224365043]
+,[2265.175991128078,3842.7700224365044]
+,[2364.4759911280776,3677.1700224365045]
+,[2463.7759911280773,3842.7700224365044]
+,[2463.7759911280773,4008.3700224365043]
+,[2364.4759911280776,3842.7700224365044]
+];
+
+
+main() {
+  for (int i = 0; i < 6000; i++) {
+    var y = panels.length;
+  }
+}
+
diff --git a/tests/language/mixin_lib_extends_method_test.dart b/tests/language/mixin_lib_extends_method_test.dart
index 2c43281..b43e0e0 100644
--- a/tests/language/mixin_lib_extends_method_test.dart
+++ b/tests/language/mixin_lib_extends_method_test.dart
@@ -2,6 +2,8 @@
 // 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 mixin_lib_extends_method_test;
+
 import "mixin_lib_extends_method_lib.dart" as L;
 
 class S {
diff --git a/tests/language/optimized_string_charcodeat_test.dart b/tests/language/optimized_string_charcodeat_test.dart
index 1e84590..aa2bd64 100644
--- a/tests/language/optimized_string_charcodeat_test.dart
+++ b/tests/language/optimized_string_charcodeat_test.dart
@@ -7,27 +7,27 @@
 String one_byte = "hest";
 String two_byte = "høns";
 
-int testOneByteCharCodeAt(String x, int i) {
+int testOneByteCharCodeAt(String x, int j) {
   int test() {
-    return x.charCodeAt(i);
+    return x.charCodeAt(j);
   }
   for (int i = 0; i < 10000; i++) test();
   return test();
 }
 
 
-int testTwoByteCharCodeAt(String x, int i) {
+int testTwoByteCharCodeAt(String x, int j) {
   int test() {
-    return x.charCodeAt(i);
+    return x.charCodeAt(j);
   }
   for (int i = 0; i < 10000; i++) test();
   return test();
 }
 
 
-int testConstantStringCharCodeAt(int i) {
+int testConstantStringCharCodeAt(int j) {
   int test() {
-    return "høns".charCodeAt(i);
+    return "høns".charCodeAt(j);
   }
   for (int i = 0; i < 10000; i++) test();
   return test();
@@ -43,9 +43,35 @@
 }
 
 
+int testOneByteCharCodeAtInLoop(var x) {
+  var result = 0;
+  for (int i = 0; i < x.length; i++) {
+    result += x.charCodeAt(i);
+  }
+  return result;
+}
+
+
+int testTwoByteCharCodeAtInLoop(var x) {
+  var result = 0;
+  for (int i = 0; i < x.length; i++) {
+    result += x.charCodeAt(i);
+  }
+  return result;
+}
+
+
 main() {
-  Expect.equals(101, testOneByteCharCodeAt(one_byte, 1));
-  Expect.equals(248, testTwoByteCharCodeAt(two_byte, 1));
-  Expect.equals(248, testConstantStringCharCodeAt(1));
-  Expect.equals(101, testConstantIndexCharCodeAt(one_byte));
+  for (int j = 0; j < 10; j++) {
+    Expect.equals(101, testOneByteCharCodeAt(one_byte, 1));
+    Expect.equals(248, testTwoByteCharCodeAt(two_byte, 1));
+    Expect.equals(248, testConstantStringCharCodeAt(1));
+    Expect.equals(101, testConstantIndexCharCodeAt(one_byte));
+  }
+  for (int j = 0; j < 2000; j++) {
+    Expect.equals(436, testOneByteCharCodeAtInLoop(one_byte));
+    Expect.equals(577, testTwoByteCharCodeAtInLoop(two_byte));
+  }
+  Expect.throws(() => testOneByteCharCodeAtInLoop(123));
+  Expect.throws(() => testTwoByteCharCodeAtInLoop(123));
 }
diff --git a/tests/language/return_this_type_test.dart b/tests/language/return_this_type_test.dart
new file mode 100644
index 0000000..b97e382
--- /dev/null
+++ b/tests/language/return_this_type_test.dart
@@ -0,0 +1,16 @@
+// 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.
+
+// Make sure the engine does not infer the wrong type for [:A.foo:].
+
+class A {
+  foo() => this;
+}
+
+class B extends A {
+}
+
+main() {
+  Expect.isTrue(new B().foo() is B);
+}
diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart
index 5458e83..43f083a 100644
--- a/tests/lib/async/future_test.dart
+++ b/tests/lib/async/future_test.dart
@@ -564,7 +564,8 @@
   final future = completer.future;
   var port = new ReceivePort();
 
-  future.then((v) => new Future.delayed(10, () => v * 2))
+  future.then((v) => new Future.delayed(const Duration(milliseconds: 10),
+                                        () => v * 2))
         .then((v) {
           Expect.equals(42, v);
           port.close();
@@ -572,6 +573,15 @@
   completer.complete(21);
 }
 
+testChainedFutureValue2Delay() {
+  var port = new ReceivePort();
+
+  new Future.delayed(const Duration(milliseconds: 10))
+    .then((v) {
+      Expect.isNull(v);
+      port.close();
+    });
+}
 testChainedFutureError() {
   final completer = new Completer();
   final future = completer.future;
diff --git a/tests/lib/async/slow_consumer_test.dart b/tests/lib/async/slow_consumer_test.dart
index dcc6167..4b14924 100644
--- a/tests/lib/async/slow_consumer_test.dart
+++ b/tests/lib/async/slow_consumer_test.dart
@@ -28,8 +28,9 @@
           .then((count) {
             // Simulated amount of time it takes to handle the data.
             int ms = data.length * 1000 ~/ bytesPerSecond;
+            Duration duration = new Duration(milliseconds: ms);
             subscription.pause();
-            return new Future.delayed(ms, () {
+            return new Future.delayed(duration, () {
               subscription.resume();
               // Make sure we use data here to keep tracking it.
               return count + data.length;
diff --git a/tests/lib/async/stream_from_iterable_test.dart b/tests/lib/async/stream_from_iterable_test.dart
index 182bf1c..0af493d 100644
--- a/tests/lib/async/stream_from_iterable_test.dart
+++ b/tests/lib/async/stream_from_iterable_test.dart
@@ -62,7 +62,10 @@
     subscription = stream.listen((int value) {
       actual.add(value);
       // Do a 10 ms pause during the playback of the iterable.
-      if (value == 20) { subscription.pause(new Future.delayed(10, () {})); }
+      Duration duration = const Duration(milliseconds: 10);
+      if (value == 20) {
+        subscription.pause(new Future.delayed(duration, () {}));
+      }
     }, onDone: expectAsync0(() {
       actual.close();
       Events expected = new Events.fromIterable(iter);
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index c429be3..8381332 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -17,6 +17,9 @@
 crypto/sha256_test: Slow, Pass
 crypto/sha1_test: Slow, Pass
 
+[ $runtime == safari]
+crypto/hmac_md5_test: Fail # Bug in JSC: the test only passes when being debugged.
+
 [ $compiler == dart2dart ]
 # Skip until we stabilize language tests.
 *: Skip
diff --git a/tests/standalone/byte_array_test.dart b/tests/standalone/byte_array_test.dart
index 5b29c7a..dd5e232 100644
--- a/tests/standalone/byte_array_test.dart
+++ b/tests/standalone/byte_array_test.dart
@@ -55,6 +55,15 @@
     Expect.equals(0, externalClampedByteArray[i]);
   }
 
+  externalClampedByteArray[0] = -1;
+  Expect.equals(0, externalClampedByteArray[0]);
+  
+  for (int i = 0; i < 10; i++) {
+    externalClampedByteArray[i] = i + 250;
+  }
+  for (int i = 0; i < 10; i++) {
+    Expect.equals(i + 250 > 255 ? 255 : i + 250, externalClampedByteArray[i]);
+  }
 }
 
 void testUnsignedByteArrayRange(bool check_throws) {
diff --git a/tests/standalone/constant_left_shift_test.dart b/tests/standalone/constant_left_shift_test.dart
new file mode 100644
index 0000000..3385a24
--- /dev/null
+++ b/tests/standalone/constant_left_shift_test.dart
@@ -0,0 +1,78 @@
+// 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.
+//
+// Dart test program for testing left shifts of a constant.
+
+shiftLeft0(c) => 0 << c;
+shiftLeft1(c) => 1 << c;
+shiftLeft8448(c) => 8448 << c;
+
+shiftLeftNeg1(c) => -1 << c;
+shiftLeftNeg8448(c) => -8448 << c;
+
+main() {
+  // Optimize shifts.
+  for (int i = 0; i < 6000; i++) {
+    shiftLeft1(2);
+    shiftLeft0(2);
+    shiftLeft8448(2);
+    shiftLeftNeg1(2);
+    shiftLeftNeg8448(2);
+  }
+  for (int i = 0; i < 80; i++) {
+    Expect.equals(0, shiftLeft0(i));
+  }
+  // Exceptions.
+  Expect.throws(() => shiftLeft0(-1));
+
+  return;
+  Expect.equals(1, shiftLeft1(0));
+  Expect.equals(128, shiftLeft1(7));
+  Expect.equals(536870912, shiftLeft1(29));
+  // Deoptimize on 32-bit.
+  Expect.equals(1073741824, shiftLeft1(30));
+  Expect.equals(2147483648, shiftLeft1(31));
+  Expect.equals(1152921504606846976, shiftLeft1(60));
+  Expect.equals(2305843009213693952, shiftLeft1(61));
+  // Deoptimize on 64 bits.
+  Expect.equals(4611686018427387904, shiftLeft1(62));
+  Expect.equals(9223372036854775808, shiftLeft1(63));
+
+  Expect.equals(8448, shiftLeft8448(0));
+  Expect.equals(1081344, shiftLeft8448(7));
+  Expect.equals(553648128, shiftLeft8448(16));
+  // Deoptimize on 32-bit.
+  Expect.equals(1107296256, shiftLeft8448(17));
+  Expect.equals(2214592512, shiftLeft8448(18));
+  Expect.equals(1188950301625810944, shiftLeft8448(47));
+  Expect.equals(2377900603251621888, shiftLeft8448(48));
+  // Deoptimize on 64 bits.
+  Expect.equals(4755801206503243776, shiftLeft8448(49));
+  Expect.equals(9511602413006487552, shiftLeft8448(50));
+
+  Expect.equals(-1, shiftLeftNeg1(0));
+  Expect.equals(-128, shiftLeftNeg1(7));
+  Expect.equals(-536870912, shiftLeftNeg1(29));
+  // Deoptimize on 32-bit.
+  Expect.equals(-1073741824, shiftLeftNeg1(30));
+  Expect.equals(-2147483648, shiftLeftNeg1(31));
+  Expect.equals(-1152921504606846976, shiftLeftNeg1(60));
+  Expect.equals(-2305843009213693952, shiftLeftNeg1(61));
+  // Deoptimize on 64 bits.
+  Expect.equals(-4611686018427387904, shiftLeftNeg1(62));
+  Expect.equals(-9223372036854775808, shiftLeftNeg1(63));
+
+  Expect.equals(-8448, shiftLeftNeg8448(0));
+  Expect.equals(-1081344, shiftLeftNeg8448(7));
+  Expect.equals(-553648128, shiftLeftNeg8448(16));
+  // Deoptimize on 32-bit.
+  Expect.equals(-1107296256, shiftLeftNeg8448(17));
+  Expect.equals(-2214592512, shiftLeftNeg8448(18));
+  Expect.equals(-1188950301625810944, shiftLeftNeg8448(47));
+  Expect.equals(-2377900603251621888, shiftLeftNeg8448(48));
+  // Deoptimize on 64 bits.
+  Expect.equals(-4755801206503243776, shiftLeftNeg8448(49));
+  Expect.equals(-9511602413006487552, shiftLeftNeg8448(50));
+}
+
diff --git a/tests/standalone/io/fuzz_support.dart b/tests/standalone/io/fuzz_support.dart
index 4c7cd1c..e6caa12 100644
--- a/tests/standalone/io/fuzz_support.dart
+++ b/tests/standalone/io/fuzz_support.dart
@@ -49,5 +49,7 @@
 // completion.
 Future doItAsync(void f()) {
   // Ignore value and errors.
-  return new Future.delayed(0, f).catchError((_) {}).then((_) => true);
+  return new Future.delayed(Duration.ZERO, f)
+    .catchError((_) {})
+    .then((_) => true);
 }
diff --git a/tests/standalone/io/skipping_dart2js_compilations_test.dart b/tests/standalone/io/skipping_dart2js_compilations_test.dart
index d6b7eb4..c6ce377 100644
--- a/tests/standalone/io/skipping_dart2js_compilations_test.dart
+++ b/tests/standalone/io/skipping_dart2js_compilations_test.dart
@@ -141,13 +141,10 @@
       Expect.isFalse(new File(fileUtils.scriptOutputPath.toNativePath())
           .existsSync());
     }
-    fileUtils.cleanup();
   }
 }
 
-runner.TestCase makeTestCase(String testName,
-                             TestCompletedHandler completedHandler) {
-  var fileUtils = completedHandler.fileUtils;
+runner.TestCase makeTestCase(String testName, FileUtils fileUtils) {
   var config = new options.TestOptionsParser().parse(['--timeout', '2'])[0];
   var scriptDirPath = new Path(new Options().script).directoryPath;
   var createFileScript = scriptDirPath.
@@ -166,7 +163,7 @@
       testName,
       commands,
       config,
-      completedHandler.processCompletedTest,
+      (_) {},
       new Set<String>.from([status.PASS]));
 }
 
@@ -199,26 +196,52 @@
                                   createJsDeps: true,
                                   createDart: true,
                                   createSnapshot: true);
+  void cleanup() {
+    fs_noTestJs.cleanup();
+    fs_noTestJsDeps.cleanup();
+    fs_noTestDart.cleanup();
+    fs_noTestSnapshot.cleanup();
+    fs_notUpToDate_snapshot.cleanup();
+    fs_notUpToDate_dart.cleanup();
+    fs_upToDate.cleanup();
+  }
 
   void touchFilesAndRunTests() {
     fs_notUpToDate_snapshot.touchFile(fs_notUpToDate_snapshot.testSnapshot);
     fs_notUpToDate_dart.touchFile(fs_notUpToDate_dart.testDart);
     fs_upToDate.touchFile(fs_upToDate.testJs);
 
-    void runTest(String name, FileUtils fileUtils, bool shouldRun) {
-      var testCase = makeTestCase(
-          name, new TestCompletedHandler(fileUtils, shouldRun));
-      new runner.RunningProcess(testCase, testCase.commands[0]).start();
+    Future runTest(String name, FileUtils fileUtils, bool shouldRun) {
+      var completedHandler = new TestCompletedHandler(fileUtils, shouldRun);
+      var testCase = makeTestCase(name, fileUtils);
+      var process = new runner.RunningProcess(testCase, testCase.commands[0]);
+      return process.start().then((_) {
+        completedHandler.processCompletedTest(testCase);
+      });
     }
-    runTest("fs_noTestJs", fs_noTestJs, true);
-    runTest("fs_noTestJsDeps", fs_noTestJsDeps, true);
-    runTest("fs_noTestDart", fs_noTestDart, true);
-    runTest("fs_noTestSnapshot", fs_noTestSnapshot, true);
-    runTest("fs_notUpToDate_snapshot", fs_notUpToDate_snapshot, true);
-    runTest("fs_notUpToDate_dart", fs_notUpToDate_dart, true);
-    // This is the only test where all dependencies are present and the test.js
-    // file is newer than all the others. So we pass 'false' for shouldRun.
-    runTest("fs_upToDate", fs_upToDate, false);
+    // We run the tests in sequence, so that if one of them failes we clean up
+    // everything and throw.
+    runTest("fs_noTestJs", fs_noTestJs, true).then((_) {
+      return runTest("fs_noTestJsDeps", fs_noTestJsDeps, true);
+    }).then((_) {
+      return runTest("fs_noTestDart", fs_noTestDart, true);
+    }).then((_) {
+      return runTest("fs_noTestSnapshot", fs_noTestSnapshot, true);
+    }).then((_) {
+      return runTest("fs_notUpToDate_snapshot", fs_notUpToDate_snapshot, true);
+    }).then((_) {
+      return runTest("fs_notUpToDate_dart", fs_notUpToDate_dart, true);
+    }).then((_) {
+      // This is the only test where all dependencies are present and the
+      // test.js file is newer than all the others. So we pass 'false' for
+      // shouldRun.
+      return runTest("fs_upToDate", fs_upToDate, false);
+    }).catchError((error) {
+      cleanup();
+      throw error;
+    }).then((_) {
+      cleanup();
+    });
   }
   // We need to wait some time to make sure that the files we 'touch' get a
   // bigger timestamp than the old ones
diff --git a/tests/utils/uri_test.dart b/tests/utils/uri_test.dart
index 2aa688e..a5f0c23 100644
--- a/tests/utils/uri_test.dart
+++ b/tests/utils/uri_test.dart
@@ -8,8 +8,8 @@
 import 'dart:uri';
 
 testUri(String uri, bool isAbsolute) {
-  Expect.equals(isAbsolute, Uri.parse(uri).isAbsolute());
-  Expect.equals(isAbsolute, new Uri(uri).isAbsolute());
+  Expect.equals(isAbsolute, Uri.parse(uri).isAbsolute);
+  Expect.equals(isAbsolute, new Uri(uri).isAbsolute);
   Expect.stringEquals(uri, Uri.parse(uri).toString());
   Expect.stringEquals(uri, new Uri(uri).toString());
 
diff --git a/tools/VERSION b/tools/VERSION
index 54a53be..05b0467 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 3
 BUILD 6
-PATCH 1
+PATCH 2
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 52e10ea..12d22c0 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -8,6 +8,7 @@
 
 import copy
 import json
+import monitored
 import os
 import re
 from htmlrenamer import html_interface_renames, renamed_html_members
@@ -17,7 +18,7 @@
 _json_path = os.path.join(_current_dir, '..', 'docs', 'docs.json')
 _dom_json = json.load(open(_json_path))
 
-_pure_interfaces = set([
+_pure_interfaces = monitored.Set('generator._pure_interfaces', [
     # TODO(sra): DOMStringMap should be a class implementing Map<String,String>.
     'DOMStringMap',
     'ElementTimeControl',
@@ -25,7 +26,6 @@
     'EventListener',
     'MediaQueryListListener',
     'MutationCallback',
-    'NodeSelector',
     'SVGExternalResourcesRequired',
     'SVGFilterPrimitiveStandardAttributes',
     'SVGFitToViewBox',
@@ -41,7 +41,8 @@
   return interface_name in _pure_interfaces
 
 
-_methods_with_named_formals = set([
+_methods_with_named_formals = monitored.Set(
+    'generator._methods_with_named_formals', [
   'DataView.getFloat32',
   'DataView.getFloat64',
   'DataView.getInt16',
@@ -65,16 +66,15 @@
 #
 # Renames for attributes that have names that are not legal Dart names.
 #
-_dart_attribute_renames = {
+_dart_attribute_renames = monitored.Dict('generator._dart_attribute_renames', {
     'default': 'defaultValue',
-    'final': 'finalValue',
-}
+})
 
 #
 # Interface version of the DOM needs to delegate typed array constructors to a
 # factory provider.
 #
-interface_factories = {
+interface_factories = monitored.Dict('generator.interface_factories', {
     'Float32Array': '_TypedArrayFactoryProvider',
     'Float64Array': '_TypedArrayFactoryProvider',
     'Int8Array': '_TypedArrayFactoryProvider',
@@ -84,19 +84,20 @@
     'Uint8ClampedArray': '_TypedArrayFactoryProvider',
     'Uint16Array': '_TypedArrayFactoryProvider',
     'Uint32Array': '_TypedArrayFactoryProvider',
-}
+})
 
 #
 # Custom native specs for the dart2js dom.
 #
-_dart2js_dom_custom_native_specs = {
+_dart2js_dom_custom_native_specs = monitored.Dict(
+      'generator._dart2js_dom_custom_native_specs', {
     # Decorate the singleton Console object, if present (workers do not have a
     # console).
     'Console': "=(typeof console == 'undefined' ? {} : console)",
 
     # DOMWindow aliased with global scope.
-    'DOMWindow': '@*DOMWindow',
-}
+    'Window': '@*DOMWindow',
+})
 
 def IsRegisteredType(type_name):
   return type_name in _idl_type_registry
@@ -419,7 +420,7 @@
 _serialize_SSV = Conversion('convertDartToNative_SerializedScriptValue',
                            'dynamic', 'dynamic')
 
-dart2js_conversions = {
+dart2js_conversions = monitored.Dict('generator.dart2js_conversions', {
     # Wrap non-local Windows.  We need to check EventTarget (the base type)
     # as well.  Note, there are no functions that take a non-local Window
     # as a parameter / setter.
@@ -432,11 +433,6 @@
       Conversion('_convertDartToNative_EventTarget', 'EventTarget',
                  'dynamic'),
 
-    'IDBKey get':
-      Conversion('_convertNativeToDart_IDBKey', 'dynamic', 'dynamic'),
-    'IDBKey set':
-      Conversion('_convertDartToNative_IDBKey', 'dynamic', 'dynamic'),
-
     'ImageData get':
       Conversion('_convertNativeToDart_ImageData', 'dynamic', 'ImageData'),
     'ImageData set':
@@ -447,7 +443,7 @@
     'Dictionary set':
       Conversion('convertDartToNative_Dictionary', 'Map', 'dynamic'),
 
-    'DOMString[] set':
+    'sequence<DOMString> set':
       Conversion('convertDartToNative_StringArray', 'List<String>', 'List'),
 
     'any set IDBObjectStore.add': _serialize_SSV,
@@ -476,7 +472,7 @@
     # IDBAny is problematic.  Some uses are just a union of other IDB types,
     # which need no conversion..  Others include data values which require
     # serialized script value processing.
-    'IDBAny get IDBCursorWithValue.value':
+    '* get IDBCursorWithValue.value':
       Conversion('_convertNativeToDart_IDBAny', 'dynamic', 'dynamic'),
 
     # This is problematic.  The result property of IDBRequest is used for
@@ -492,7 +488,7 @@
 
     # Should be either a DOMString, an Array of DOMStrings or null.
     'IDBAny get IDBObjectStore.keyPath': None,
-}
+})
 
 def FindConversion(idl_type, direction, interface, member):
   table = dart2js_conversions
@@ -513,7 +509,7 @@
 #   -TYPE:            add annotations only if there are no member annotations.
 #   TYPE:             add regardless of member annotations.
 
-dart2js_annotations = {
+dart2js_annotations = monitored.Dict('generator.dart2js_annotations', {
 
     'CanvasRenderingContext2D.createImageData': [
       "@Creates('ImageData|=Object')",
@@ -549,12 +545,6 @@
       "@Creates('DatabaseSync')",
     ],
 
-    # Cross-frame windows are EventTargets.
-    '-EventTarget': [
-      "@Creates('EventTarget|=Object')",
-      "@Returns('EventTarget|=Object')",
-    ],
-
     # To be in callback with the browser-created Event, we had to have called
     # addEventListener on the target, so we avoid
     'Event.currentTarget': [
@@ -627,10 +617,6 @@
       "@Returns('Request')",
       "@Creates('Request')",
     ],
-    '+IDBVersionChangeRequest': [
-      "@Returns('Request')",
-      "@Creates('Request')",
-    ],
 
     'MessageEvent.ports': ["@Creates('=List')"],
 
@@ -652,7 +638,7 @@
     'XMLHttpRequest.response': [
       "@Creates('ArrayBuffer|Blob|Document|=Object|=List|String|num')",
     ],
-}
+})
 
 _indexed_db_annotations = [
   "@SupportedBrowser(SupportedBrowser.CHROME)",
@@ -721,7 +707,7 @@
 # The table is indexed as:
 #   INTERFACE:     annotations to be added to the interface declaration
 #   INTERFACE.MEMBER: annotation to be added to the member declaration
-dart_annotations = {
+dart_annotations = monitored.Dict('generator.dart_annotations', {
   'ArrayBuffer': _all_but_ie9_annotations,
   'ArrayBufferView': _all_but_ie9_annotations,
   'Database': _web_sql_annotations,
@@ -733,8 +719,10 @@
     "@SupportedBrowser(SupportedBrowser.OPERA)",
     "@SupportedBrowser(SupportedBrowser.SAFARI)",
   ],
-  'DOMWindow.convertPointFromNodeToPage': _webkit_experimental_annotations,
-  'DOMWindow.convertPointFromPageToNode': _webkit_experimental_annotations,
+  'DOMFileSystem': _file_system_annotations,
+  'DOMFileSystemSync': _file_system_annotations,
+  'DOMWindow.webkitConvertPointFromNodeToPage': _webkit_experimental_annotations,
+  'DOMWindow.webkitConvertPointFromPageToNode': _webkit_experimental_annotations,
   'DOMWindow.indexedDB': _indexed_db_annotations,
   'DOMWindow.openDatabase': _web_sql_annotations,
   'DOMWindow.performance': _performance_annotations,
@@ -749,8 +737,6 @@
     "@SupportedBrowser(SupportedBrowser.CHROME, '25')",
     "@Experimental",
   ],
-  'FileSystem': _file_system_annotations,
-  'FileSystemSync': _file_system_annotations,
   'HashChangeEvent': [
     "@SupportedBrowser(SupportedBrowser.CHROME)",
     "@SupportedBrowser(SupportedBrowser.FIREFOX)",
@@ -791,11 +777,9 @@
   'IDBDatabase': _indexed_db_annotations,
   'LocalMediaStream': _rtc_annotations,
   'MediaStream': _rtc_annotations,
-  'MediaStreamEvents': _rtc_annotations,
   'MediaStreamEvent': _rtc_annotations,
   'MediaStreamTrack': _rtc_annotations,
   'MediaStreamTrackEvent': _rtc_annotations,
-  'MediaStreamTrackEvents': _rtc_annotations,
   'MutationObserver': [
     "@SupportedBrowser(SupportedBrowser.CHROME)",
     "@SupportedBrowser(SupportedBrowser.FIREFOX)",
@@ -837,7 +821,7 @@
   'SVGFEImageElement': _svg_annotations,
   'SVGFEMergeElement': _svg_annotations,
   'SVGFEMergeNodeElement': _svg_annotations,
-  'SVGFEMorphology': _svg_annotations,
+  'SVGFEMorphologyElement': _svg_annotations,
   'SVGFEOffsetElement': _svg_annotations,
   'SVGFEPointLightElement': _svg_annotations,
   'SVGFESpecularLightingElement': _svg_annotations,
@@ -866,7 +850,7 @@
     "@SupportedBrowser(SupportedBrowser.FIREFOX)",
     "@SupportedBrowser(SupportedBrowser.SAFARI)",
   ],
-}
+})
 
 def GetComments(library_name, interface_name, member_name=None):
   """ Finds all comments for the interface or member and returns a list. """
@@ -1306,7 +1290,7 @@
   return TypeData(clazz='Interface', item_type=item_type, is_typed_array=True)
 
 
-_idl_type_registry = {
+_idl_type_registry = monitored.Dict('generator._idl_type_registry', {
     'boolean': TypeData(clazz='Primitive', dart_type='bool', native_type='bool',
                         webcore_getter_name='hasAttribute',
                         webcore_setter_name='setBooleanAttribute'),
@@ -1339,9 +1323,6 @@
     # TODO(vsm): This won't actually work until we convert the Map to
     # a native JS Map for JS DOM.
     'Dictionary': TypeData(clazz='Primitive', dart_type='Map'),
-    # TODO(sra): Flags is really a dictionary: {create:bool, exclusive:bool}
-    # http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#the-flags-interface
-    'Flags': TypeData(clazz='Primitive', dart_type='Object'),
     'DOMTimeStamp': TypeData(clazz='Primitive', dart_type='int', native_type='unsigned long long'),
     'object': TypeData(clazz='Primitive', dart_type='Object', native_type='ScriptValue'),
     'ObjectArray': TypeData(clazz='Primitive', dart_type='List'),
@@ -1350,10 +1331,6 @@
     # the documentation, the user is made aware that only a limited subset of
     # serializable types are actually permitted.
     'SerializedScriptValue': TypeData(clazz='Primitive', dart_type='dynamic'),
-    # TODO(sra): Flags is really a dictionary: {create:bool, exclusive:bool}
-    # http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#the-flags-interface
-    'WebKitFlags': TypeData(clazz='Primitive', dart_type='Object'),
-
     'sequence': TypeData(clazz='Primitive', dart_type='List'),
     'void': TypeData(clazz='Primitive', dart_type='void'),
 
@@ -1368,7 +1345,6 @@
     'HTMLElement': TypeData(clazz='Interface', merged_into='Element',
         custom_to_dart=True),
     'IDBAny': TypeData(clazz='Interface', dart_type='dynamic', custom_to_native=True),
-    'IDBKey': TypeData(clazz='Interface', dart_type='dynamic', custom_to_native=True),
     'MutationRecordArray': TypeData(clazz='Interface',  # C++ pass by pointer.
         native_type='MutationRecordArray', dart_type='List<MutationRecord>'),
     'StyleSheet': TypeData(clazz='Interface', conversion_includes=['CSSStyleSheet']),
@@ -1413,8 +1389,6 @@
     'TextTrackCueList': TypeData(clazz='Interface', item_type='TextTrackCue'),
     'TextTrackList': TypeData(clazz='Interface', item_type='TextTrack'),
     'TouchList': TypeData(clazz='Interface', item_type='Touch'),
-    'WebKitAnimationList': TypeData(clazz='Interface',
-        item_type='WebKitAnimation', suppress_interface=True),
 
     'Float32Array': TypedArrayTypeData('double'),
     'Float64Array': TypedArrayTypeData('double'),
@@ -1443,7 +1417,7 @@
     'SVGTransform': TypeData(clazz='SVGTearOff'),
     'SVGTransformList': TypeData(clazz='SVGTearOff', item_type='SVGTransform',
         native_type='SVGTransformListPropertyTearOff'),
-}
+})
 
 _svg_supplemental_includes = [
     '"SVGAnimatedPropertyTearOff.h"',
diff --git a/tools/dom/scripts/htmleventgenerator.py b/tools/dom/scripts/htmleventgenerator.py
index a05dd1b..64063b3 100644
--- a/tools/dom/scripts/htmleventgenerator.py
+++ b/tools/dom/scripts/htmleventgenerator.py
@@ -6,6 +6,7 @@
 """This module provides functionality to generate dart:html event classes."""
 
 import logging
+import monitored
 from generator import GetAnnotationsAndComments, FormatAnnotationsAndComments
 
 _logger = logging.getLogger('dartgenerator')
@@ -14,176 +15,24 @@
 # We can automatically extract most event names by checking for
 # onEventName methods in the IDL but some events aren't listed so we need
 # to manually add them here so that they are easy for users to find.
-_html_manual_events = {
+_html_manual_events = monitored.Dict('htmleventgenerator._html_manual_events', {
   'Element': ['touchleave', 'touchenter', 'webkitTransitionEnd'],
   'Window': ['DOMContentLoaded']
-}
+})
 
 # These event names must be camel case when attaching event listeners
 # using addEventListener even though the onEventName properties in the DOM for
 # them are not camel case.
-_on_attribute_to_event_name_mapping = {
+_on_attribute_to_event_name_mapping = monitored.Dict(
+    'htmleventgenerator._on_attribute_to_event_name_mapping', {
   'webkitanimationend': 'webkitAnimationEnd',
   'webkitanimationiteration': 'webkitAnimationIteration',
   'webkitanimationstart': 'webkitAnimationStart',
   'webkitspeechchange': 'webkitSpeechChange',
   'webkittransitionend': 'webkitTransitionEnd',
-}
+})
 
-# Mapping from raw event names to the pretty camelCase event names exposed as
-# properties in dart:html.  If the DOM exposes a new event name, you will need
-# to add the lower case to camel case conversion for that event name here.
-_html_event_names = {
-  'DOMContentLoaded': 'contentLoaded',
-  'abort': 'abort',
-  'addstream': 'addStream',
-  'addtrack': 'addTrack',
-  'audioend': 'audioEnd',
-  'audioprocess': 'audioProcess',
-  'audiostart': 'audioStart',
-  'beforecopy': 'beforeCopy',
-  'beforecut': 'beforeCut',
-  'beforepaste': 'beforePaste',
-  'beforeunload': 'beforeUnload',
-  'blocked': 'blocked',
-  'blur': 'blur',
-  'cached': 'cached',
-  'canplay': 'canPlay',
-  'canplaythrough': 'canPlayThrough',
-  'change': 'change',
-  'chargingchange': 'chargingChange',
-  'chargingtimechange': 'chargingTimeChange',
-  'checking': 'checking',
-  'click': 'click',
-  'close': 'close',
-  'complete': 'complete',
-  'connect': 'connect',
-  'connecting': 'connecting',
-  'contextmenu': 'contextMenu',
-  'copy': 'copy',
-  'cuechange': 'cueChange',
-  'cut': 'cut',
-  'dblclick': 'doubleClick',
-  'devicemotion': 'deviceMotion',
-  'deviceorientation': 'deviceOrientation',
-  'dischargingtimechange': 'dischargingTimeChange',
-  'display': 'display',
-  'downloading': 'downloading',
-  'drag': 'drag',
-  'dragend': 'dragEnd',
-  'dragenter': 'dragEnter',
-  'dragleave': 'dragLeave',
-  'dragover': 'dragOver',
-  'dragstart': 'dragStart',
-  'drop': 'drop',
-  'durationchange': 'durationChange',
-  'emptied': 'emptied',
-  'end': 'end',
-  'ended': 'ended',
-  'enter': 'enter',
-  'error': 'error',
-  'exit': 'exit',
-  'focus': 'focus',
-  'hashchange': 'hashChange',
-  'icecandidate': 'iceCandidate',
-  'icechange': 'iceChange',
-  'input': 'input',
-  'invalid': 'invalid',
-  'keydown': 'keyDown',
-  'keypress': 'keyPress',
-  'keyup': 'keyUp',
-  'levelchange': 'levelChange',
-  'load': 'load',
-  'loadeddata': 'loadedData',
-  'loadedmetadata': 'loadedMetadata',
-  'loadend': 'loadEnd',
-  'loadstart': 'loadStart',
-  'message': 'message',
-  'mousedown': 'mouseDown',
-  'mousemove': 'mouseMove',
-  'mouseout': 'mouseOut',
-  'mouseover': 'mouseOver',
-  'mouseup': 'mouseUp',
-  'mousewheel': 'mouseWheel',
-  'mute': 'mute',
-  'negotiationneeded': 'negotiationNeeded',
-  'nomatch': 'noMatch',
-  'noupdate': 'noUpdate',
-  'obsolete': 'obsolete',
-  'offline': 'offline',
-  'online': 'online',
-  'open': 'open',
-  'pagehide': 'pageHide',
-  'pageshow': 'pageShow',
-  'paste': 'paste',
-  'pause': 'pause',
-  'play': 'play',
-  'playing': 'playing',
-  'popstate': 'popState',
-  'progress': 'progress',
-  'ratechange': 'rateChange',
-  'readystatechange': 'readyStateChange',
-  'removestream': 'removeStream',
-  'removetrack': 'removeTrack',
-  'reset': 'reset',
-  'resize': 'resize',
-  'result': 'result',
-  'resultdeleted': 'resultDeleted',
-  'scroll': 'scroll',
-  'search': 'search',
-  'seeked': 'seeked',
-  'seeking': 'seeking',
-  'select': 'select',
-  'selectionchange': 'selectionChange',
-  'selectstart': 'selectStart',
-  'show': 'show',
-  'soundend': 'soundEnd',
-  'soundstart': 'soundStart',
-  'speechend': 'speechEnd',
-  'speechstart': 'speechStart',
-  'stalled': 'stalled',
-  'start': 'start',
-  'statechange': 'stateChange',
-  'storage': 'storage',
-  'submit': 'submit',
-  'success': 'success',
-  'suspend': 'suspend',
-  'timeupdate': 'timeUpdate',
-  'touchcancel': 'touchCancel',
-  'touchend': 'touchEnd',
-  'touchenter': 'touchEnter',
-  'touchleave': 'touchLeave',
-  'touchmove': 'touchMove',
-  'touchstart': 'touchStart',
-  'unload': 'unload',
-  'upgradeneeded': 'upgradeNeeded',
-  'unmute': 'unmute',
-  'updateready': 'updateReady',
-  'versionchange': 'versionChange',
-  'volumechange': 'volumeChange',
-  'waiting': 'waiting',
-  'webkitAnimationEnd': 'animationEnd',
-  'webkitAnimationIteration': 'animationIteration',
-  'webkitAnimationStart': 'animationStart',
-  'webkitfullscreenchange': 'fullscreenChange',
-  'webkitfullscreenerror': 'fullscreenError',
-  'webkitkeyadded': 'keyAdded',
-  'webkitkeyerror': 'keyError',
-  'webkitkeymessage': 'keyMessage',
-  'webkitneedkey': 'needKey',
-  'webkitpointerlockchange': 'pointerLockChange',
-  'webkitpointerlockerror': 'pointerLockError',
-  'webkitSpeechChange': 'speechChange',
-  'webkitsourceclose': 'sourceClose',
-  'webkitsourceended': 'sourceEnded',
-  'webkitsourceopen': 'sourceOpen',
-  'webkitTransitionEnd': 'transitionEnd',
-  'write': 'write',
-  'writeend': 'writeEnd',
-  'writestart': 'writeStart'
-}
-
-_html_event_types = {
+_html_event_types = monitored.Dict('htmleventgenerator._html_event_types', {
   '*.abort': ('abort', 'Event'),
   '*.beforecopy': ('beforeCopy', 'Event'),
   '*.beforecut': ('beforeCut', 'Event'),
@@ -275,12 +124,10 @@
   'DOMApplicationCache.obsolete': ('obsolete', 'Event'),
   'DOMApplicationCache.progress': ('progress', 'Event'),
   'DOMApplicationCache.updateready': ('updateReady', 'Event'),
-  'Document.cuechange': ('cueChange', 'Event'),
   'Document.readystatechange': ('readyStateChange', 'Event'),
   'Document.selectionchange': ('selectionChange', 'Event'),
   'Document.webkitpointerlockchange': ('pointerLockChange', 'Event'),
   'Document.webkitpointerlockerror': ('pointerLockError', 'Event'),
-  'Element.cuechange': ('cueChange', 'Event'),
   'EventSource.open': ('open', 'Event'),
   'FileReader.abort': ('abort', 'ProgressEvent'),
   'FileReader.load': ('load', 'ProgressEvent'),
@@ -306,12 +153,10 @@
   'IDBOpenDBRequest.upgradeneeded': ('upgradeNeeded', 'VersionChangeEvent'),
   'IDBRequest.success': ('success', 'Event'),
   'IDBTransaction.complete': ('complete', 'Event'),
-  'IDBVersionChangeRequest.blocked': ('blocked', 'Event'),
-  'MediaController.play': ('play', 'Event'),
+  'MediaStream.addtrack': ('addTrack', 'Event'),
+  'MediaStream.removetrack': ('removeTrack', 'Event'),
   'MediaStreamTrack.mute': ('mute', 'Event'),
   'MediaStreamTrack.unmute': ('unmute', 'Event'),
-  'MediaStreamTrackList.addtrack': ('addTrack', 'MediaStreamTrackEvent'),
-  'MediaStreamTrackList.removetrack': ('removeTrack', 'MediaStreamTrackEvent'),
   'Notification.click': ('click', 'Event'),
   'Notification.close': ('close', 'Event'),
   'Notification.display': ('display', 'Event'),
@@ -319,15 +164,13 @@
   'RTCDataChannel.close': ('close', 'Event'),
   'RTCDataChannel.open': ('open', 'Event'),
   'RTCPeerConnection.addstream': ('addStream', 'MediaStreamEvent'),
-  'RTCPeerConnection.connecting': ('connecting', 'MediaStreamEvent'),
   'RTCPeerConnection.datachannel': ('dataChannel', 'RtcDataChannelEvent'),
   'RTCPeerConnection.icecandidate': ('iceCandidate', 'RtcIceCandidateEvent'),
   'RTCPeerConnection.icechange': ('iceChange', 'Event'),
+  'RTCPeerConnection.gatheringchange': ('gatheringChange', 'Event'),
   'RTCPeerConnection.negotiationneeded': ('negotiationNeeded', 'Event'),
-  'RTCPeerConnection.open': ('open', 'Event'),
   'RTCPeerConnection.removestream': ('removeStream', 'MediaStreamEvent'),
   'RTCPeerConnection.statechange': ('stateChange', 'Event'),
-  'ScriptProcessorNode.audioprocess': ('audioProcess', 'AudioProcessingEvent'),
   'SharedWorkerContext.connect': ('connect', 'Event'),
   'SpeechRecognition.audioend': ('audioEnd', 'Event'),
   'SpeechRecognition.audiostart': ('audioStart', 'Event'),
@@ -347,7 +190,6 @@
   'WebSocket.close': ('close', 'CloseEvent'),
   'WebSocket.open': ('open', 'Event'), # should be OpenEvent, but not exposed.
   'Window.DOMContentLoaded': ('contentLoaded', 'Event'),
-  'Window.cuechange': ('cueChange', 'Event'),
   'Window.devicemotion': ('deviceMotion', 'DeviceMotionEvent'),
   'Window.deviceorientation': ('deviceOrientation', 'DeviceOrientationEvent'),
   'Window.loadstart': ('loadStart', 'Event'),
@@ -367,7 +209,7 @@
   'XMLHttpRequestUpload.loadend': ('loadEnd', 'ProgressEvent'),
   'XMLHttpRequestUpload.loadstart': ('loadStart', 'ProgressEvent'),
   'XMLHttpRequestUpload.progress': ('progress', 'ProgressEvent'),
-}
+})
 
 # These classes require an explicit declaration for the "on" method even though
 # they don't declare any unique events, because the concrete class hierarchy
@@ -517,84 +359,3 @@
     _logger.warn('Cannot resolve event type for %s.%s' %
         (html_interface_name, dom_event_name))
     return None
-
-  def ProcessInterface(self, interface, html_interface_name, custom_events,
-                       events_implementation_emitter):
-    event_names = set([attr.id[2:] for attr in interface.attributes
-                  if attr.type.id == 'EventListener'])
-
-    # Document and DocumentFragment actually derive from Element, so omit
-    # any events which are duplicated with that.
-    if interface.id == 'Document' or interface.id == 'DocumentFragment':
-      element_interface = self._database.GetInterface('Element')
-      for attr in element_interface.attributes:
-        if attr.type.id == 'EventListener' and attr.id[2:] in event_names:
-          event_names.remove(attr.id[2:])
-
-    if not event_names and interface.id not in _html_explicit_event_classes:
-      return None
-
-    self._event_classes.add(interface.id)
-    events_class_name = html_interface_name + 'Events'
-    parent_events_class_name = self._GetParentEventsClassName(interface)
-
-    if not event_names:
-      return parent_events_class_name
-
-    template_file = 'impl_%s.darttemplate' % events_class_name
-    template = (self._template_loader.TryLoad(template_file) or
-        '\n'
-        '@DocsEditable\n'
-        '@deprecated\n'
-        'class $CLASSNAME extends $SUPER {\n'
-        '  @DocsEditable\n'
-        '  $CLASSNAME(EventTarget _ptr) : super(_ptr);\n'
-        '$!MEMBERS}\n')
-
-    # TODO(jacobr): specify the type of _ptr as EventTarget
-    implementation_events_members = events_implementation_emitter.Emit(
-        template,
-        CLASSNAME=events_class_name,
-        SUPER='%s' % parent_events_class_name)
-
-    dom_event_names = set()
-    for event in event_names:
-      dom_name = event
-      dom_name = _on_attribute_to_event_name_mapping.get(dom_name, dom_name)
-      dom_event_names.add(dom_name)
-    if html_interface_name in _html_manual_events:
-      dom_event_names.update(_html_manual_events[html_interface_name])
-    for dom_name in sorted(dom_event_names):
-      if dom_name not in _html_event_names:
-        _logger.warn('omitting %s event as there is no HTML name for it' % dom_name)
-        continue
-
-      html_name = _html_event_names[dom_name]
-      full_event_name = '%sEvents.%s' % (html_interface_name, html_name)
-      if not full_event_name in custom_events:
-        implementation_events_members.Emit(
-            "\n"
-            "  @DocsEditable\n"
-            "  EventListenerList get $NAME => this['$DOM_NAME'];\n",
-          NAME=html_name,
-            DOM_NAME=dom_name)
-
-    return events_class_name
-
-  # TODO(jacobr): this isn't quite right....
-  def _GetParentEventsClassName(self, interface):
-    # Ugly hack as we don't specify that Document and DocumentFragment inherit
-    # from Element in our IDL.
-    if interface.id == 'Document' or interface.id == 'DocumentFragment':
-      return 'ElementEvents'
-
-    parent_events_class_name = 'Events'
-    interfaces_with_events = set()
-    for parent in self._database.Hierarchy(interface):
-      if parent != interface and parent.id in self._event_classes:
-        parent_name = self._renamer.RenameInterface(parent)
-        parent_events_class_name = parent_name + 'Events'
-        interfaces_with_events.add(parent)
-    if len(interfaces_with_events) > 1:
-      raise Exception('Only one parent event class allowed ' + interface.id)
-    return parent_events_class_name
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 1dc400e..2057291 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -135,6 +135,9 @@
   'Element.querySelectorAll',
   'Element.removeAttribute',
   'Element.removeAttributeNS',
+  'Element.scrollIntoView',
+  'Element.scrollIntoViewIfNeeded',
+  'Element.setAttributeNS',
   'Element.setAttribute',
   'Element.setAttributeNS',
   'ElementTraversal.childElementCount',
@@ -198,7 +201,6 @@
     'DOMWindow.webkitResolveLocalFileSystemURL': 'resolveLocalFileSystemUrl',
     'DOMWindow.webkitRequestFileSystem': 'requestFileSystem',
     'DOMWindow.webkitResolveLocalFileSystemURL': 'resolveLocalFileSystemUrl',
-    'Element.scrollIntoViewIfNeeded': 'scrollIntoView',
     'Element.webkitCreateShadowRoot': 'createShadowRoot',
     'Element.webkitMatchesSelector' : 'matches',
     'Navigator.webkitGetUserMedia': '_getUserMedia',
@@ -337,7 +339,6 @@
     'Element.innerText',
     'Element.outerText',
     'Element.removeAttributeNode',
-    'Element.scrollIntoView',
     'Element.set:outerHTML',
     'Element.setAttributeNode',
     'Element.setAttributeNodeNS',
diff --git a/tools/dom/scripts/idlsync.py b/tools/dom/scripts/idlsync.py
index 7307845..1439399 100755
--- a/tools/dom/scripts/idlsync.py
+++ b/tools/dom/scripts/idlsync.py
@@ -14,22 +14,75 @@
 SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__))
 DART_PATH = os.path.abspath(os.path.join(SCRIPT_PATH, '..', '..', '..'))
 
-# Path to install latest IDL.
-IDL_PATH = os.path.join(DART_PATH, 'third_party', 'WebCore')
+# Dartium DEPS file with Chrome and WebKit revisions.
+DEPS = ('http://dart.googlecode.com/svn/branches/'
+        'bleeding_edge/deps/dartium.deps/DEPS')
 
 # Whitelist of files to keep.
 WHITELIST = [
     r'LICENSE(\S+)',
-    r'(\S+)\.idl']
+    r'(\S+)\.idl',
+    r'(\S+)\.json',
+    r'(\S+)\.py',
+    ]
 
-# README file to generate.
-README = os.path.join(IDL_PATH, 'README')
-
-# SVN URL to latest Dartium version of WebKit.
-DEPS = 'http://dart.googlecode.com/svn/branches/bleeding_edge/deps/dartium.deps/DEPS'
-URL_PATTERN = r'"dartium_webkit_trunk": "(\S+)",'
-REV_PATTERN = r'"dartium_webkit_revision": "(\d+)",'
+# WebKit / WebCore info.
+WEBKIT_URL_PATTERN = r'"dartium_webkit_trunk": "(\S+)",'
+WEBKIT_REV_PATTERN = r'"dartium_webkit_revision": "(\d+)",'
 WEBCORE_SUBPATH = 'Source/WebCore'
+LOCAL_WEBKIT_IDL_PATH = os.path.join(DART_PATH, 'third_party', 'WebCore')
+LOCAL_WEBKIT_README = os.path.join(LOCAL_WEBKIT_IDL_PATH, 'README')
+LOCAL_WEBKIT_README = """\
+This directory contains a copy of WebKit/WebCore IDL files.
+See the attached LICENSE-* files in this directory.
+
+Please do not modify the files here.  They are periodically copied
+using the script: $DART_ROOT/sdk/lib/html/scripts/%(script)s
+
+The current version corresponds to:
+URL: %(url)s
+Current revision: %(revision)s
+"""
+
+# Chrome info.
+CHROME_URL_PATTERN = r'"chromium_url": "(\S+)",'
+CHROME_REV_PATTERN = r'"chromium_revision": "(\d+)",'
+CHROME_IDL_SUBPATH = 'trunk/src/chrome/common/extensions/api'
+CHROME_TOOLS_SUBPATH = 'trunk/src/tools/json_schema_compiler'
+LOCAL_CHROME_IDL_PATH = os.path.join(DART_PATH, 'third_party', 'chrome', 'idl')
+LOCAL_CHROME_TOOLS_PATH = os.path.join(DART_PATH, 'third_party', 'chrome',
+                                       'tools')
+LOCAL_CHROME_README = """\
+This directory contains a copy of Chromium IDL and generation scripts
+used to generate Dart APIs for Chrome Apps.
+
+The original files are from:
+URL: %(url)s
+Current revision: %(revision)s
+
+Please see the corresponding LICENSE file at
+%(url)s/trunk/src/LICENSE.
+"""
+
+# Regular expressions corresponding to URL/revision patters in the
+# DEPS file.
+DEPS_PATTERNS = {
+    'webkit': (WEBKIT_URL_PATTERN, WEBKIT_REV_PATTERN),
+    'chrome': (CHROME_URL_PATTERN, CHROME_REV_PATTERN),
+    }
+
+# List of components to update.
+UPDATE_LIST = [
+    # (component, remote subpath, local path, local readme file)
+
+    # WebKit IDL.
+    ('webkit', WEBCORE_SUBPATH, LOCAL_WEBKIT_IDL_PATH, LOCAL_WEBKIT_README),
+    # Chrome IDL.
+    ('chrome', CHROME_IDL_SUBPATH, LOCAL_CHROME_IDL_PATH, LOCAL_CHROME_README),
+    # Chrome IDL compiler files.
+    ('chrome', CHROME_TOOLS_SUBPATH, LOCAL_CHROME_TOOLS_PATH,
+     LOCAL_CHROME_README),
+    ]
 
 
 def RunCommand(cmd):
@@ -45,30 +98,40 @@
     sys.exit(pipe.returncode)
 
 
-def GetWebkitSvnRevision():
+def GetDeps():
+  """Returns the DEPS file contents with pinned revision info."""
+  return RunCommand(['svn', 'cat', DEPS])
+
+
+def GetSvnRevision(deps, component):
   """Returns a tuple with the (dartium webkit repo, latest revision)."""
-  deps = RunCommand(['svn', 'cat', DEPS])
-  url = re.search(URL_PATTERN, deps).group(1)
-  revision = re.search(REV_PATTERN, deps).group(1)
+  url_pattern, rev_pattern = DEPS_PATTERNS[component]
+  url = re.search(url_pattern, deps).group(1)
+  revision = re.search(rev_pattern, deps).group(1)
   return (url, revision)
 
 
-def RefreshIDL(url, revision):
-  """Refreshes the IDL to specific WebKit url / revision."""
+def RefreshIDL(url, revision, remote_path, local_path):
+  """Refreshes refreshes files in the local_path to specific url /
+  revision / remote_path."""
   cwd = os.getcwd()
   try:
-    shutil.rmtree(IDL_PATH)
-    os.chdir(os.path.dirname(IDL_PATH))
-    RunCommand(['svn', 'export', '-r', revision, url + '/' + WEBCORE_SUBPATH])
+    if os.path.exists(local_path):
+      shutil.rmtree(local_path)
+    head, tail = os.path.split(local_path)
+    if not os.path.exists(head):
+      os.makedirs(head)
+    os.chdir(head)
+    RunCommand(['svn', 'export', '-r', revision, url + '/' + remote_path, tail])
   finally:
     os.chdir(cwd)
 
 
-def PruneExtraFiles():
+def PruneExtraFiles(local_path):
   """Removes all files that do not match the whitelist."""
   pattern = re.compile(reduce(lambda x,y: '%s|%s' % (x,y),
                               map(lambda z: '(%s)' % z, WHITELIST)))
-  for (root, dirs, files) in os.walk(IDL_PATH, topdown=False):
+  for (root, dirs, files) in os.walk(local_path, topdown=False):
     for f in files:
       if not pattern.match(f):
         os.remove(os.path.join(root, f))
@@ -78,41 +141,48 @@
         shutil.rmtree(dirpath)
 
 
-def ParseOptions():
-  parser = optparse.OptionParser()
-  parser.add_option('--revision', '-r', dest='revision',
-                    help='Revision to install', default=None)
-  args, _ = parser.parse_args()
-  return args.revision
-
-
-def GenerateReadme(url, revision):
-  readme = """This directory contains a copy of WebKit/WebCore IDL files.
-See the attached LICENSE-* files in this directory.
-
-Please do not modify the files here.  They are periodically copied
-using the script: $DART_ROOT/sdk/lib/html/scripts/%(script)s
-
-The current version corresponds to:
-URL: %(url)s
-Current revision: %(revision)s
-""" % {
+def GenerateReadme(local_path, template, url, revision):
+  readme = template % {
     'script': os.path.basename(__file__),
     'url': url,
     'revision': revision }
-  out = open(README, 'w')
+
+  readme_path = os.path.join(local_path, 'README')
+  out = open(readme_path, 'w')
   out.write(readme)
   out.close()
 
 
+def ParseOptions():
+  parser = optparse.OptionParser()
+  parser.add_option('--webkit-revision', '-w', dest='webkit_revision',
+                    help='WebKit IDL revision to install', default=None)
+  parser.add_option('--chrome-revision', '-c', dest='chrome_revision',
+                    help='Chrome IDL revision to install', default=None)
+  parser.add_option('--update', '-u', dest='update',
+                    help='IDL to update (webkit | chrome | all)',
+                    default='webkit')
+  args, _ = parser.parse_args()
+  update = {}
+  if args.update == 'all' or args.update == 'chrome':
+    update['chrome'] = args.chrome_revision
+  if args.update == 'all' or args.update == 'webkit':
+    update['webkit'] = args.webkit_revision
+  return update
+
+
 def main():
-  revision = ParseOptions()
-  url, latest = GetWebkitSvnRevision()
-  if not revision:
-    revision = latest
-  RefreshIDL(url, revision)
-  PruneExtraFiles()
-  GenerateReadme(url, revision)
+  deps = GetDeps()
+  update = ParseOptions()
+  for (component, remote_path, local_path, readme) in UPDATE_LIST:
+    if component in update.keys():
+      revision = update[component]
+      url, latest = GetSvnRevision(deps, component)
+      if revision is None:
+        revision = latest
+      RefreshIDL(url, revision, remote_path, local_path)
+      PruneExtraFiles(local_path)
+      GenerateReadme(local_path, readme, url, revision)
 
 
 if __name__ == '__main__':
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index d1f4542..2594b1e 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -7,11 +7,12 @@
 Dart:html APIs from the IDL database."""
 
 import emitter
+import monitored
 import os
 from generator import *
 from htmldartgenerator import *
 
-_js_custom_members = set([
+_js_custom_members = monitored.Set('systemhtml._js_custom_members', [
     'ArrayBuffer.slice',
     'AudioBufferSourceNode.start',
     'AudioBufferSourceNode.stop',
@@ -66,12 +67,10 @@
     'Window.location',
     'Window.open',
     'Window.requestAnimationFrame',
-    'Window.webkitCancelAnimationFrame',
-    'Window.webkitRequestAnimationFrame',
     'WorkerContext.indexedDB',
     ])
 
-_js_custom_constructors = set([
+_js_custom_constructors = monitored.Set('systemhtml._js_custom_constructors', [
     'AudioContext',
     'Blob',
     'MutationObserver',
@@ -118,7 +117,8 @@
     info.pure_dart_constructor = True
     return info
 
-_html_element_constructors = {
+_html_element_constructors = monitored.Dict(
+      'systemhtml._html_element_constructors', {
   'HTMLAnchorElement' :
     ElementConstructorInfo(tag='a', opt_params=[('DOMString', 'href')]),
   'HTMLAreaElement': 'area',
@@ -184,9 +184,10 @@
   'HTMLTrackElement': 'track',
   'HTMLUListElement': 'ul',
   'HTMLVideoElement': 'video'
-}
+})
 
-_svg_element_constructors = {
+_svg_element_constructors = monitored.Dict(
+      'systemhtml._svg_element_constructors', {
   'SVGAElement': 'a',
   'SVGAltGlyphElement': 'altGlyph',
   'SVGAnimateElement': 'animate',
@@ -252,7 +253,7 @@
   'SVGUseElement': 'use',
   'SVGViewElement': 'view',
   'SVGVKernElement': 'vkern',
-}
+})
 
 _element_constructors = {
   'html': _html_element_constructors,
@@ -517,13 +518,6 @@
 
     self._backend.EmitSupportCheck()
 
-    events_class_name = self._event_generator.ProcessInterface(
-        self._interface, interface_name,
-        self._backend.CustomJSMembers(),
-        implementation_emitter)
-    if events_class_name:
-      self._backend.EmitEventGetter(events_class_name)
-
     merged_interface = self._interface_type_info.merged_interface()
     if merged_interface:
       self._backend.AddMembers(self._database.GetInterface(merged_interface),
diff --git a/tools/dom/src/Isolates.dart b/tools/dom/src/Isolates.dart
index 3e4f507..467d998 100644
--- a/tools/dom/src/Isolates.dart
+++ b/tools/dom/src/Isolates.dart
@@ -99,12 +99,10 @@
     // TODO(vsm): Set this up set once, on the first call.
     var source = '$target-result';
     var result = null;
-    var listener = (Event e) {
+    window.on[source].first.then((Event e) {
       result = json.parse(_getPortSyncEventData(e));
-    };
-    window.on[source].add(listener);
+    });
     _dispatchEvent(target, [source, message]);
-    window.on[source].remove(listener);
     return result;
   }
 
@@ -159,7 +157,7 @@
 
   num _portId;
   Function _callback;
-  EventListener _listener;
+  StreamSubscription _portSubscription;
 
   ReceivePortSync() {
     if (_portIdCount == null) {
@@ -184,21 +182,20 @@
 
   void receive(callback(var message)) {
     _callback = callback;
-    if (_listener == null) {
-      _listener = (Event e) {
+    if (_portSubscription == null) {
+      _portSubscription = window.on[_listenerName].listen((Event e) {
         var data = json.parse(_getPortSyncEventData(e));
         var replyTo = data[0];
         var message = _deserialize(data[1]);
         var result = _callback(message);
         _dispatchEvent(replyTo, _serialize(result));
-      };
-      window.on[_listenerName].add(_listener);
+      });
     }
   }
 
   void close() {
     _portMap.remove(_portId);
-    if (_listener != null) window.on[_listenerName].remove(_listener);
+    if (_portSubscription != null) _portSubscription.cancel();
   }
 
   SendPortSync toSendPort() {
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index 3445f6b..825b6c8 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -75,9 +75,9 @@
 
 _callPortSync(num id, var message) {
   if (!_callPortInitialized) {
-    window.on['js-result'].add((event) {
+    window.on['js-result'].listen((event) {
       _callPortLastResult = json.parse(_getPortSyncEventData(event));
-    }, false);
+    });
     _callPortInitialized = true;
   }
   assert(_callPortLastResult == null);
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 47f53c1..5499b22 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -775,6 +775,44 @@
 $endif
   var xtag;
 
+  /**
+   * Scrolls this element into view.
+   *
+   * Only one of of the alignment options may be specified at a time.
+   *
+   * If no options are specified then this will attempt to scroll the minimum
+   * amount needed to bring the element into view.
+   *
+   * Note that alignCenter is currently only supported on WebKit platforms. If
+   * alignCenter is specified but not supported then this will fall back to
+   * alignTop.
+   *
+   * See also:
+   *
+   * * [scrollIntoView](http://docs.webplatform.org/wiki/dom/methods/scrollIntoView)
+   * * [scrollIntoViewIfNeeded](http://docs.webplatform.org/wiki/dom/methods/scrollIntoViewIfNeeded)
+   */
+  void scrollIntoView([ScrollAlignment alignment]) {
+    var hasScrollIntoViewIfNeeded = false;
+$if DART2JS
+    hasScrollIntoViewIfNeeded =
+        JS('bool', '!!(#.scrollIntoViewIfNeeded)', this);
+$endif
+    if (alignment == ScrollAlignment.TOP) {
+      this.$dom_scrollIntoView(true);
+    } else if (alignment == ScrollAlignment.BOTTOM) {
+      this.$dom_scrollIntoView(false);
+    } else if (hasScrollIntoViewIfNeeded) {
+      if (alignment == ScrollAlignment.CENTER) {
+        this.$dom_scrollIntoViewIfNeeded(true);
+      } else {
+        this.$dom_scrollIntoViewIfNeeded();
+      }
+    } else {
+      this.$dom_scrollIntoView();
+    }
+  }
+
 $if DART2JS
   @DomName('Element.mouseWheelEvent')
   static const EventStreamProvider<WheelEvent> mouseWheelEvent =
@@ -1064,3 +1102,20 @@
       document.$dom_createElement(tag);
 $endif
 }
+
+
+/**
+ * Options for Element.scrollIntoView.
+ */
+class ScrollAlignment {
+  final _value;
+  const ScrollAlignment._internal(this._value);
+  toString() => 'ScrollAlignment.$_value';
+
+  /// Attempt to align the element to the top of the scrollable area.
+  static const TOP = const ScrollAlignment._internal('TOP');
+  /// Attempt to center the element in the scrollable area.
+  static const CENTER = const ScrollAlignment._internal('CENTER');
+  /// Attempt to align the element to the bottom of the scrollable area.
+  static const BOTTOM = const ScrollAlignment._internal('BOTTOM');
+}
diff --git a/tools/dom/templates/html/impl/impl_EventTarget.darttemplate b/tools/dom/templates/html/impl/impl_EventTarget.darttemplate
index e0ff57e..bce2318 100644
--- a/tools/dom/templates/html/impl/impl_EventTarget.darttemplate
+++ b/tools/dom/templates/html/impl/impl_EventTarget.darttemplate
@@ -7,15 +7,38 @@
 /**
  * Base class that supports listening for and dispatching browser events.
  *
- * Events can either be accessed by string name (using the indexed getter) or by
- * getters exposed by subclasses. Use the getters exposed by subclasses when
- * possible for better compile-time type checks.
+ * Normally events are accessed via the Stream getter:
  *
- * Using an indexed getter:
- *     events['mouseover'].add((e) => print("Mouse over!"));
+ *     element.onMouseOver.listen((e) => print('Mouse over!'));
  *
- * Using a getter provided by a subclass:
- *     elementEvents.mouseOver.add((e) => print("Mouse over!"));
+ * To access bubbling events which are declared on one element, but may bubble
+ * up to another element type (common for MediaElement events):
+ *
+ *     MediaElement.pauseEvent.forTarget(document.body).listen(...);
+ *
+ * To useCapture on events:
+ *
+ *     Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
+ *
+ * Custom events can be declared as:
+ *
+ *    class DataGenerator {
+ *      static EventStreamProvider<Event> dataEvent =
+ *          new EventStreamProvider('data');
+ *    }
+ *
+ * Then listeners should access the event with:
+ *
+ *     DataGenerator.dataEvent.forTarget(element).listen(...);
+ *
+ * Custom events can also be accessed as:
+ *
+ *     element.on['some_event'].listen(...);
+ *
+ * This approach is generally discouraged as it loses the event typing and
+ * some DOM events may have multiple platform-dependent event names under the
+ * covers. By using the standard Stream getters you will get the platform
+ * specific event name automatically.
  */
 class Events {
   /* Raw event target. */
@@ -23,59 +46,24 @@
 
   Events(this._ptr);
 
-  EventListenerList operator [](String type) {
-    return new EventListenerList(_ptr, type);
-  }
-}
-
-/**
- * Supports adding, removing, and dispatching events for a specific event type.
- */
-class EventListenerList {
-
-  final EventTarget _ptr;
-  final String _type;
-
-  EventListenerList(this._ptr, this._type);
-
-  // TODO(jacobr): implement equals.
-
-  EventListenerList add(EventListener listener,
-      [bool useCapture = false]) {
-    _add(listener, useCapture);
-    return this;
-  }
-
-  EventListenerList remove(EventListener listener,
-      [bool useCapture = false]) {
-    _remove(listener, useCapture);
-    return this;
-  }
-
-  bool dispatch(Event evt) {
-    return _ptr.dispatchEvent(evt);
-  }
-
-  void _add(EventListener listener, bool useCapture) {
-    _ptr.$dom_addEventListener(_type, listener, useCapture);
-  }
-
-  void _remove(EventListener listener, bool useCapture) {
-    _ptr.$dom_removeEventListener(_type, listener, useCapture);
+  Stream operator [](String type) {
+    return new _EventStream(_ptr, type, false);
   }
 }
 
 /**
  * Base class for all browser objects that support events.
  *
- * Use the [on] property to add, remove, and dispatch events (rather than
- * [$dom_addEventListener], [$dom_dispatchEvent], and
- * [$dom_removeEventListener]) for compile-time type checks and a more concise
- * API.
+ * Use the [on] property to add, and remove events (rather than
+ * [$dom_addEventListener] and [$dom_removeEventListener]
+ * for compile-time type checks and a more concise API.
  */
 $(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
 
-  @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
+  /**
+   * This is an ease-of-use accessor for event streams which should only be
+   * used when an explicit accessor is not available.
+   */
   Events get on => new Events(this);
 $!MEMBERS
 }
diff --git a/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate b/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
index b8ee68a..ec7d9b3 100644
--- a/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
+++ b/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
@@ -54,7 +54,7 @@
    * the current transaction.
    */
   @DomName('IDBObjectStore.openCursor')
-  Stream<Cursor> openCursor({key, KeyRange range, String direction,
+  Stream<CursorWithValue> openCursor({key, KeyRange range, String direction,
       bool autoAdvance}) {
     var key_OR_range = null;
     if (key != null) {
@@ -86,7 +86,7 @@
     // TODO: need to guarantee that the controller provides the values
     // immediately as waiting until the next tick will cause the transaction to
     // close.
-    var controller = new StreamController<Cursor>();
+    var controller = new StreamController();
 
     request.onError.listen((e) {
       //TODO: Report stacktrace once issue 4061 is resolved.
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index edbe56e..8a73b91 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -33,17 +33,17 @@
       },
 
       'Dart_ia32_Base': {
-        'cflags': [ '-m32', ],
+        'cflags': [ '-m32', '-msse2' ],
         'ldflags': [ '-m32', ],
       },
 
       'Dart_x64_Base': {
-        'cflags': [ '-m64', ],
+        'cflags': [ '-m64', '-msse2' ],
         'ldflags': [ '-m64', ],
       },
 
       'Dart_simarm_Base': {
-        'cflags': [ '-O3', '-m32', ],
+        'cflags': [ '-O3', '-m32', '-msse2' ],
         'ldflags': [ '-m32', ],
       },
 
@@ -57,7 +57,7 @@
       },
 
       'Dart_simmips_Base': {
-        'cflags': [ '-O3', '-m32', ],
+        'cflags': [ '-O3', '-m32', '-msse2' ],
         'ldflags': [ '-m32', ],
       },
 
diff --git a/tools/testing/dart/http_server.dart b/tools/testing/dart/http_server.dart
index 84a5b77..06b87da 100644
--- a/tools/testing/dart/http_server.dart
+++ b/tools/testing/dart/http_server.dart
@@ -6,6 +6,7 @@
 
 import 'dart:io';
 import 'dart:isolate';
+import 'dart:uri';
 import 'test_suite.dart';  // For TestUtils.
 // TODO(efortuna): Rewrite to not use the args library and simply take an
 // expected number of arguments, so test.dart doesn't rely on the args library?
@@ -28,6 +29,8 @@
   parser.addFlag('help', abbr: 'h', negatable: false,
       help: 'Print this usage information.');
   parser.addOption('package-root', help: 'The package root to use.');
+  parser.addOption('network', help: 'The network interface to use.',
+      defaultsTo: '127.0.0.1');
   var args = parser.parse(new Options().arguments);
   if (args['help']) {
     print(parser.getUsage());
@@ -41,11 +44,12 @@
         .canonicalize()
         .toNativePath();
     TestingServerRunner._packageRootDir = new Path(args['package-root']);
-    TestingServerRunner.startHttpServer('127.0.0.1',
+    var network = args['network'];
+    TestingServerRunner.startHttpServer(network,
         port: int.parse(args['port']));
     print('Server listening on port '
           '${TestingServerRunner.serverList[0].port}.');
-    TestingServerRunner.startHttpServer('127.0.0.1',
+    TestingServerRunner.startHttpServer(network,
         allowedPort: TestingServerRunner.serverList[0].port, port:
         int.parse(args['crossOriginPort']));
     print(
@@ -93,10 +97,14 @@
       file.exists().then((exists) {
         if (exists) {
           if (allowedPort != -1) {
-            // Allow loading from localhost:$allowedPort in browsers.
-            resp.headers.set("Access-Control-Allow-Origin",
-                "http://127.0.0.1:$allowedPort");
-            resp.headers.set('Access-Control-Allow-Credentials', 'true');
+            if (request.headers.value('Origin') != null) {
+              var origin = new Uri(request.headers.value('Origin'));
+              // Allow loading from http://*:$allowedPort in browsers.
+              var allowedOrigin =
+                  '${origin.scheme}://${origin.domain}:${allowedPort}';
+              resp.headers.set("Access-Control-Allow-Origin", allowedOrigin);
+              resp.headers.set('Access-Control-Allow-Credentials', 'true');
+            }
           } else {
             // No allowedPort specified. Allow from anywhere (but cross-origin
             // requests *with credentials* will fail because you can't use "*").
@@ -111,16 +119,14 @@
           }
           file.openInputStream().pipe(resp.outputStream);
         } else {
-          resp.statusCode = HttpStatus.NOT_FOUND;
-          try {
-            resp.outputStream.close();
-          } catch (e) {
-            if (e is StreamException) {
-              print('Test http_server error closing the response stream: $e');
+          var directory = new Directory.fromPath(path);
+          directory.exists().then((exists) {
+            if (!exists) {
+              sendNotFound(resp);
             } else {
-              throw e;
+              sendDirectoryListing(directory, request, resp);
             }
-          }
+          });
         }
       });
     };
@@ -136,7 +142,84 @@
     serverList.add(httpServer);
   }
 
+  static void sendNotFound(HttpResponse response) {
+    response.statusCode = HttpStatus.NOT_FOUND;
+    try {
+      response.outputStream.close();
+    } catch (e) {
+      if (e is StreamException) {
+        print('Test http_server error closing the response stream: $e');
+      } else {
+        throw e;
+      }
+    }
+  }
+
+  /**
+   * Sends a simple listing of all the files and sub-directories within
+   * directory.
+   *
+   * This is intended to make it easier to browse tests when manually running
+   * tests against this test server.
+   */
+  static void sendDirectoryListing(Directory directory, HttpRequest request,
+      HttpResponse response) {
+    response.headers.set('Content-Type', 'text/html');
+    var header = '''<!DOCTYPE html>
+    <html>
+    <head>
+      <title>${request.path}</title>
+    </head>
+    <body>
+      <code>
+        <div>${request.path}</div>
+        <hr/>
+        <ul>''';
+    var footer = '''
+        </ul>
+      </code>
+    </body>
+    </html>''';
+
+    var entries = [];
+
+    directory.list()
+      ..onFile = (filepath) {
+        var filename = new Path(filepath).filename;
+        entries.add(new _Entry(filename, filename));
+      }
+      ..onDir = (dirpath) {
+        var filename = new Path(dirpath).filename;
+        entries.add(new _Entry(filename, '$filename/'));
+      }
+      ..onDone = (_) {
+        var requestPath = new Path.raw(request.path);
+        entries.sort();
+
+        response.outputStream.writeString(header);
+        for (var entry in entries) {
+          response.outputStream.writeString(
+              '<li><a href="${requestPath.append(entry.name)}">'
+              '${entry.displayName}</a></li>');
+        }
+        response.outputStream.writeString(footer);
+        response.outputStream.close();
+      };
+  }
+
   static terminateHttpServers() {
     for (var server in serverList) server.close();
   }
 }
+
+// Helper class for displaying directory listings.
+class _Entry {
+  final String name;
+  final String displayName;
+
+  _Entry(this.name, this.displayName);
+
+  int compareTo(_Entry other) {
+    return name.compareTo(other.name);
+  }
+}
diff --git a/utils/apidoc/apidoc.dart b/utils/apidoc/apidoc.dart
index 7cd8b7f..4caf0d5 100644
--- a/utils/apidoc/apidoc.dart
+++ b/utils/apidoc/apidoc.dart
@@ -274,7 +274,7 @@
         includeMdnMemberComment(member), super.getMemberComment(member));
   }
 
-  doc.DocComment _mergeDocs(MdnComment mdnComment,
+  doc.DocComment _mergeDocs(doc.MdnComment mdnComment,
                             doc.DocComment fileComment) {
     // Otherwise, prefer comment from the (possibly generated) Dart file.
     if (fileComment != null) return fileComment;
@@ -321,11 +321,21 @@
     }
   }
 
+  doc.MdnComment lookupMdnComment(Mirror mirror) { 
+    if (mirror is TypeMirror) {
+      return includeMdnTypeComment(mirror);
+    } else if (mirror is MemberMirror) {
+      return includeMdnMemberComment(mirror);
+    } else {
+      return null;
+    }
+  }
+
   /**
    * Gets the MDN-scraped docs for [type], or `null` if this type isn't
    * scraped from MDN.
    */
-  MdnComment includeMdnTypeComment(TypeMirror type) {
+  doc.MdnComment includeMdnTypeComment(TypeMirror type) {
     if (_mdnTypeNamesToSkip.contains(type.simpleName)) {
       print('Skipping MDN type ${type.simpleName}');
       return null;
@@ -359,7 +369,7 @@
     if (mdnType['summary'].trim().isEmpty) return null;
 
     // Remember which MDN page we're using so we can attribute it.
-    return new MdnComment(mdnType['summary'], mdnType['srcUrl']);
+    return new doc.MdnComment(mdnType['summary'], mdnType['srcUrl']);
   }
 
   /**
@@ -412,7 +422,7 @@
     if (mdnMember['help'].trim().isEmpty) return null;
 
     // Remember which MDN page we're using so we can attribute it.
-    return new MdnComment(mdnMember['help'], mdnType['srcUrl']);
+    return new doc.MdnComment(mdnMember['help'], mdnType['srcUrl']);
   }
 
   /**
@@ -430,27 +440,3 @@
     return a(memberUrl(member), memberName);
   }
 }
-
-class MdnComment implements doc.DocComment {
-  final String mdnComment;
-  final String mdnUrl;
-
-  MdnComment(String this.mdnComment, String this.mdnUrl);
-
-  String get text => mdnComment;
-
-  ClassMirror get inheritedFrom => null;
-
-  String get html {
-    // Wrap the mdn comment so we can highlight it and so we handle MDN scraped
-    // content that lacks a top-level block tag.
-   return '''
-        <div class="mdn">
-        $mdnComment
-        <div class="mdn-note"><a href="$mdnUrl">from MDN</a></div>
-        </div>
-        ''';
-  }
-
-  String toString() => mdnComment;
-}
diff --git a/utils/pub/command_lish.dart b/utils/pub/command_lish.dart
index d3a2cb4..f2e5f05 100644
--- a/utils/pub/command_lish.dart
+++ b/utils/pub/command_lish.dart
@@ -146,15 +146,15 @@
       return listDir(rootDir, recursive: true).then((entries) {
         return entries
             .where(fileExists) // Skip directories.
-            .map((entry) => relativeTo(entry, rootDir));
+            .map((entry) => path.relative(entry, from: rootDir));
       });
     }).then((files) => files.where(_shouldPublish).toList());
   }
 
   /// Returns `true` if [file] should be published.
   bool _shouldPublish(String file) {
-    if (_BLACKLISTED_FILES.contains(basename(file))) return false;
-    return !splitPath(file).any(_BLACKLISTED_DIRS.contains);
+    if (_BLACKLISTED_FILES.contains(path.basename(file))) return false;
+    return !path.split(file).any(_BLACKLISTED_DIRS.contains);
   }
 
   /// Returns the value associated with [key] in [map]. Throws a user-friendly
diff --git a/utils/pub/entrypoint.dart b/utils/pub/entrypoint.dart
index 6d7ffe0..f778bbb 100644
--- a/utils/pub/entrypoint.dart
+++ b/utils/pub/entrypoint.dart
@@ -5,6 +5,9 @@
 library entrypoint;
 
 import 'dart:async';
+
+import '../../pkg/path/lib/path.dart' as path;
+
 import 'io.dart';
 import 'lock_file.dart';
 import 'log.dart' as log;
@@ -49,8 +52,8 @@
         cache = cache;
 
   // TODO(rnystrom): Make this path configurable.
-  /// The path to this "packages" directory.
-  String get path => join(root.dir, 'packages');
+  /// The path to the entrypoint's "packages" directory.
+  String get packagesDir => join(root.dir, 'packages');
 
   /// Ensures that the package identified by [id] is installed to the directory.
   /// Returns the resolved [PackageId].
@@ -67,9 +70,9 @@
     var pendingOrCompleted = _installs[id];
     if (pendingOrCompleted != null) return pendingOrCompleted;
 
-    var packageDir = join(path, id.name);
+    var packageDir = join(packagesDir, id.name);
     var future = defer(() {
-      ensureDir(dirname(packageDir));
+      ensureDir(path.dirname(packageDir));
       if (!dirExists(packageDir)) return;
 
       // TODO(nweiz): figure out when to actually delete the directory, and when
@@ -127,7 +130,7 @@
   /// Removes the old packages directory, installs all dependencies listed in
   /// [packageVersions], and writes a [LockFile].
   Future _installDependencies(List<PackageId> packageVersions) {
-    return cleanDir(path).then((_) {
+    return cleanDir(packagesDir).then((_) {
       return Future.wait(packageVersions.map((id) {
         if (id.isRoot) return new Future.immediate(id);
         return install(id);
@@ -224,10 +227,10 @@
   /// allow a package to import its own files using `package:`.
   Future _installSelfReference(_) {
     return defer(() {
-      var linkPath = join(path, root.name);
+      var linkPath = join(packagesDir, root.name);
       // Create the symlink if it doesn't exist.
       if (entryExists(linkPath)) return;
-      ensureDir(path);
+      ensureDir(packagesDir);
       return createPackageSymlink(root.name, root.dir, linkPath,
           isSelfLink: true);
     });
@@ -275,7 +278,7 @@
   Future<List<String>> _listDirWithoutPackages(dir) {
     return listDir(dir).then((files) {
       return Future.wait(files.map((file) {
-        if (basename(file) == 'packages') return new Future.immediate([]);
+        if (path.basename(file) == 'packages') return new Future.immediate([]);
         return defer(() {
           if (!dirExists(file)) return [];
           return _listDirWithoutPackages(file);
@@ -293,7 +296,7 @@
     return defer(() {
       var to = join(dir, 'packages');
       if (entryExists(to)) return;
-      return createSymlink(path, to);
+      return createSymlink(packagesDir, to);
     });
   }
 }
diff --git a/utils/pub/io.dart b/utils/pub/io.dart
index 0eab87a..c439384 100644
--- a/utils/pub/io.dart
+++ b/utils/pub/io.dart
@@ -33,27 +33,13 @@
       parts[6], parts[7]);
 }
 
-/// Gets the basename, the file name without any leading directory path, for
-/// [file], which can either be a [String], [File], or [Directory].
-String basename(file) => path.basename(_getPath(file));
-
-/// Gets the the leading directory path for [file], which can either be a
-/// [String], [File], or [Directory].
-String dirname(file) => path.dirname(_getPath(file));
-
-/// Splits [entry] into its individual components.
-List<String> splitPath(entry) => path.split(_getPath(entry));
-
 /// Returns whether or not [entry] is nested somewhere within [dir]. This just
 /// performs a path comparison; it doesn't look at the actual filesystem.
-bool isBeneath(entry, dir) {
-  var relative = relativeTo(entry, dir);
-  return !path.isAbsolute(relative) && splitPath(relative)[0] != '..';
+bool isBeneath(String entry, String dir) {
+  var relative = path.relative(entry, from: dir);
+  return !path.isAbsolute(relative) && path.split(relative)[0] != '..';
 }
 
-/// Returns the path to [target] from [base].
-String relativeTo(target, base) => path.relative(target, from: base);
-
 /// Determines if [path], which can be a [String] file path, a [File], or a
 /// [Directory] exists on the file system.
 bool entryExists(path) => fileExists(path) || dirExists(path);
@@ -93,8 +79,7 @@
   return file..writeAsStringSync(contents);
 }
 
-/// Deletes [file], which can be a [String] or a [File]. Returns a [Future]
-/// that completes when the deletion is done.
+/// Deletes [file], which can be a [String] or a [File].
 File deleteFile(file) => _getFile(file)..delete();
 
 /// Creates [file] (which can either be a [String] or a [File]), and writes
@@ -128,16 +113,16 @@
 /// Creates a directory [dir].
 Directory createDir(dir) => _getDirectory(dir)..createSync();
 
-/// Ensures that [path] and all its parent directories exist. If they don't
+/// Ensures that [dirPath] and all its parent directories exist. If they don't
 /// exist, creates them.
-Directory ensureDir(path) {
-  path = _getPath(path);
+Directory ensureDir(dirPath) {
+  dirPath = _getPath(dirPath);
 
-  log.fine("Ensuring directory $path exists.");
-  var dir = new Directory(path);
-  if (path == '.' || dirExists(path)) return dir;
+  log.fine("Ensuring directory $dirPath exists.");
+  var dir = new Directory(dirPath);
+  if (dirPath == '.' || dirExists(dirPath)) return dir;
 
-  ensureDir(dirname(path));
+  ensureDir(path.dirname(dirPath));
 
   try {
     createDir(dir);
@@ -155,12 +140,12 @@
 
 /// Creates a temp directory whose name will be based on [dir] with a unique
 /// 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.
-Directory createTempDir([dir = '']) {
+/// created in a platform-dependent temporary location. Returns the path of the
+/// created directory.
+String createTempDir([dir = '']) {
   var tempDir = _getDirectory(dir).createTempSync();
   log.io("Created temp directory ${tempDir.path}");
-  return tempDir;
+  return tempDir.path;
 }
 
 /// Asynchronously recursively deletes [dir], which can be a [String] or a
@@ -218,8 +203,8 @@
     var children = [];
     lister.onError = (error) => completer.completeError(error, stackTrace);
     lister.onDir = (file) {
-      if (!includeHiddenFiles && basename(file).startsWith('.')) return;
-      file = join(dir, basename(file));
+      if (!includeHiddenFiles && path.basename(file).startsWith('.')) return;
+      file = join(dir, path.basename(file));
       contents.add(file);
       // TODO(nweiz): don't manually recurse once issue 7358 is fixed. Note that
       // once we remove the manual recursion, we'll need to explicitly filter
@@ -230,8 +215,8 @@
     };
 
     lister.onFile = (file) {
-      if (!includeHiddenFiles && basename(file).startsWith('.')) return;
-      contents.add(join(dir, basename(file)));
+      if (!includeHiddenFiles && path.basename(file).startsWith('.')) return;
+      contents.add(join(dir, path.basename(file)));
     };
 
     return completer.future.then((contents) {
@@ -315,7 +300,7 @@
   from = _getPath(from);
   to = _getPath(to);
 
-  log.fine("Create symlink $from -> $to.");
+  log.fine("Creating symlink ($to is a symlink to $from)");
 
   var command = 'ln';
   var args = ['-s', from, to];
@@ -361,13 +346,6 @@
   });
 }
 
-/// Given [entry] which may be a [String], [File], or [Directory] relative to
-/// the current working directory, returns its full canonicalized path.
-String getFullPath(entry) => path.absolute(_getPath(entry));
-
-/// Returns whether or not [entry] is an absolute path.
-bool isAbsolute(entry) => path.isAbsolute(_getPath(entry));
-
 /// Resolves [target] relative to the location of pub.dart.
 String relativeToPub(String target) {
   var scriptPath = new File(new Options().script).fullPathSync();
@@ -375,10 +353,11 @@
   // Walk up until we hit the "util(s)" directory. This lets us figure out where
   // we are if this function is called from pub.dart, or one of the tests,
   // which also live under "utils", or from the SDK where pub is in "util".
-  var utilDir = dirname(scriptPath);
-  while (basename(utilDir) != 'utils' && basename(utilDir) != 'util') {
-    if (basename(utilDir) == '') throw 'Could not find path to pub.';
-    utilDir = dirname(utilDir);
+  var utilDir = path.dirname(scriptPath);
+  while (path.basename(utilDir) != 'utils' &&
+         path.basename(utilDir) != 'util') {
+    if (path.basename(utilDir) == '') throw 'Could not find path to pub.';
+    utilDir = path.dirname(utilDir);
   }
 
   return path.normalize(join(utilDir, 'pub', target));
@@ -728,7 +707,7 @@
 Future withTempDir(Future fn(String path)) {
   return defer(() {
     var tempDir = createTempDir();
-    return fn(tempDir.path).whenComplete(() {
+    return fn(tempDir).whenComplete(() {
       return deleteDir(tempDir);
     });
   });
@@ -835,13 +814,13 @@
   var controller = new StreamController<List<int>>();
 
   if (baseDir == null) baseDir = path.current;
-  baseDir = getFullPath(baseDir);
+  baseDir = path.absolute(baseDir);
   contents = contents.map((entry) {
-    entry = getFullPath(entry);
+    entry = path.absolute(_getPath(entry));
     if (!isBeneath(entry, baseDir)) {
       throw 'Entry $entry is not inside $baseDir.';
     }
-    return relativeTo(entry, baseDir);
+    return path.relative(entry, from: baseDir);
   }).toList();
 
   if (Platform.operatingSystem != "windows") {
diff --git a/utils/pub/oauth2.dart b/utils/pub/oauth2.dart
index 9711452..3ea33cc 100644
--- a/utils/pub/oauth2.dart
+++ b/utils/pub/oauth2.dart
@@ -10,6 +10,8 @@
 
 // TODO(nweiz): Make this a "package:" URL, or something nicer than this.
 import '../../pkg/oauth2/lib/oauth2.dart';
+import '../../pkg/path/lib/path.dart' as path;
+
 import 'http.dart';
 import 'io.dart';
 import 'log.dart' as log;
@@ -138,9 +140,9 @@
 void _saveCredentials(SystemCache cache, Credentials credentials) {
   log.fine('Saving OAuth2 credentials.');
   _credentials = credentials;
-  var path = _credentialsFile(cache);
-  ensureDir(dirname(path));
-  writeTextFile(path, credentials.toJson(), dontLogContents: true);
+  var credentialsPath = _credentialsFile(cache);
+  ensureDir(path.dirname(credentialsPath));
+  writeTextFile(credentialsPath, credentials.toJson(), dontLogContents: true);
 }
 
 /// The path to the file in which the user's OAuth2 credentials are stored.
diff --git a/utils/pub/package.dart b/utils/pub/package.dart
index 5485b65..dd988cb 100644
--- a/utils/pub/package.dart
+++ b/utils/pub/package.dart
@@ -5,6 +5,9 @@
 library package;
 
 import 'dart:async';
+
+import '../../pkg/path/lib/path.dart' as path;
+
 import 'io.dart';
 import 'pubspec.dart';
 import 'source.dart';
@@ -21,7 +24,7 @@
   /// The name of the package.
   String get name {
     if (pubspec.name != null) return pubspec.name;
-    if (dir != null) return basename(dir);
+    if (dir != null) return path.basename(dir);
     return null;
   }
 
diff --git a/utils/pub/path_source.dart b/utils/pub/path_source.dart
new file mode 100644
index 0000000..123a308
--- /dev/null
+++ b/utils/pub/path_source.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.
+
+library path_source;
+
+import 'dart:async';
+import 'dart:io';
+
+import '../../pkg/path/lib/path.dart' as path;
+
+import 'io.dart';
+import 'package.dart';
+import 'pubspec.dart';
+import 'version.dart';
+import 'source.dart';
+import 'utils.dart';
+
+// TODO(rnystrom): Support relative paths. (See comment in _validatePath().)
+/// A package [Source] that installs packages from a given local file path.
+class PathSource extends Source {
+  final name = 'path';
+  final shouldCache = false;
+
+  Future<Pubspec> describe(PackageId id) {
+    return defer(() {
+      _validatePath(id.name, id.description);
+      return new Pubspec.load(id.name, id.description, systemCache.sources);
+    });
+  }
+
+  Future<bool> install(PackageId id, String path) {
+    return defer(() {
+      try {
+        _validatePath(id.name, id.description);
+      } on FormatException catch(err) {
+        return false;
+      }
+      return createPackageSymlink(id.name, id.description, path);
+    }).then((_) => true);
+  }
+
+  void validateDescription(description, {bool fromLockFile: false}) {
+    if (description is! String) {
+      throw new FormatException("The description must be a path string.");
+    }
+  }
+
+  /// Ensures that [dir] is a valid path. It must be an absolute path that
+  /// points to an existing directory. Throws a [FormatException] if the path
+  /// is invalid.
+  void _validatePath(String name, String dir) {
+    // Relative paths are not (currently) allowed because the user would expect
+    // them to be relative to the pubspec where the dependency appears. That in
+    // turn means that two pubspecs in different locations with the same
+    // relative path dependency could refer to two different packages. That
+    // violates pub's rule that a description should uniquely identify a
+    // package.
+    //
+    // At some point, we may want to loosen this, but it will mean tracking
+    // where a given PackageId appeared.
+    if (!path.isAbsolute(dir)) {
+      throw new FormatException(
+          "Path dependency for package '$name' must be an absolute path. "
+          "Was '$dir'.");
+    }
+
+    if (fileExists(dir)) {
+      throw new FormatException(
+          "Path dependency for package '$name' must refer to a "
+          "directory, not a file. Was '$dir'.");
+    }
+
+    if (!dirExists(dir)) {
+      throw new FormatException("Could not find package '$name' at '$dir'.");
+    }
+  }
+}
\ No newline at end of file
diff --git a/utils/pub/pub.dart b/utils/pub/pub.dart
index 302420f..a837163 100644
--- a/utils/pub/pub.dart
+++ b/utils/pub/pub.dart
@@ -235,12 +235,19 @@
     handleError(error, trace) {
       // This is basically the top-level exception handler so that we don't
       // spew a stack trace on our users.
-      var message = error.toString();
+      var message;
 
-      // TODO(rnystrom): The default exception implementation class puts
-      // "Exception:" in the output, so strip that off.
-      if (message.startsWith("Exception: ")) {
-        message = message.substring("Exception: ".length);
+      try {
+        // Most exception types have a "message" property. We prefer this since
+        // it skips the "Exception:", "HttpException:", etc. prefix that calling
+        // toString() adds. But, alas, "message" isn't actually defined in the
+        // base Exception type so there's no easy way to know if it's available
+        // short of a giant pile of type tests for each known exception type.
+        //
+        // So just try it. If it throws, default to toString().
+        message = error.message;
+      } on NoSuchMethodError catch (_) {
+        message = error.toString();
       }
 
       log.error(message);
@@ -271,7 +278,7 @@
           '${path.current}.';
       } else if (e is PubspecHasNoNameException && e.name == null) {
         e = 'pubspec.yaml is missing the required "name" field (e.g. "name: '
-          '${basename(path.current)}").';
+          '${path.basename(path.current)}").';
       }
 
       handleError(e, asyncError.stackTrace);
diff --git a/utils/pub/source.dart b/utils/pub/source.dart
index 777c1a0..30fd5eb 100644
--- a/utils/pub/source.dart
+++ b/utils/pub/source.dart
@@ -5,6 +5,9 @@
 library source;
 
 import 'dart:async';
+
+import '../../pkg/path/lib/path.dart' as path;
+
 import 'io.dart';
 import 'package.dart';
 import 'pubspec.dart';
@@ -105,15 +108,51 @@
   ///
   /// By default, this uses [systemCacheDirectory] and [install].
   Future<Package> installToSystemCache(PackageId id) {
-    var path;
+    var packageDir;
     return systemCacheDirectory(id).then((p) {
-      path = p;
-      if (dirExists(path)) return true;
-      ensureDir(dirname(path));
-      return install(id, path);
+      packageDir = p;
+
+      // See if it's already cached.
+      if (!dirExists(packageDir)) return false;
+
+      return _isCachedPackageCorrupted(packageDir).then((isCorrupted) {
+        if (!isCorrupted) return true;
+
+        // Busted, so wipe out the package and reinstall.
+        return deleteDir(packageDir).then((_) => false);
+      });
+    }).then((isInstalled) {
+      if (isInstalled) return true;
+      ensureDir(path.dirname(packageDir));
+      return install(id, packageDir);
     }).then((found) {
       if (!found) throw 'Package $id not found.';
-      return new Package.load(id.name, path, systemCache.sources);
+      return new Package.load(id.name, packageDir, systemCache.sources);
+    });
+  }
+
+  /// Since pub generates symlinks that point into the system cache (in
+  /// particular, targeting the "lib" directories of cached packages), it's
+  /// possible to accidentally break cached packages if something traverses
+  /// that symlink.
+  ///
+  /// This tries to determine if the cached package at [packageDir] has been
+  /// corrupted. The heuristics are it is corrupted if any of the following are
+  /// true:
+  ///
+  ///   * It has an empty "lib" directory.
+  ///   * It has no pubspec.
+  Future<bool> _isCachedPackageCorrupted(String packageDir) {
+    return defer(() {
+      if (!fileExists(join(packageDir, "pubspec.yaml"))) return true;
+
+      var libDir = join(packageDir, "lib");
+      if (dirExists(libDir)) {
+        return listDir(libDir).then((contents) => contents.length == 0);
+      }
+
+      // If we got here, it's OK.
+      return false;
     });
   }
 
diff --git a/utils/pub/system_cache.dart b/utils/pub/system_cache.dart
index 13e6b8d..377ac17 100644
--- a/utils/pub/system_cache.dart
+++ b/utils/pub/system_cache.dart
@@ -13,6 +13,7 @@
 import 'io.dart' as io show createTempDir;
 import 'log.dart' as log;
 import 'package.dart';
+import 'path_source.dart';
 import 'pubspec.dart';
 import 'sdk_source.dart';
 import 'source.dart';
@@ -46,9 +47,10 @@
   /// Creates a system cache and registers the standard set of sources.
   factory SystemCache.withSources(String rootDir) {
     var cache = new SystemCache(rootDir);
-    cache.register(new SdkSource());
     cache.register(new GitSource());
     cache.register(new HostedSource());
+    cache.register(new PathSource());
+    cache.register(new SdkSource());
     cache.sources.setDefault('hosted');
     return cache;
   }
@@ -101,7 +103,7 @@
   /// 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.
-  Directory createTempDir() {
+  String createTempDir() {
     var temp = ensureDir(tempDir);
     return io.createTempDir(join(temp, 'dir'));
   }
diff --git a/utils/pub/validator/compiled_dartdoc.dart b/utils/pub/validator/compiled_dartdoc.dart
index e5a7353..20f69be 100644
--- a/utils/pub/validator/compiled_dartdoc.dart
+++ b/utils/pub/validator/compiled_dartdoc.dart
@@ -22,8 +22,8 @@
   Future validate() {
     return listDir(entrypoint.root.dir, recursive: true).then((entries) {
       for (var entry in entries) {
-        if (basename(entry) != "nav.json") return false;
-        var dir = dirname(entry);
+        if (path.basename(entry) != "nav.json") return false;
+        var dir = path.dirname(entry);
 
         // Look for tell-tale Dartdoc output files all in the same directory.
         var files = [
diff --git a/utils/pub/validator/dependency.dart b/utils/pub/validator/dependency.dart
index a848c54..de02738 100644
--- a/utils/pub/validator/dependency.dart
+++ b/utils/pub/validator/dependency.dart
@@ -10,6 +10,7 @@
 import '../hosted_source.dart';
 import '../http.dart';
 import '../package.dart';
+import '../path_source.dart';
 import '../utils.dart';
 import '../validator.dart';
 import '../version.dart';
@@ -62,7 +63,13 @@
         }
       }
 
-      warnings.add('Don\'t depend on "${ref.name}" from the ${ref.source.name} '
+      // Path sources are errors. Other sources are just warnings.
+      var messages = warnings;
+      if (ref.source is PathSource) {
+        messages = errors;
+      }
+
+      messages.add('Don\'t depend on "${ref.name}" from the ${ref.source.name} '
               'source. Use the hosted source instead. For example:\n'
           '\n'
           'dependencies:\n'
diff --git a/utils/pub/validator/directory.dart b/utils/pub/validator/directory.dart
index 6ab932c..1d1c2b8 100644
--- a/utils/pub/validator/directory.dart
+++ b/utils/pub/validator/directory.dart
@@ -6,6 +6,8 @@
 
 import 'dart:async';
 
+import '../../../pkg/path/lib/path.dart' as path;
+
 import '../entrypoint.dart';
 import '../io.dart';
 import '../utils.dart';
@@ -23,7 +25,7 @@
       for (var dir in dirs) {
         if (!dirExists(dir)) continue;
 
-        dir = basename(dir);
+        dir = path.basename(dir);
         if (_PLURAL_NAMES.contains(dir)) {
           // Cut off the "s"
           var singularName = dir.substring(0, dir.length - 1);
diff --git a/utils/pub/validator/lib.dart b/utils/pub/validator/lib.dart
index 7346223e..c72d309 100644
--- a/utils/pub/validator/lib.dart
+++ b/utils/pub/validator/lib.dart
@@ -7,6 +7,8 @@
 import 'dart:async';
 import 'dart:io';
 
+import '../../../pkg/path/lib/path.dart' as path;
+
 import '../entrypoint.dart';
 import '../io.dart';
 import '../system_cache.dart';
@@ -31,7 +33,7 @@
       }
 
       return listDir(libDir).then((files) {
-        files = files.map((file) => relativeTo(file, libDir)).toList();
+        files = files.map((file) => path.relative(file, from: libDir)).toList();
         if (files.isEmpty) {
           errors.add('You must have a non-empty "lib" directory.\n'
               "Without that, users cannot import any code from your package.");
diff --git a/utils/pub/validator/license.dart b/utils/pub/validator/license.dart
index 8c32548..63b9aa8 100644
--- a/utils/pub/validator/license.dart
+++ b/utils/pub/validator/license.dart
@@ -6,6 +6,8 @@
 
 import 'dart:async';
 
+import '../../../pkg/path/lib/path.dart' as path;
+
 import '../entrypoint.dart';
 import '../io.dart';
 import '../system_cache.dart';
@@ -20,7 +22,7 @@
     return listDir(entrypoint.root.dir).then((files) {
       var licenseLike = new RegExp(
           r"^([a-zA-Z0-9]+[-_])?(LICENSE|COPYING)(\..*)?$");
-      if (files.map(basename).any(licenseLike.hasMatch)) return;
+      if (files.map(path.basename).any(licenseLike.hasMatch)) return;
 
       errors.add(
           "You must have a COPYING or LICENSE file in the root directory.\n"
diff --git a/utils/pub/validator/name.dart b/utils/pub/validator/name.dart
index 0386089..6a8cd91 100644
--- a/utils/pub/validator/name.dart
+++ b/utils/pub/validator/name.dart
@@ -8,6 +8,7 @@
 import 'dart:io';
 
 import '../../../pkg/path/lib/path.dart' as path;
+
 import '../entrypoint.dart';
 import '../io.dart';
 import '../utils.dart';
@@ -53,8 +54,8 @@
       return listDir(libDir, recursive: true);
     }).then((files) {
       return files
-          .map((file) => relativeTo(file, dirname(libDir)))
-          .where((file) => !splitPath(file).contains("src") &&
+          .map((file) => path.relative(file, from: path.dirname(libDir)))
+          .where((file) => !path.split(file).contains("src") &&
                            path.extension(file) == '.dart')
           .toList();
     });
diff --git a/utils/tests/pub/install/hosted/repair_cache_test.dart b/utils/tests/pub/install/hosted/repair_cache_test.dart
new file mode 100644
index 0000000..8f2f79f
--- /dev/null
+++ b/utils/tests/pub/install/hosted/repair_cache_test.dart
@@ -0,0 +1,64 @@
+// 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 pub_tests;
+
+import '../../../../../pkg/path/lib/path.dart' as path;
+
+import '../../../../pub/io.dart';
+import '../../test_pub.dart';
+
+main() {
+  initConfig();
+  integration('re-installs a package if it has an empty "lib" directory', () {
+
+    servePackages([package("foo", "1.2.3")]);
+
+    // Set up a cache with a broken foo package.
+    dir(cachePath, [
+      dir('hosted', [
+        async(port.then((p) => dir('localhost%58$p', [
+          dir("foo-1.2.3", [
+            libPubspec("foo", "1.2.3"),
+            // Note: empty "lib" directory.
+            dir("lib", [])
+          ])
+        ])))
+      ])
+    ]).scheduleCreate();
+
+    appDir([dependency("foo", "1.2.3")]).scheduleCreate();
+
+    schedulePub(args: ['install'],
+        output: new RegExp("Dependencies installed!\$"));
+
+    cacheDir({"foo": "1.2.3"}).scheduleValidate();
+    packagesDir({"foo": "1.2.3"}).scheduleValidate();
+  });
+
+  integration('re-installs a package if it has no pubspec', () {
+
+    servePackages([package("foo", "1.2.3")]);
+
+    // Set up a cache with a broken foo package.
+    dir(cachePath, [
+      dir('hosted', [
+        async(port.then((p) => dir('localhost%58$p', [
+          dir("foo-1.2.3", [
+            libDir("foo")
+            // Note: no pubspec.
+          ])
+        ])))
+      ])
+    ]).scheduleCreate();
+
+    appDir([dependency("foo", "1.2.3")]).scheduleCreate();
+
+    schedulePub(args: ['install'],
+        output: new RegExp("Dependencies installed!\$"));
+
+    cacheDir({"foo": "1.2.3"}).scheduleValidate();
+    packagesDir({"foo": "1.2.3"}).scheduleValidate();
+  });
+}
diff --git a/utils/tests/pub/install/path/absolute_path_test.dart b/utils/tests/pub/install/path/absolute_path_test.dart
new file mode 100644
index 0000000..cef0a76
--- /dev/null
+++ b/utils/tests/pub/install/path/absolute_path_test.dart
@@ -0,0 +1,46 @@
+// 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 '../../../../../pkg/path/lib/path.dart' as path;
+
+import '../../test_pub.dart';
+
+main() {
+  initConfig();
+  integration('path dependency with absolute path', () {
+    dir('foo', [
+      libDir('foo'),
+      libPubspec('foo', '0.0.1')
+    ]).scheduleCreate();
+
+    dir(appPath, [
+      pubspec({
+        "name": "myapp",
+        "dependencies": {
+          "foo": {"path": path.join(sandboxDir, "foo")}
+        }
+      })
+    ]).scheduleCreate();
+
+    schedulePub(args: ["install"],
+        output: new RegExp(r"Dependencies installed!$"));
+
+    dir(packagesPath, [
+      dir("foo", [
+        file("foo.dart", 'main() => "foo";')
+      ])
+    ]).scheduleValidate();
+
+    // Move the packages directory and ensure the symlink still works. That
+    // will validate that we actually created an absolute symlink.
+    dir("moved").scheduleCreate();
+    scheduleRename(packagesPath, "moved/packages");
+
+    dir("moved/packages", [
+      dir("foo", [
+        file("foo.dart", 'main() => "foo";')
+      ])
+    ]).scheduleValidate();
+  });
+}
\ No newline at end of file
diff --git a/utils/tests/pub/install/path/no_pubspec_test.dart b/utils/tests/pub/install/path/no_pubspec_test.dart
new file mode 100644
index 0000000..92f54fd
--- /dev/null
+++ b/utils/tests/pub/install/path/no_pubspec_test.dart
@@ -0,0 +1,31 @@
+// 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 'dart:io';
+
+import '../../../../../pkg/path/lib/path.dart' as path;
+
+import '../../test_pub.dart';
+
+main() {
+  initConfig();
+  integration('path dependency to non-package directory', () {
+    // Make an empty directory.
+    dir('foo').scheduleCreate();
+    var fooPath = path.join(sandboxDir, "foo");
+
+    dir(appPath, [
+      pubspec({
+        "name": "myapp",
+        "dependencies": {
+          "foo": {"path": fooPath}
+        }
+      })
+    ]).scheduleCreate();
+
+    schedulePub(args: ['install'],
+        error: new RegExp('Package "foo" doesn\'t have a pubspec.yaml file.'),
+        exitCode: 1);
+  });
+}
\ No newline at end of file
diff --git a/utils/tests/pub/install/path/nonexistent_dir_test.dart b/utils/tests/pub/install/path/nonexistent_dir_test.dart
new file mode 100644
index 0000000..4a129f4
--- /dev/null
+++ b/utils/tests/pub/install/path/nonexistent_dir_test.dart
@@ -0,0 +1,37 @@
+// 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 'dart:io';
+
+import '../../../../../pkg/path/lib/path.dart' as path;
+
+import '../../../../pub/exit_codes.dart' as exit_codes;
+import '../../test_pub.dart';
+
+main() {
+  initConfig();
+  integration('path dependency to non-existent directory', () {
+    var badPath = path.join(sandboxDir, "bad_path");
+
+    dir(appPath, [
+      pubspec({
+        "name": "myapp",
+        "dependencies": {
+          "foo": {"path": badPath}
+        }
+      })
+    ]).scheduleCreate();
+
+    // TODO(rnystrom): The "\" in a Windows path gets treated like a regex
+    // character, so hack escape. A better fix is to use a literal string
+    // instead of a RegExp to validate, but that requires us to move the
+    // stack traces out of the stderr when we invoke pub. See also: #4706.
+    var escapePath = badPath.replaceAll(r"\", r"\\");
+
+    schedulePub(args: ['install'],
+        error:
+            new RegExp("Could not find package 'foo' at '$escapePath'."),
+        exitCode: exit_codes.DATA);
+  });
+}
\ No newline at end of file
diff --git a/utils/tests/pub/install/path/path_is_file_test.dart b/utils/tests/pub/install/path/path_is_file_test.dart
new file mode 100644
index 0000000..8717b49
--- /dev/null
+++ b/utils/tests/pub/install/path/path_is_file_test.dart
@@ -0,0 +1,41 @@
+// 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 '../../../../../pkg/path/lib/path.dart' as path;
+
+import '../../../../pub/exit_codes.dart' as exit_codes;
+import '../../test_pub.dart';
+
+main() {
+  initConfig();
+  integration('path dependency when path is a file', () {
+    dir('foo', [
+      libDir('foo'),
+      libPubspec('foo', '0.0.1')
+    ]).scheduleCreate();
+
+    file('dummy.txt', '').scheduleCreate();
+    var dummyPath = path.join(sandboxDir, 'dummy.txt');
+
+    dir(appPath, [
+      pubspec({
+        "name": "myapp",
+        "dependencies": {
+          "foo": {"path": dummyPath}
+        }
+      })
+    ]).scheduleCreate();
+
+    // TODO(rnystrom): The "\" in a Windows path gets treated like a regex
+    // character, so hack escape. A better fix is to use a literal string
+    // instead of a RegExp to validate, but that requires us to move the
+    // stack traces out of the stderr when we invoke pub. See also: #4706.
+    var escapePath = dummyPath.replaceAll(r"\", r"\\");
+
+    schedulePub(args: ['install'],
+        error: new RegExp("Path dependency for package 'foo' must refer to a "
+                          "directory, not a file. Was '$escapePath'."),
+        exitCode: exit_codes.DATA);
+  });
+}
\ No newline at end of file
diff --git a/utils/tests/pub/install/path/relative_path_test.dart b/utils/tests/pub/install/path/relative_path_test.dart
new file mode 100644
index 0000000..56fe28a
--- /dev/null
+++ b/utils/tests/pub/install/path/relative_path_test.dart
@@ -0,0 +1,25 @@
+// 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 '../../../../pub/exit_codes.dart' as exit_codes;
+import '../../test_pub.dart';
+
+main() {
+  initConfig();
+  integration('path dependencies cannot use relative paths', () {
+    dir(appPath, [
+      pubspec({
+        "name": "myapp",
+        "dependencies": {
+          "foo": {"path": "../foo"}
+        }
+      })
+    ]).scheduleCreate();
+
+    schedulePub(args: ['install'],
+        error: new RegExp("Path dependency for package 'foo' must be an "
+                          "absolute path. Was '../foo'."),
+        exitCode: exit_codes.DATA);
+  });
+}
\ No newline at end of file
diff --git a/utils/tests/pub/pub.status b/utils/tests/pub/pub.status
index 2605568..254abd7 100644
--- a/utils/tests/pub/pub.status
+++ b/utils/tests/pub/pub.status
@@ -15,4 +15,4 @@
 *: Skip
 
 [ $system == windows ]
-io_test: Timeout # Issue 7505
+io_test: Fail # Issue 7505
diff --git a/utils/tests/pub/test_pub.dart b/utils/tests/pub/test_pub.dart
index b84a7aa..cae3a80 100644
--- a/utils/tests/pub/test_pub.dart
+++ b/utils/tests/pub/test_pub.dart
@@ -31,6 +31,7 @@
 import '../../pub/hosted_source.dart';
 import '../../pub/http.dart';
 import '../../pub/io.dart';
+import '../../pub/path_source.dart';
 import '../../pub/sdk_source.dart';
 import '../../pub/system_cache.dart';
 import '../../pub/utils.dart';
@@ -404,6 +405,9 @@
       case "hosted":
         source = new HostedSource();
         break;
+      case "path":
+        source = new PathSource();
+        break;
       case "sdk":
         source = new SdkSource();
         break;
@@ -423,10 +427,14 @@
   switch (sourceName) {
   case "git":
     var url = description is String ? description : description['url'];
-    return basename(url.replaceFirst(new RegExp(r"(\.git)?/?$"), ""));
+    // TODO(rnystrom): Using path.basename on a URL is hacky. If we add URL
+    // support to pkg/path, should use an explicit builder for that.
+    return path.basename(url.replaceFirst(new RegExp(r"(\.git)?/?$"), ""));
   case "hosted":
     if (description is String) return description;
     return description['name'];
+  case "path":
+    return path.basename(description);
   case "sdk":
     return description;
   default:
@@ -434,6 +442,10 @@
   }
 }
 
+/// The full path to the created sandbox directory for an integration test.
+String get sandboxDir => _sandboxDir;
+String _sandboxDir;
+
 /// The path of the package cache directory used for tests. Relative to the
 /// sandbox directory.
 final String cachePath = "cache";
@@ -452,7 +464,7 @@
 
 /// The type for callbacks that will be fired during [schedulePub]. Takes the
 /// sandbox directory as a parameter.
-typedef Future _ScheduledEvent(Directory parentDir);
+typedef Future _ScheduledEvent(String parentDir);
 
 /// The list of events that are scheduled to run as part of the test case.
 List<_ScheduledEvent> _scheduled;
@@ -488,27 +500,32 @@
       file('version', '0.1.2.3')
     ]).scheduleCreate();
 
+    _sandboxDir = createTempDir();
+
     // Schedule the test.
     body();
 
     // 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 sandboxDir = createTempDir();
-    return timeout(_runScheduled(sandboxDir, _scheduled),
+    return timeout(_runScheduled(_scheduled),
           _TIMEOUT, 'waiting for a test to complete').catchError((e) {
-      return _runScheduled(sandboxDir, _scheduledOnException).then((_) {
+      return _runScheduled(_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(sandboxDir, _scheduledCleanup).then((_) {
+      return _runScheduled(_scheduledCleanup).then((_) {
         _scheduled = null;
         _scheduledCleanup = null;
         _scheduledOnException = null;
-        if (sandboxDir != null) return deleteDir(sandboxDir);
+        if (_sandboxDir != null) {
+          var dir = _sandboxDir;
+          _sandboxDir = null;
+          return deleteDir(dir);
+        }
       });
     }).then((_) {
       // If we got here, the test completed successfully so tell unittest so.
@@ -527,9 +544,17 @@
 /// tests.
 String get testDirectory {
   var dir = new Options().script;
-  while (basename(dir) != 'pub') dir = dirname(dir);
+  while (path.basename(dir) != 'pub') dir = path.dirname(dir);
 
-  return getFullPath(dir);
+  return path.absolute(dir);
+}
+
+/// Schedules renaming (moving) the directory at [from] to [to], both of which
+/// are assumed to be relative to [sandboxDir].
+void scheduleRename(String from, String to) {
+  _schedule((sandboxDir) {
+    return renameDir(join(sandboxDir, from), join(sandboxDir, to));
+  });
 }
 
 /// Schedules a call to the Pub command-line utility. Runs Pub with [args] and
@@ -602,12 +627,14 @@
   pub.writeLine("y");
 }
 
-
 /// Calls [fn] with appropriately modified arguments to run a pub process. [fn]
 /// should have the same signature as [startProcess], except that the returned
 /// [Future] may have a type other than [Process].
 Future _doPub(Function fn, sandboxDir, List args, Future<Uri> tokenEndpoint) {
-  String pathInSandbox(path) => join(getFullPath(sandboxDir), path);
+  String pathInSandbox(String relPath) {
+    return join(path.absolute(sandboxDir), relPath);
+  }
+
   return defer(() {
     ensureDir(pathInSandbox(appPath));
     return Future.wait([
@@ -677,7 +704,7 @@
   });
 }
 
-Future _runScheduled(Directory parentDir, List<_ScheduledEvent> scheduled) {
+Future _runScheduled(List<_ScheduledEvent> scheduled) {
   if (scheduled == null) return new Future.immediate(null);
   var iterator = scheduled.iterator;
 
@@ -688,7 +715,7 @@
       return new Future.immediate(null);
     }
 
-    var future = iterator.current(parentDir);
+    var future = iterator.current(_sandboxDir);
     if (future != null) {
       return future.then(runNextEvent);
     } else {
@@ -815,7 +842,7 @@
   /// Schedules the directory to be validated after Pub is run with
   /// [schedulePub]. The directory will be validated relative to the sandbox
   /// directory.
-  void scheduleValidate() => _schedule((parentDir) => validate(parentDir.path));
+  void scheduleValidate() => _schedule((parentDir) => validate(parentDir));
 
   /// Asserts that the name of the descriptor is a [String] and returns it.
   String get _stringName {
@@ -1169,7 +1196,7 @@
 typedef Validator ValidatorCreator(Entrypoint entrypoint);
 
 /// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled
-/// Future that contains the erros and warnings produced by that validator.
+/// Future that contains the errors and warnings produced by that validator.
 Future<Pair<List<String>, List<String>>> schedulePackageValidation(
     ValidatorCreator fn) {
   return _scheduleValue((sandboxDir) {
diff --git a/utils/tests/pub/validator_test.dart b/utils/tests/pub/validator_test.dart
index b11d90f..b64f131 100644
--- a/utils/tests/pub/validator_test.dart
+++ b/utils/tests/pub/validator_test.dart
@@ -10,9 +10,10 @@
 import 'dart:math' as math;
 
 import 'test_pub.dart';
-import '../../../pkg/unittest/lib/unittest.dart';
 import '../../../pkg/http/lib/http.dart' as http;
 import '../../../pkg/http/lib/testing.dart';
+import '../../../pkg/path/lib/path.dart' as path;
+import '../../../pkg/unittest/lib/unittest.dart';
 import '../../pub/entrypoint.dart';
 import '../../pub/io.dart';
 import '../../pub/validator.dart';
@@ -38,6 +39,16 @@
   expectLater(schedulePackageValidation(fn), pairOf(isEmpty, isNot(isEmpty)));
 }
 
+expectDependencyValidationError(String error) {
+  expectLater(schedulePackageValidation(dependency),
+      pairOf(someElement(contains(error)), isEmpty));
+}
+
+expectDependencyValidationWarning(String warning) {
+  expectLater(schedulePackageValidation(dependency),
+      pairOf(isEmpty, someElement(contains(warning))));
+}
+
 Validator compiledDartdoc(Entrypoint entrypoint) =>
   new CompiledDartdocValidator(entrypoint);
 
@@ -66,7 +77,31 @@
 
 void scheduleNormalPackage() => normalPackage.scheduleCreate();
 
+/// Sets up a test package with dependency [dep] and mocks a server with
+/// [hostedVersions] of the package available.
+setUpDependency(Map dep, {List<String> hostedVersions}) {
+  useMockClient(new MockClient((request) {
+    expect(request.method, equals("GET"));
+    expect(request.url.path, equals("/packages/foo.json"));
+
+    if (hostedVersions == null) {
+      return new Future.immediate(new http.Response("not found", 404));
+    } else {
+      return new Future.immediate(new http.Response(json.stringify({
+        "name": "foo",
+        "uploaders": ["nweiz@google.com"],
+        "versions": hostedVersions
+      }), 200));
+    }
+  }));
+
+  dir(appPath, [
+    libPubspec("test_pkg", "1.0.0", deps: [dep])
+  ]).scheduleCreate();
+}
+
 main() {
+  initConfig();
   group('should consider a package valid if it', () {
     setUp(scheduleNormalPackage);
 
@@ -326,124 +361,88 @@
       expectValidationError(lib);
     });
 
-    group('has a dependency with a non-hosted source', () {
-      group('where a hosted version of that dependency exists', () {
-        integration("and should suggest the hosted package's primary "
-            "version", () {
-          useMockClient(new MockClient((request) {
-            expect(request.method, equals("GET"));
-            expect(request.url.path, equals("/packages/foo.json"));
-
-            return new Future.immediate(new http.Response(json.stringify({
-              "name": "foo",
-              "uploaders": ["nweiz@google.com"],
-              "versions": ["3.0.0-pre", "2.0.0", "1.0.0"]
-            }), 200));
-          }));
-
-          dir(appPath, [
-            libPubspec("test_pkg", "1.0.0", deps: [
-              {'git': 'git://github.com/dart-lang/foo'}
-            ])
-          ]).scheduleCreate();
-
-          expectLater(schedulePackageValidation(dependency),
-              pairOf(isEmpty, someElement(contains(
-                  '  foo: ">=2.0.0 <3.0.0"'))));
+    group('has a git dependency', () {
+      group('where a hosted version exists', () {
+        integration("and should suggest the hosted primary version", () {
+          setUpDependency({'git': 'git://github.com/dart-lang/foo'},
+              hostedVersions: ["3.0.0-pre", "2.0.0", "1.0.0"]);
+          expectDependencyValidationWarning('  foo: ">=2.0.0 <3.0.0"');
         });
 
-        integration("and should suggest the hosted package's prerelease "
-            "version if it's the only version available", () {
-          useMockClient(new MockClient((request) {
-            expect(request.method, equals("GET"));
-            expect(request.url.path, equals("/packages/foo.json"));
-
-            return new Future.immediate(new http.Response(json.stringify({
-              "name": "foo",
-              "uploaders": ["nweiz@google.com"],
-              "versions": ["3.0.0-pre", "2.0.0-pre"]
-            }), 200));
-          }));
-
-          dir(appPath, [
-            libPubspec("test_pkg", "1.0.0", deps: [
-              {'git': 'git://github.com/dart-lang/foo'}
-            ])
-          ]).scheduleCreate();
-
-          expectLater(schedulePackageValidation(dependency),
-              pairOf(isEmpty, someElement(contains(
-                  '  foo: ">=3.0.0-pre <4.0.0"'))));
+        integration("and should suggest the hosted prerelease version if "
+                    "it's the only version available", () {
+          setUpDependency({'git': 'git://github.com/dart-lang/foo'},
+              hostedVersions: ["3.0.0-pre", "2.0.0-pre"]);
+          expectDependencyValidationWarning('  foo: ">=3.0.0-pre <4.0.0"');
         });
 
-        integration("and should suggest a tighter constraint if the primary "
-            "version is pre-1.0.0", () {
-          useMockClient(new MockClient((request) {
-            expect(request.method, equals("GET"));
-            expect(request.url.path, equals("/packages/foo.json"));
-
-            return new Future.immediate(new http.Response(json.stringify({
-              "name": "foo",
-              "uploaders": ["nweiz@google.com"],
-              "versions": ["0.0.1", "0.0.2"]
-            }), 200));
-          }));
-
-          dir(appPath, [
-            libPubspec("test_pkg", "1.0.0", deps: [
-              {'git': 'git://github.com/dart-lang/foo'}
-            ])
-          ]).scheduleCreate();
-
-          expectLater(schedulePackageValidation(dependency),
-              pairOf(isEmpty, someElement(contains(
-                  '  foo: ">=0.0.2 <0.0.3"'))));
+        integration("and should suggest a tighter constraint if primary is "
+                    "pre-1.0.0", () {
+          setUpDependency({'git': 'git://github.com/dart-lang/foo'},
+              hostedVersions: ["0.0.1", "0.0.2"]);
+          expectDependencyValidationWarning('  foo: ">=0.0.2 <0.0.3"');
         });
       });
 
-      group('where no hosted version of that dependency exists', () {
+      group('where no hosted version exists', () {
         integration("and should use the other source's version", () {
-          useMockClient(new MockClient((request) {
-            expect(request.method, equals("GET"));
-            expect(request.url.path, equals("/packages/foo.json"));
-
-            return new Future.immediate(new http.Response("not found", 404));
-          }));
-
-          dir(appPath, [
-            libPubspec("test_pkg", "1.0.0", deps: [
-              {
-                'git': {'url': 'git://github.com/dart-lang/foo'},
-                'version': '>=1.0.0 <2.0.0'
-              }
-            ])
-          ]).scheduleCreate();
-
-          expectLater(schedulePackageValidation(dependency),
-              pairOf(isEmpty, someElement(contains(
-                  '  foo: ">=1.0.0 <2.0.0"'))));
+          setUpDependency({
+            'git': 'git://github.com/dart-lang/foo',
+            'version': '>=1.0.0 <2.0.0'
+          });
+          expectDependencyValidationWarning('  foo: ">=1.0.0 <2.0.0"');
         });
 
         integration("and should use the other source's unquoted version if "
-            "it's concrete", () {
-          useMockClient(new MockClient((request) {
-            expect(request.method, equals("GET"));
-            expect(request.url.path, equals("/packages/foo.json"));
+                    "concrete", () {
+          setUpDependency({
+            'git': 'git://github.com/dart-lang/foo',
+            'version': '0.2.3'
+          });
+          expectDependencyValidationWarning('  foo: 0.2.3');
+        });
+      });
+    });
 
-            return new Future.immediate(new http.Response("not found", 404));
-          }));
+    group('has a path dependency', () {
+      group('where a hosted version exists', () {
+        integration("and should suggest the hosted primary version", () {
+          setUpDependency({'path': path.join(sandboxDir, 'foo')},
+              hostedVersions: ["3.0.0-pre", "2.0.0", "1.0.0"]);
+          expectDependencyValidationError('  foo: ">=2.0.0 <3.0.0"');
+        });
 
-          dir(appPath, [
-            libPubspec("test_pkg", "1.0.0", deps: [
-              {
-                'git': {'url': 'git://github.com/dart-lang/foo'},
-                'version': '0.2.3'
-              }
-            ])
-          ]).scheduleCreate();
+        integration("and should suggest the hosted prerelease version if "
+                    "it's the only version available", () {
+          setUpDependency({'path': path.join(sandboxDir, 'foo')},
+              hostedVersions: ["3.0.0-pre", "2.0.0-pre"]);
+          expectDependencyValidationError('  foo: ">=3.0.0-pre <4.0.0"');
+        });
 
-          expectLater(schedulePackageValidation(dependency),
-              pairOf(isEmpty, someElement(contains('  foo: 0.2.3'))));
+        integration("and should suggest a tighter constraint if primary is "
+                    "pre-1.0.0", () {
+          setUpDependency({'path': path.join(sandboxDir, 'foo')},
+              hostedVersions: ["0.0.1", "0.0.2"]);
+          expectDependencyValidationError('  foo: ">=0.0.2 <0.0.3"');
+        });
+      });
+
+      group('where no hosted version exists', () {
+        integration("and should use the other source's version", () {
+          setUpDependency({
+            'path': path.join(sandboxDir, 'foo'),
+            'version': '>=1.0.0 <2.0.0'
+          });
+          expectDependencyValidationError('  foo: ">=1.0.0 <2.0.0"');
+        });
+
+        integration("and should use the other source's unquoted version if "
+                    "concrete", () {
+          setUpDependency({
+            'path': path.join(sandboxDir, 'foo'),
+            'version': '0.2.3'
+          });
+          expectDependencyValidationError('  foo: 0.2.3');
         });
       });
     });
@@ -507,9 +506,7 @@
             }))
           ]).scheduleCreate();
 
-          expectLater(schedulePackageValidation(dependency),
-              pairOf(isEmpty, someElement(contains(
-                  '  foo: ">=1.2.3 <2.0.0"'))));
+          expectDependencyValidationWarning('  foo: ">=1.2.3 <2.0.0"');
         });
 
         integration('and it should suggest a concrete constraint if the locked '
@@ -532,9 +529,7 @@
             }))
           ]).scheduleCreate();
 
-          expectLater(schedulePackageValidation(dependency),
-              pairOf(isEmpty, someElement(contains(
-                  '  foo: ">=0.1.2 <0.1.3"'))));
+          expectDependencyValidationWarning('  foo: ">=0.1.2 <0.1.3"');
         });
       });
     });