Version 0.5.20.0

svn merge -r 24061:24101 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@24106 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index 03c75c6..22db244 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -230,8 +230,12 @@
       'sources': [
         '../include/dart_api.h',
         '../include/dart_debugger_api.h',
+        '../include/dart_mirrors_api.h',
+        '../include/dart_native_api.h',
         '../vm/dart_api_impl.cc',
         '../vm/debugger_api_impl.cc',
+        '../vm/mirrors_api_impl.cc',
+        '../vm/native_api_impl.cc',
         '<(version_cc_file)',
       ],
       'defines': [
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 375c6d5..8134848 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -5,6 +5,7 @@
 #include "bin/dartutils.h"
 
 #include "include/dart_api.h"
+#include "include/dart_native_api.h"
 
 #include "platform/assert.h"
 #include "platform/globals.h"
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 48db952..026b83a 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -6,6 +6,7 @@
 #define BIN_DARTUTILS_H_
 
 #include "include/dart_api.h"
+#include "include/dart_native_api.h"
 
 #include "platform/assert.h"
 #include "platform/globals.h"
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index 6ca4ac0..7ce1787 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -150,11 +150,11 @@
                Dart_Null(),
                0,
                NULL);
-  SyncDirectoryListing sync_listing(results);
-  Directory::List(DartUtils::GetStringValue(path),
-                  DartUtils::GetBooleanValue(recursive),
-                  DartUtils::GetBooleanValue(follow_links),
-                  &sync_listing);
+  SyncDirectoryListing sync_listing(results,
+                                    DartUtils::GetStringValue(path),
+                                    DartUtils::GetBooleanValue(recursive),
+                                    DartUtils::GetBooleanValue(follow_links));
+  Directory::List(&sync_listing);
   Dart_SetReturnValue(args, results);
   Dart_ExitScope();
 }
@@ -220,41 +220,75 @@
   return CObject::IllegalArgumentError();
 }
 
+static CObject* CreateIllegalArgumentError() {
+  // Respond with an illegal argument list error message.
+  CObjectArray* error = new CObjectArray(CObject::NewArray(3));
+  error->SetAt(0, new CObjectInt32(
+      CObject::NewInt32(AsyncDirectoryListing::kListError)));
+  error->SetAt(1, CObject::Null());
+  error->SetAt(2, CObject::IllegalArgumentError());
+  return error;
+}
 
-static CObject* DirectoryListRequest(const CObjectArray& request,
-                                     Dart_Port response_port) {
+static CObject* DirectoryListStartRequest(const CObjectArray& request) {
   if (request.Length() == 4 &&
       request[1]->IsString() &&
       request[2]->IsBool() &&
       request[3]->IsBool()) {
-    AsyncDirectoryListing* dir_listing =
-        new AsyncDirectoryListing(response_port);
     CObjectString path(request[1]);
     CObjectBool recursive(request[2]);
     CObjectBool follow_links(request[3]);
-    bool completed = Directory::List(
-        path.CString(), recursive.Value(), follow_links.Value(), dir_listing);
-    delete dir_listing;
-    CObjectArray* response = new CObjectArray(CObject::NewArray(2));
-    response->SetAt(
-        0,
-        new CObjectInt32(CObject::NewInt32(AsyncDirectoryListing::kListDone)));
-    response->SetAt(1, CObject::Bool(completed));
+    AsyncDirectoryListing* dir_listing =
+        new AsyncDirectoryListing(path.CString(),
+                                  recursive.Value(),
+                                  follow_links.Value());
+    if (dir_listing->error()) {
+      // Report error now, so we capture the correct OSError.
+      CObject* err = CObject::NewOSError();
+      delete dir_listing;
+      CObjectArray* error = new CObjectArray(CObject::NewArray(3));
+      error->SetAt(0, new CObjectInt32(
+          CObject::NewInt32(AsyncDirectoryListing::kListError)));
+      error->SetAt(1, request[1]);
+      error->SetAt(2, err);
+      return error;
+    }
+    // TODO(ajohnsen): Consider returning the first few results.
+    return new CObjectIntptr(CObject::NewIntptr(
+        reinterpret_cast<intptr_t>(dir_listing)));
+  }
+  return CreateIllegalArgumentError();
+}
+
+
+static CObject* DirectoryListNextRequest(const CObjectArray& request) {
+  if (request.Length() == 2 &&
+      request[1]->IsIntptr()) {
+    CObjectIntptr ptr(request[1]);
+    AsyncDirectoryListing* dir_listing =
+        reinterpret_cast<AsyncDirectoryListing*>(ptr.Value());
+    const int kArraySize = 128;
+    CObjectArray* response = new CObjectArray(CObject::NewArray(kArraySize));
+    dir_listing->SetArray(response, kArraySize);
+    Directory::List(dir_listing);
+    // In case the listing ended before it hit the buffer length, we need to
+    // override the array length.
+    response->AsApiCObject()->value.as_array.length = dir_listing->index();
     return response;
   }
-  // Respond with an illegal argument list error message.
-  CObjectArray* response = new CObjectArray(CObject::NewArray(3));
-  response->SetAt(0, new CObjectInt32(
-      CObject::NewInt32(AsyncDirectoryListing::kListError)));
-  response->SetAt(1, CObject::Null());
-  response->SetAt(2, CObject::IllegalArgumentError());
-  Dart_PostCObject(response_port, response->AsApiCObject());
+  return CreateIllegalArgumentError();
+}
 
-  response = new CObjectArray(CObject::NewArray(2));
-  response->SetAt(
-      0, new CObjectInt32(CObject::NewInt32(AsyncDirectoryListing::kListDone)));
-  response->SetAt(1, CObject::False());
-  return response;
+
+static CObject* DirectoryListStopRequest(const CObjectArray& request) {
+  if (request.Length() == 2 && request[1]->IsIntptr()) {
+    CObjectIntptr ptr(request[1]);
+    AsyncDirectoryListing* dir_listing =
+        reinterpret_cast<AsyncDirectoryListing*>(ptr.Value());
+    delete dir_listing;
+    return new CObjectBool(CObject::Bool(true));
+  }
+  return CreateIllegalArgumentError();
 }
 
 
@@ -294,8 +328,14 @@
         case Directory::kCreateTempRequest:
           response = DirectoryCreateTempRequest(request);
           break;
-        case Directory::kListRequest:
-          response = DirectoryListRequest(request, reply_port_id);
+        case Directory::kListStartRequest:
+          response = DirectoryListStartRequest(request);
+          break;
+        case Directory::kListNextRequest:
+          response = DirectoryListNextRequest(request);
+          break;
+        case Directory::kListStopRequest:
+          response = DirectoryListStopRequest(request);
           break;
         case Directory::kRenameRequest:
           response = DirectoryRenameRequest(request, reply_port_id);
@@ -328,39 +368,46 @@
 }
 
 
-CObjectArray* AsyncDirectoryListing::NewResponse(Response type, char* arg) {
-  CObjectArray* response = new CObjectArray(CObject::NewArray(2));
-  response->SetAt(0, new CObjectInt32(CObject::NewInt32(type)));
-  response->SetAt(1, new CObjectString(CObject::NewString(arg)));
-  return response;
+bool AsyncDirectoryListing::AddFileSystemEntityToResponse(Response type,
+                                                          char* arg) {
+  array_->SetAt(index_++, new CObjectInt32(CObject::NewInt32(type)));
+  if (arg != NULL) {
+    array_->SetAt(index_++, new CObjectString(CObject::NewString(arg)));
+  } else {
+    array_->SetAt(index_++, CObject::Null());
+  }
+  return index_ < length_;
 }
 
 
 bool AsyncDirectoryListing::HandleDirectory(char* dir_name) {
-  CObjectArray* response = NewResponse(kListDirectory, dir_name);
-  return Dart_PostCObject(response_port_, response->AsApiCObject());
+  return AddFileSystemEntityToResponse(kListDirectory, dir_name);
 }
 
 
 bool AsyncDirectoryListing::HandleFile(char* file_name) {
-  CObjectArray* response = NewResponse(kListFile, file_name);
-  return Dart_PostCObject(response_port_, response->AsApiCObject());
+  return AddFileSystemEntityToResponse(kListFile, file_name);
 }
 
 
 bool AsyncDirectoryListing::HandleLink(char* link_name) {
-  CObjectArray* response = NewResponse(kListLink, link_name);
-  return Dart_PostCObject(response_port_, response->AsApiCObject());
+  return AddFileSystemEntityToResponse(kListLink, link_name);
+}
+
+void AsyncDirectoryListing::HandleDone() {
+  AddFileSystemEntityToResponse(kListDone, NULL);
 }
 
 
 bool AsyncDirectoryListing::HandleError(const char* dir_name) {
   CObject* err = CObject::NewOSError();
+  array_->SetAt(index_++, new CObjectInt32(CObject::NewInt32(kListError)));
   CObjectArray* response = new CObjectArray(CObject::NewArray(3));
   response->SetAt(0, new CObjectInt32(CObject::NewInt32(kListError)));
   response->SetAt(1, new CObjectString(CObject::NewString(dir_name)));
   response->SetAt(2, err);
-  return Dart_PostCObject(response_port_, response->AsApiCObject());
+  array_->SetAt(index_++, response);
+  return index_ < length_;
 }
 
 bool SyncDirectoryListing::HandleDirectory(char* dir_name) {
@@ -401,5 +448,47 @@
   return true;
 }
 
+
+static bool ListNext(DirectoryListing* listing) {
+  switch (listing->top()->Next(listing)) {
+    case kListFile:
+      return listing->HandleFile(listing->CurrentPath());
+
+    case kListLink:
+      return listing->HandleLink(listing->CurrentPath());
+
+    case kListDirectory:
+      if (listing->recursive()) {
+        listing->Push(new DirectoryListingEntry(listing->top()));
+      }
+      return listing->HandleDirectory(listing->CurrentPath());
+
+    case kListError:
+      return listing->HandleError(listing->CurrentPath());
+
+    case kListDone:
+      listing->Pop();
+      if (listing->IsEmpty()) {
+        listing->HandleDone();
+        return false;
+      } else {
+        return true;
+      }
+
+    default:
+      UNREACHABLE();
+  }
+  return false;
+}
+
+void Directory::List(DirectoryListing* listing) {
+  if (listing->error()) {
+    listing->HandleError("Invalid path");
+    listing->HandleDone();
+  } else {
+    while (ListNext(listing)) {}
+  }
+}
+
 }  // namespace bin
 }  // namespace dart
diff --git a/runtime/bin/directory.h b/runtime/bin/directory.h
index a19d274..5fa10f0 100644
--- a/runtime/bin/directory.h
+++ b/runtime/bin/directory.h
@@ -15,13 +15,165 @@
 namespace dart {
 namespace bin {
 
+enum ListType {
+  kListFile = 0,
+  kListDirectory = 1,
+  kListLink = 2,
+  kListError = 3,
+  kListDone = 4
+};
+
+class PathBuffer {
+ public:
+  PathBuffer();
+  ~PathBuffer() {
+    free(data_);
+  }
+
+  bool Add(const char* name);
+  bool AddW(const wchar_t* name);
+
+  char* AsString() const;
+  wchar_t* AsStringW() const;
+
+  void Reset(int new_length);
+
+  int length() const {
+    return length_;
+  }
+
+ private:
+  void* data_;
+  int length_;
+
+  DISALLOW_COPY_AND_ASSIGN(PathBuffer);
+};
+
+class DirectoryListing;
+
+struct LinkList;
+
+// DirectoryListingEntry is used as a stack item, when performing recursive
+// directory listing. By using DirectoryListingEntry as stack elements, a
+// directory listing can be paused e.g. when a buffer is full, and resumed
+// later on.
+//
+// The stack is managed by the DirectoryListing's PathBuffer. Each
+// DirectoryListingEntry stored a entry-length, that it'll reset the PathBuffer
+// to on each call to Next.
+class DirectoryListingEntry {
+ public:
+  explicit DirectoryListingEntry(DirectoryListingEntry* parent)
+    : parent_(parent), lister_(0), done_(false), link_(NULL) {}
+
+  ~DirectoryListingEntry() {
+    ResetLink();
+  }
+
+  ListType Next(DirectoryListing* listing);
+
+  DirectoryListingEntry* parent() const {
+    return parent_;
+  }
+
+  LinkList* link() {
+    return link_;
+  }
+
+  void set_link(LinkList* link) {
+    link_ = link;
+  }
+
+  void ResetLink() {
+    if (link_ != NULL && (parent_ == NULL || parent_->link_ != link_)) {
+      free(link_);
+      link_ = NULL;
+    }
+    if (parent_ != NULL) {
+      link_ = parent_->link_;
+    }
+  }
+
+ private:
+  DirectoryListingEntry* parent_;
+  intptr_t lister_;
+  bool done_;
+  int path_length_;
+  LinkList* link_;
+
+  DISALLOW_COPY_AND_ASSIGN(DirectoryListingEntry);
+};
+
 class DirectoryListing {
  public:
-  virtual ~DirectoryListing() {}
+  DirectoryListing(const char* dir_name, bool recursive, bool follow_links)
+    : top_(NULL),
+      error_(false),
+      recursive_(recursive),
+      follow_links_(follow_links) {
+    if (!path_buffer_.Add(dir_name)) {
+      error_ = true;
+    }
+    Push(new DirectoryListingEntry(NULL));
+  }
+
+  virtual ~DirectoryListing() {
+    while (!IsEmpty()) {
+      Pop();
+    }
+  }
+
   virtual bool HandleDirectory(char* dir_name) = 0;
   virtual bool HandleFile(char* file_name) = 0;
-  virtual bool HandleLink(char* file_name) = 0;
+  virtual bool HandleLink(char* link_name) = 0;
   virtual bool HandleError(const char* dir_name) = 0;
+  virtual void HandleDone() {}
+
+  void Push(DirectoryListingEntry* directory) {
+    top_ = directory;
+  }
+
+  void Pop() {
+    ASSERT(!IsEmpty());
+    DirectoryListingEntry* current = top_;
+    top_ = top_->parent();
+    delete current;
+  }
+
+  bool IsEmpty() const {
+    return top_ == NULL;
+  }
+
+  DirectoryListingEntry* top() const {
+    return top_;
+  }
+
+  bool recursive() const {
+    return recursive_;
+  }
+
+  bool follow_links() const {
+    return follow_links_;
+  }
+
+  char* CurrentPath() {
+    return path_buffer_.AsString();
+  }
+
+  PathBuffer& path_buffer() {
+    return path_buffer_;
+  }
+
+  bool error() const {
+    return error_;
+  }
+
+ private:
+  PathBuffer path_buffer_;
+  DirectoryListingEntry* top_;
+  bool error_;
+  bool recursive_;
+  bool follow_links_;
 };
 
 
@@ -35,17 +187,34 @@
     kListDone = 4
   };
 
-  explicit AsyncDirectoryListing(Dart_Port response_port)
-      : response_port_(response_port) {}
+  AsyncDirectoryListing(const char* dir_name,
+                        bool recursive,
+                        bool follow_links)
+      : DirectoryListing(dir_name, recursive, follow_links) {}
+
   virtual ~AsyncDirectoryListing() {}
   virtual bool HandleDirectory(char* dir_name);
   virtual bool HandleFile(char* file_name);
   virtual bool HandleLink(char* file_name);
   virtual bool HandleError(const char* dir_name);
+  virtual void HandleDone();
+
+  void SetArray(CObjectArray* array, intptr_t length) {
+    ASSERT(length % 2 == 0);
+    array_ = array;
+    index_ = 0;
+    length_ = length;
+  }
+
+  intptr_t index() const {
+    return index_;
+  }
 
  private:
-  CObjectArray* NewResponse(Response response, char* arg);
-  Dart_Port response_port_;
+  bool AddFileSystemEntityToResponse(Response response, char* arg);
+  CObjectArray* array_;
+  intptr_t index_;
+  intptr_t length_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(AsyncDirectoryListing);
 };
@@ -53,8 +222,12 @@
 
 class SyncDirectoryListing: public DirectoryListing {
  public:
-  explicit SyncDirectoryListing(Dart_Handle results)
-      : results_(results) {
+  SyncDirectoryListing(Dart_Handle results,
+                       const char* dir_name,
+                       bool recursive,
+                       bool follow_links)
+      : DirectoryListing(dir_name, recursive, follow_links),
+        results_(results) {
     add_string_ = DartUtils::NewString("add");
     directory_class_ =
         DartUtils::GetDartClass(DartUtils::kIOLibURL, "Directory");
@@ -95,14 +268,13 @@
     kDeleteRequest = 1,
     kExistsRequest = 2,
     kCreateTempRequest = 3,
-    kListRequest = 4,
-    kRenameRequest = 5
+    kListStartRequest = 4,
+    kListNextRequest = 5,
+    kListStopRequest = 6,
+    kRenameRequest = 7
   };
 
-  static bool List(const char* path,
-                   bool recursive,
-                   bool follow_links,
-                   DirectoryListing* listing);
+  static void List(DirectoryListing* listing);
   static ExistsResult Exists(const char* path);
   static char* Current();
   static bool SetCurrent(const char* path);
diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc
index dc5bad2..5c0f891 100644
--- a/runtime/bin/directory_android.cc
+++ b/runtime/bin/directory_android.cc
@@ -21,41 +21,47 @@
 namespace dart {
 namespace bin {
 
-class PathBuffer {
- public:
-  PathBuffer() : length(0) {
-    data = new char[PATH_MAX + 1];
-  }
 
-  ~PathBuffer() {
-    delete[] data;
-  }
+PathBuffer::PathBuffer() : length_(0) {
+  data_ = new char[PATH_MAX + 1];
+}
 
-  char* data;
-  int length;
+bool PathBuffer::AddW(const wchar_t* name) {
+  UNREACHABLE();
+  return false;
+}
 
-  bool Add(const char* name) {
-    int written = snprintf(data + length,
-                           PATH_MAX - length,
-                           "%s",
-                           name);
-    data[PATH_MAX] = '\0';
-    if (written <= PATH_MAX - length &&
-        written >= 0 &&
-        static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) {
-      length += written;
-      return true;
-    } else {
-      errno = ENAMETOOLONG;
-      return false;
-    }
-  }
+char* PathBuffer::AsString() const {
+  return reinterpret_cast<char*>(data_);
+}
 
-  void Reset(int new_length) {
-    length = new_length;
-    data[length] = '\0';
+wchar_t* PathBuffer::AsStringW() const {
+  UNREACHABLE();
+  return NULL;
+}
+
+bool PathBuffer::Add(const char* name) {
+  char* data = AsString();
+  int written = snprintf(data + length_,
+                         PATH_MAX - length_,
+                         "%s",
+                         name);
+  data[PATH_MAX] = '\0';
+  if (written <= PATH_MAX - length_ &&
+      written >= 0 &&
+      static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) {
+    length_ += written;
+    return true;
+  } else {
+    errno = ENAMETOOLONG;
+    return false;
   }
-};
+}
+
+void PathBuffer::Reset(int new_length) {
+  length_ = new_length;
+  AsString()[length_] = '\0';
+}
 
 
 // A linked list of symbolic links, with their unique file system identifiers.
@@ -67,110 +73,54 @@
 };
 
 
-// Forward declarations.
-static bool ListRecursively(PathBuffer* path,
-                            bool recursive,
-                            bool follow_links,
-                            LinkList* seen,
-                            DirectoryListing* listing);
-static bool DeleteRecursively(PathBuffer* path);
-
-
-static void PostError(DirectoryListing *listing,
-                      const char* dir_name) {
-  listing->HandleError(dir_name);
-}
-
-
-static bool HandleDir(char* dir_name,
-                      PathBuffer* path,
-                      bool recursive,
-                      bool follow_links,
-                      LinkList* seen,
-                      DirectoryListing *listing) {
-  if (strcmp(dir_name, ".") == 0) return true;
-  if (strcmp(dir_name, "..") == 0) return true;
-  if (!path->Add(dir_name)) {
-    PostError(listing, path->data);
-    return false;
+ListType DirectoryListingEntry::Next(DirectoryListing* listing) {
+  if (done_) {
+    return kListDone;
   }
-  return listing->HandleDirectory(path->data) &&
-      (!recursive ||
-       ListRecursively(path, recursive, follow_links, seen, listing));
-}
 
+  if (lister_ == 0) {
+    if (!listing->path_buffer().Add(File::PathSeparator())) {
+      done_ = true;
+      return kListError;
+    }
+    path_length_ = listing->path_buffer().length();
+    do {
+      lister_ = reinterpret_cast<intptr_t>(
+          opendir(listing->path_buffer().AsString()));
+    } while (lister_ == 0 && errno == EINTR);
 
-static bool HandleFile(char* file_name,
-                       PathBuffer* path,
-                       DirectoryListing *listing) {
-  if (!path->Add(file_name)) {
-    PostError(listing, path->data);
-    return false;
+    if (lister_ == 0) {
+      done_ = true;
+      return kListError;
+    }
   }
-  return listing->HandleFile(path->data);
-}
-
-
-static bool HandleLink(char* link_name,
-                       PathBuffer* path,
-                       DirectoryListing *listing) {
-  if (!path->Add(link_name)) {
-    PostError(listing, path->data);
-    return false;
-  }
-  return listing->HandleLink(path->data);
-}
-
-
-static bool ListRecursively(PathBuffer* path,
-                            bool recursive,
-                            bool follow_links,
-                            LinkList* seen,
-                            DirectoryListing *listing) {
-  if (!path->Add(File::PathSeparator())) {
-    PostError(listing, path->data);
-    return false;
-  }
-  DIR* dir_pointer;
-  do {
-    dir_pointer = opendir(path->data);
-  } while (dir_pointer == NULL && errno == EINTR);
-  if (dir_pointer == NULL) {
-    PostError(listing, path->data);
-    return false;
-  }
+  // Reset.
+  listing->path_buffer().Reset(path_length_);
+  ResetLink();
 
   // Iterate the directory and post the directories and files to the
   // ports.
-  int path_length = path->length;
   int status = 0;
-  bool success = true;
   dirent entry;
   dirent* result;
-  while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
-                                                &entry,
-                                                &result))) == 0 &&
-         result != NULL) {
+  if ((status = TEMP_FAILURE_RETRY(readdir_r(reinterpret_cast<DIR*>(lister_),
+                                    &entry,
+                                    &result))) == 0 &&
+      result != NULL) {
+    if (!listing->path_buffer().Add(entry.d_name)) {
+      done_ = true;
+      return kListError;
+    }
     switch (entry.d_type) {
       case DT_DIR:
-        success = HandleDir(entry.d_name,
-                            path,
-                            recursive,
-                            follow_links,
-                            seen,
-                            listing) && success;
-        break;
+        if (strcmp(entry.d_name, ".") == 0) return Next(listing);
+        if (strcmp(entry.d_name, "..") == 0) return Next(listing);
+        return kListDirectory;
       case DT_REG:
-        success = HandleFile(entry.d_name,
-                             path,
-                             listing) && success;
-        break;
+        return kListFile;
       case DT_LNK:
-        if (!follow_links) {
-          success = HandleLink(entry.d_name,
-                               path,
-                               listing) && success;
-          break;
+        if (!listing->follow_links()) {
+          return kListLink;
         }
         // Else fall through to next case.
         // Fall through.
@@ -180,103 +130,77 @@
         // the actual entry type. Notice that stat returns the type of
         // the file pointed to.
         struct stat entry_info;
-        if (!path->Add(entry.d_name)) {
-          success = false;
-          break;
-        }
         int stat_success;
-        stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
+        stat_success = TEMP_FAILURE_RETRY(
+            lstat(listing->path_buffer().AsString(), &entry_info));
         if (stat_success == -1) {
-          success = false;
-          PostError(listing, path->data);
-          break;
+          return kListError;
         }
-        if (follow_links && S_ISLNK(entry_info.st_mode)) {
+        if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) {
           // Check to see if we are in a loop created by a symbolic link.
           LinkList current_link = { entry_info.st_dev,
                                     entry_info.st_ino,
-                                    seen };
-          LinkList* previous = seen;
-          bool looping_link = false;
+                                    link_ };
+          LinkList* previous = link_;
           while (previous != NULL) {
             if (previous->dev == current_link.dev &&
                 previous->ino == current_link.ino) {
               // Report the looping link as a link, rather than following it.
-              path->Reset(path_length);
-              success = HandleLink(entry.d_name,
-                                   path,
-                                   listing) && success;
-              looping_link = true;
-              break;
+              return kListLink;
             }
             previous = previous->next;
           }
-          if (looping_link) break;
-          stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
+          stat_success = TEMP_FAILURE_RETRY(
+              stat(listing->path_buffer().AsString(), &entry_info));
           if (stat_success == -1) {
             // Report a broken link as a link, even if follow_links is true.
-            path->Reset(path_length);
-            success = HandleLink(entry.d_name,
-                                 path,
-                                 listing) && success;
-            break;
+            return kListLink;
           }
           if (S_ISDIR(entry_info.st_mode)) {
             // Recurse into the subdirectory with current_link added to the
             // linked list of seen file system links.
-            path->Reset(path_length);
-            success = HandleDir(entry.d_name,
-                                path,
-                                recursive,
-                                follow_links,
-                                &current_link,
-                                listing) && success;
-            break;
+            link_ = new LinkList(current_link);
+            if (strcmp(entry.d_name, ".") == 0) return Next(listing);
+            if (strcmp(entry.d_name, "..") == 0) return Next(listing);
+            return kListDirectory;
           }
         }
-        path->Reset(path_length);
         if (S_ISDIR(entry_info.st_mode)) {
-          success = HandleDir(entry.d_name,
-                              path,
-                              recursive,
-                              follow_links,
-                              seen,
-                              listing) && success;
+          if (strcmp(entry.d_name, ".") == 0) return Next(listing);
+          if (strcmp(entry.d_name, "..") == 0) return Next(listing);
+          return kListDirectory;
         } else if (S_ISREG(entry_info.st_mode)) {
-          success = HandleFile(entry.d_name,
-                               path,
-                               listing) && success;
+          return kListFile;
         } else if (S_ISLNK(entry_info.st_mode)) {
-          success = HandleLink(entry.d_name,
-                               path,
-                               listing) && success;
+          return kListLink;
         }
-        break;
       }
+
       default:
         break;
     }
-    path->Reset(path_length);
   }
+  done_ = true;
 
   if (status != 0) {
     errno = status;
-    success = false;
-    PostError(listing, path->data);
+    return kListError;
   }
 
-  if (closedir(dir_pointer) == -1) {
-    success = false;
-    PostError(listing, path->data);
+  if (closedir(reinterpret_cast<DIR*>(lister_)) == -1) {
+    return kListError;
   }
 
-  return success;
+  return kListDone;
 }
 
 
+static bool DeleteRecursively(PathBuffer* path);
+
+
 static bool DeleteFile(char* file_name,
                        PathBuffer* path) {
-  return path->Add(file_name) && unlink(path->data) == 0;
+  return path->Add(file_name) && unlink(path->AsString()) == 0;
 }
 
 
@@ -292,10 +216,10 @@
   // Do not recurse into links for deletion. Instead delete the link.
   // If it's a file, delete it.
   struct stat st;
-  if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
+  if (TEMP_FAILURE_RETRY(lstat(path->AsString(), &st)) == -1) {
     return false;
   } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
-    return (unlink(path->data) == 0);
+    return (unlink(path->AsString()) == 0);
   }
 
   if (!path->Add(File::PathSeparator())) return false;
@@ -304,7 +228,7 @@
   // directory.
   DIR* dir_pointer;
   do {
-    dir_pointer = opendir(path->data);
+    dir_pointer = opendir(path->AsString());
   } while (dir_pointer == NULL && errno == EINTR);
 
   if (dir_pointer == NULL) {
@@ -312,7 +236,7 @@
   }
 
   // Iterate the directory and delete all files and directories.
-  int path_length = path->length;
+  int path_length = path->length();
   int read = 0;
   bool success = true;
   dirent entry;
@@ -342,7 +266,8 @@
           success = false;
           break;
         }
-        int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
+        int lstat_success = TEMP_FAILURE_RETRY(
+            lstat(path->AsString(), &entry_info));
         if (lstat_success == -1) {
           success = false;
           break;
@@ -366,26 +291,13 @@
 
   if ((read != 0) ||
       (closedir(dir_pointer) == -1) ||
-      (remove(path->data) == -1)) {
+      (remove(path->AsString()) == -1)) {
     return false;
   }
   return success;
 }
 
 
-bool Directory::List(const char* dir_name,
-                     bool recursive,
-                     bool follow_links,
-                     DirectoryListing *listing) {
-  PathBuffer path;
-  if (!path.Add(dir_name)) {
-    PostError(listing, dir_name);
-    return false;
-  }
-  return ListRecursively(&path, recursive, follow_links, NULL, listing);
-}
-
-
 Directory::ExistsResult Directory::Exists(const char* dir_name) {
   struct stat entry_info;
   int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
@@ -466,7 +378,7 @@
   // The return value must be freed by the caller.
   PathBuffer path;
   path.Add(const_template);
-  if (path.length == 0) {
+  if (path.length() == 0) {
     // Android does not have a /tmp directory. A partial substitute,
     // suitable for bring-up work and tests, is to create a tmp
     // directory in /data/local/tmp.
@@ -479,7 +391,7 @@
       mkdir(ANDROID_TEMP_DIR, 0777);
     }
     path.Add(ANDROID_TEMP_DIR "/temp_dir1_");
-  } else if ((path.data)[path.length - 1] == '/') {
+  } else if ((path.AsString())[path.length() - 1] == '/') {
     path.Add("temp_dir_");
   }
   if (!path.Add("XXXXXX")) {
@@ -488,14 +400,14 @@
   }
   char* result;
   do {
-    result = MakeTempDirectory(path.data);
+    result = MakeTempDirectory(path.AsString());
   } while (result == NULL && errno == EINTR);
   if (result == NULL) {
     return NULL;
   }
-  int length = strnlen(path.data, PATH_MAX);
+  int length = strnlen(path.AsString(), PATH_MAX);
   result = static_cast<char*>(malloc(length + 1));
-  strncpy(result, path.data, length);
+  strncpy(result, path.AsString(), length);
   result[length] = '\0';
   return result;
 }
diff --git a/runtime/bin/directory_linux.cc b/runtime/bin/directory_linux.cc
index bd84753..f715604 100644
--- a/runtime/bin/directory_linux.cc
+++ b/runtime/bin/directory_linux.cc
@@ -21,41 +21,47 @@
 namespace dart {
 namespace bin {
 
-class PathBuffer {
- public:
-  PathBuffer() : length(0) {
-    data = new char[PATH_MAX + 1];
-  }
 
-  ~PathBuffer() {
-    delete[] data;
-  }
+PathBuffer::PathBuffer() : length_(0) {
+  data_ = new char[PATH_MAX + 1];
+}
 
-  char* data;
-  int length;
+bool PathBuffer::AddW(const wchar_t* name) {
+  UNREACHABLE();
+  return false;
+}
 
-  bool Add(const char* name) {
-    int written = snprintf(data + length,
-                           PATH_MAX - length,
-                           "%s",
-                           name);
-    data[PATH_MAX] = '\0';
-    if (written <= PATH_MAX - length &&
-        written >= 0 &&
-        static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) {
-      length += written;
-      return true;
-    } else {
-      errno = ENAMETOOLONG;
-      return false;
-    }
-  }
+char* PathBuffer::AsString() const {
+  return reinterpret_cast<char*>(data_);
+}
 
-  void Reset(int new_length) {
-    length = new_length;
-    data[length] = '\0';
+wchar_t* PathBuffer::AsStringW() const {
+  UNREACHABLE();
+  return NULL;
+}
+
+bool PathBuffer::Add(const char* name) {
+  char* data = AsString();
+  int written = snprintf(data + length_,
+                         PATH_MAX - length_,
+                         "%s",
+                         name);
+  data[PATH_MAX] = '\0';
+  if (written <= PATH_MAX - length_ &&
+      written >= 0 &&
+      static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1)) {
+    length_ += written;
+    return true;
+  } else {
+    errno = ENAMETOOLONG;
+    return false;
   }
-};
+}
+
+void PathBuffer::Reset(int new_length) {
+  length_ = new_length;
+  AsString()[length_] = '\0';
+}
 
 
 // A linked list of symbolic links, with their unique file system identifiers.
@@ -67,110 +73,54 @@
 };
 
 
-// Forward declarations.
-static bool ListRecursively(PathBuffer* path,
-                            bool recursive,
-                            bool follow_links,
-                            LinkList* seen,
-                            DirectoryListing* listing);
-static bool DeleteRecursively(PathBuffer* path);
-
-
-static void PostError(DirectoryListing *listing,
-                      const char* dir_name) {
-  listing->HandleError(dir_name);
-}
-
-
-static bool HandleDir(char* dir_name,
-                      PathBuffer* path,
-                      bool recursive,
-                      bool follow_links,
-                      LinkList* seen,
-                      DirectoryListing *listing) {
-  if (strcmp(dir_name, ".") == 0) return true;
-  if (strcmp(dir_name, "..") == 0) return true;
-  if (!path->Add(dir_name)) {
-    PostError(listing, path->data);
-    return false;
+ListType DirectoryListingEntry::Next(DirectoryListing* listing) {
+  if (done_) {
+    return kListDone;
   }
-  return listing->HandleDirectory(path->data) &&
-      (!recursive ||
-       ListRecursively(path, recursive, follow_links, seen, listing));
-}
 
+  if (lister_ == 0) {
+    if (!listing->path_buffer().Add(File::PathSeparator())) {
+      done_ = true;
+      return kListError;
+    }
+    path_length_ = listing->path_buffer().length();
+    do {
+      lister_ = reinterpret_cast<intptr_t>(
+          opendir(listing->path_buffer().AsString()));
+    } while (lister_ == 0 && errno == EINTR);
 
-static bool HandleFile(char* file_name,
-                       PathBuffer* path,
-                       DirectoryListing *listing) {
-  if (!path->Add(file_name)) {
-    PostError(listing, path->data);
-    return false;
+    if (lister_ == 0) {
+      done_ = true;
+      return kListError;
+    }
   }
-  return listing->HandleFile(path->data);
-}
-
-
-static bool HandleLink(char* link_name,
-                       PathBuffer* path,
-                       DirectoryListing *listing) {
-  if (!path->Add(link_name)) {
-    PostError(listing, path->data);
-    return false;
-  }
-  return listing->HandleLink(path->data);
-}
-
-
-static bool ListRecursively(PathBuffer* path,
-                            bool recursive,
-                            bool follow_links,
-                            LinkList* seen,
-                            DirectoryListing *listing) {
-  if (!path->Add(File::PathSeparator())) {
-    PostError(listing, path->data);
-    return false;
-  }
-  DIR* dir_pointer;
-  do {
-    dir_pointer = opendir(path->data);
-  } while (dir_pointer == NULL && errno == EINTR);
-  if (dir_pointer == NULL) {
-    PostError(listing, path->data);
-    return false;
-  }
+  // Reset.
+  listing->path_buffer().Reset(path_length_);
+  ResetLink();
 
   // Iterate the directory and post the directories and files to the
   // ports.
-  int path_length = path->length;
   int status = 0;
-  bool success = true;
   dirent entry;
   dirent* result;
-  while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
-                                                &entry,
-                                                &result))) == 0 &&
-         result != NULL) {
+  if ((status = TEMP_FAILURE_RETRY(readdir_r(reinterpret_cast<DIR*>(lister_),
+                                    &entry,
+                                    &result))) == 0 &&
+      result != NULL) {
+    if (!listing->path_buffer().Add(entry.d_name)) {
+      done_ = true;
+      return kListError;
+    }
     switch (entry.d_type) {
       case DT_DIR:
-        success = HandleDir(entry.d_name,
-                            path,
-                            recursive,
-                            follow_links,
-                            seen,
-                            listing) && success;
-        break;
+        if (strcmp(entry.d_name, ".") == 0) return Next(listing);
+        if (strcmp(entry.d_name, "..") == 0) return Next(listing);
+        return kListDirectory;
       case DT_REG:
-        success = HandleFile(entry.d_name,
-                             path,
-                             listing) && success;
-        break;
+        return kListFile;
       case DT_LNK:
-        if (!follow_links) {
-          success = HandleLink(entry.d_name,
-                               path,
-                               listing) && success;
-          break;
+        if (!listing->follow_links()) {
+          return kListLink;
         }
         // Else fall through to next case.
         // Fall through.
@@ -180,103 +130,77 @@
         // the actual entry type. Notice that stat returns the type of
         // the file pointed to.
         struct stat entry_info;
-        if (!path->Add(entry.d_name)) {
-          success = false;
-          break;
-        }
         int stat_success;
-        stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
+        stat_success = TEMP_FAILURE_RETRY(
+            lstat(listing->path_buffer().AsString(), &entry_info));
         if (stat_success == -1) {
-          success = false;
-          PostError(listing, path->data);
-          break;
+          return kListError;
         }
-        if (follow_links && S_ISLNK(entry_info.st_mode)) {
+        if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) {
           // Check to see if we are in a loop created by a symbolic link.
           LinkList current_link = { entry_info.st_dev,
                                     entry_info.st_ino,
-                                    seen };
-          LinkList* previous = seen;
-          bool looping_link = false;
+                                    link_ };
+          LinkList* previous = link_;
           while (previous != NULL) {
             if (previous->dev == current_link.dev &&
                 previous->ino == current_link.ino) {
               // Report the looping link as a link, rather than following it.
-              path->Reset(path_length);
-              success = HandleLink(entry.d_name,
-                                   path,
-                                   listing) && success;
-              looping_link = true;
-              break;
+              return kListLink;
             }
             previous = previous->next;
           }
-          if (looping_link) break;
-          stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
+          stat_success = TEMP_FAILURE_RETRY(
+              stat(listing->path_buffer().AsString(), &entry_info));
           if (stat_success == -1) {
             // Report a broken link as a link, even if follow_links is true.
-            path->Reset(path_length);
-            success = HandleLink(entry.d_name,
-                                 path,
-                                 listing) && success;
-            break;
+            return kListLink;
           }
           if (S_ISDIR(entry_info.st_mode)) {
             // Recurse into the subdirectory with current_link added to the
             // linked list of seen file system links.
-            path->Reset(path_length);
-            success = HandleDir(entry.d_name,
-                                path,
-                                recursive,
-                                follow_links,
-                                &current_link,
-                                listing) && success;
-            break;
+            link_ = new LinkList(current_link);
+            if (strcmp(entry.d_name, ".") == 0) return Next(listing);
+            if (strcmp(entry.d_name, "..") == 0) return Next(listing);
+            return kListDirectory;
           }
         }
-        path->Reset(path_length);
         if (S_ISDIR(entry_info.st_mode)) {
-          success = HandleDir(entry.d_name,
-                              path,
-                              recursive,
-                              follow_links,
-                              seen,
-                              listing) && success;
+          if (strcmp(entry.d_name, ".") == 0) return Next(listing);
+          if (strcmp(entry.d_name, "..") == 0) return Next(listing);
+          return kListDirectory;
         } else if (S_ISREG(entry_info.st_mode)) {
-          success = HandleFile(entry.d_name,
-                               path,
-                               listing) && success;
+          return kListFile;
         } else if (S_ISLNK(entry_info.st_mode)) {
-          success = HandleLink(entry.d_name,
-                               path,
-                               listing) && success;
+          return kListLink;
         }
-        break;
       }
+
       default:
         break;
     }
-    path->Reset(path_length);
   }
+  done_ = true;
 
   if (status != 0) {
     errno = status;
-    success = false;
-    PostError(listing, path->data);
+    return kListError;
   }
 
-  if (closedir(dir_pointer) == -1) {
-    success = false;
-    PostError(listing, path->data);
+  if (closedir(reinterpret_cast<DIR*>(lister_)) == -1) {
+    return kListError;
   }
 
-  return success;
+  return kListDone;
 }
 
 
+static bool DeleteRecursively(PathBuffer* path);
+
+
 static bool DeleteFile(char* file_name,
                        PathBuffer* path) {
-  return path->Add(file_name) && unlink(path->data) == 0;
+  return path->Add(file_name) && unlink(path->AsString()) == 0;
 }
 
 
@@ -292,10 +216,10 @@
   // Do not recurse into links for deletion. Instead delete the link.
   // If it's a file, delete it.
   struct stat st;
-  if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
+  if (TEMP_FAILURE_RETRY(lstat(path->AsString(), &st)) == -1) {
     return false;
   } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
-    return (unlink(path->data) == 0);
+    return (unlink(path->AsString()) == 0);
   }
 
   if (!path->Add(File::PathSeparator())) return false;
@@ -304,7 +228,7 @@
   // directory.
   DIR* dir_pointer;
   do {
-    dir_pointer = opendir(path->data);
+    dir_pointer = opendir(path->AsString());
   } while (dir_pointer == NULL && errno == EINTR);
 
   if (dir_pointer == NULL) {
@@ -312,7 +236,7 @@
   }
 
   // Iterate the directory and delete all files and directories.
-  int path_length = path->length;
+  int path_length = path->length();
   int read = 0;
   bool success = true;
   dirent entry;
@@ -342,7 +266,8 @@
           success = false;
           break;
         }
-        int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
+        int lstat_success = TEMP_FAILURE_RETRY(
+            lstat(path->AsString(), &entry_info));
         if (lstat_success == -1) {
           success = false;
           break;
@@ -366,26 +291,13 @@
 
   if ((read != 0) ||
       (closedir(dir_pointer) == -1) ||
-      (remove(path->data) == -1)) {
+      (remove(path->AsString()) == -1)) {
     return false;
   }
   return success;
 }
 
 
-bool Directory::List(const char* dir_name,
-                     bool recursive,
-                     bool follow_links,
-                     DirectoryListing *listing) {
-  PathBuffer path;
-  if (!path.Add(dir_name)) {
-    PostError(listing, dir_name);
-    return false;
-  }
-  return ListRecursively(&path, recursive, follow_links, NULL, listing);
-}
-
-
 Directory::ExistsResult Directory::Exists(const char* dir_name) {
   struct stat entry_info;
   int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
@@ -456,9 +368,9 @@
   // The return value must be freed by the caller.
   PathBuffer path;
   path.Add(const_template);
-  if (path.length == 0) {
+  if (path.length() == 0) {
     path.Add("/tmp/temp_dir1_");
-  } else if ((path.data)[path.length - 1] == '/') {
+  } else if ((path.AsString())[path.length() - 1] == '/') {
     path.Add("temp_dir_");
   }
   if (!path.Add("XXXXXX")) {
@@ -467,14 +379,14 @@
   }
   char* result;
   do {
-    result = mkdtemp(path.data);
+    result = mkdtemp(path.AsString());
   } while (result == NULL && errno == EINTR);
   if (result == NULL) {
     return NULL;
   }
-  int length = strnlen(path.data, PATH_MAX);
+  int length = strnlen(path.AsString(), PATH_MAX);
   result = static_cast<char*>(malloc(length + 1));
-  strncpy(result, path.data, length);
+  strncpy(result, path.AsString(), length);
   result[length] = '\0';
   return result;
 }
diff --git a/runtime/bin/directory_macos.cc b/runtime/bin/directory_macos.cc
index 3a9ab04..88e430b 100644
--- a/runtime/bin/directory_macos.cc
+++ b/runtime/bin/directory_macos.cc
@@ -21,41 +21,47 @@
 namespace dart {
 namespace bin {
 
-class PathBuffer {
- public:
-  PathBuffer() : length(0) {
-    data = new char[PATH_MAX + 1];
-  }
 
-  ~PathBuffer() {
-    delete[] data;
-  }
+PathBuffer::PathBuffer() : length_(0) {
+  data_ = new char[PATH_MAX + 1];
+}
 
-  char* data;
-  int length;
+bool PathBuffer::AddW(const wchar_t* name) {
+  UNREACHABLE();
+  return false;
+}
 
-  bool Add(const char* name) {
-    int written = snprintf(data + length,
-                           PATH_MAX - length,
-                           "%s",
-                           name);
-    data[PATH_MAX] = '\0';
-    if (written <= PATH_MAX - length &&
-        written >= 0 &&
-        static_cast<size_t>(written) == strlen(name)) {
-      length += written;
-      return true;
-    } else {
-      errno = ENAMETOOLONG;
-      return false;
-    }
-  }
+char* PathBuffer::AsString() const {
+  return reinterpret_cast<char*>(data_);
+}
 
-  void Reset(int new_length) {
-    length = new_length;
-    data[length] = '\0';
+wchar_t* PathBuffer::AsStringW() const {
+  UNREACHABLE();
+  return NULL;
+}
+
+bool PathBuffer::Add(const char* name) {
+  char* data = AsString();
+  int written = snprintf(data + length_,
+                         PATH_MAX - length_,
+                         "%s",
+                         name);
+  data[PATH_MAX] = '\0';
+  if (written <= PATH_MAX - length_ &&
+      written >= 0 &&
+      static_cast<size_t>(written) == strlen(name)) {
+    length_ += written;
+    return true;
+  } else {
+    errno = ENAMETOOLONG;
+    return false;
   }
-};
+}
+
+void PathBuffer::Reset(int new_length) {
+  length_ = new_length;
+  AsString()[length_] = '\0';
+}
 
 
 // A linked list of symbolic links, with their unique file system identifiers.
@@ -67,110 +73,54 @@
 };
 
 
-// Forward declarations.
-static bool ListRecursively(PathBuffer* path,
-                            bool recursive,
-                            bool follow_links,
-                            LinkList* seen,
-                            DirectoryListing* listing);
-static bool DeleteRecursively(PathBuffer* path);
-
-
-static void PostError(DirectoryListing *listing,
-                      const char* dir_name) {
-  listing->HandleError(dir_name);
-}
-
-
-static bool HandleDir(char* dir_name,
-                      PathBuffer* path,
-                      bool recursive,
-                      bool follow_links,
-                      LinkList* seen,
-                      DirectoryListing *listing) {
-  if (strcmp(dir_name, ".") == 0) return true;
-  if (strcmp(dir_name, "..") == 0) return true;
-  if (!path->Add(dir_name)) {
-    PostError(listing, path->data);
-    return false;
+ListType DirectoryListingEntry::Next(DirectoryListing* listing) {
+  if (done_) {
+    return kListDone;
   }
-  return listing->HandleDirectory(path->data) &&
-      (!recursive ||
-       ListRecursively(path, recursive, follow_links, seen, listing));
-}
 
+  if (lister_ == 0) {
+    if (!listing->path_buffer().Add(File::PathSeparator())) {
+      done_ = true;
+      return kListError;
+    }
+    path_length_ = listing->path_buffer().length();
+    do {
+      lister_ = reinterpret_cast<intptr_t>(
+          opendir(listing->path_buffer().AsString()));
+    } while (lister_ == 0 && errno == EINTR);
 
-static bool HandleFile(char* file_name,
-                       PathBuffer* path,
-                       DirectoryListing *listing) {
-  if (!path->Add(file_name)) {
-    PostError(listing, path->data);
-    return false;
+    if (lister_ == 0) {
+      done_ = true;
+      return kListError;
+    }
   }
-  return listing->HandleFile(path->data);
-}
-
-
-static bool HandleLink(char* link_name,
-                       PathBuffer* path,
-                       DirectoryListing *listing) {
-  if (!path->Add(link_name)) {
-    PostError(listing, path->data);
-    return false;
-  }
-  return listing->HandleLink(path->data);
-}
-
-
-static bool ListRecursively(PathBuffer* path,
-                            bool recursive,
-                            bool follow_links,
-                            LinkList* seen,
-                            DirectoryListing *listing) {
-  if (!path->Add(File::PathSeparator())) {
-    PostError(listing, path->data);
-    return false;
-  }
-  DIR* dir_pointer;
-  do {
-    dir_pointer = opendir(path->data);
-  } while (dir_pointer == NULL && errno == EINTR);
-  if (dir_pointer == NULL) {
-    PostError(listing, path->data);
-    return false;
-  }
+  // Reset.
+  listing->path_buffer().Reset(path_length_);
+  ResetLink();
 
   // Iterate the directory and post the directories and files to the
   // ports.
-  int path_length = path->length;
   int status = 0;
-  bool success = true;
   dirent entry;
   dirent* result;
-  while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
-                                                &entry,
-                                                &result))) == 0 &&
-         result != NULL) {
+  if ((status = TEMP_FAILURE_RETRY(readdir_r(reinterpret_cast<DIR*>(lister_),
+                                    &entry,
+                                    &result))) == 0 &&
+      result != NULL) {
+    if (!listing->path_buffer().Add(entry.d_name)) {
+      done_ = true;
+      return kListError;
+    }
     switch (entry.d_type) {
       case DT_DIR:
-        success = HandleDir(entry.d_name,
-                            path,
-                            recursive,
-                            follow_links,
-                            seen,
-                            listing) && success;
-        break;
+        if (strcmp(entry.d_name, ".") == 0) return Next(listing);
+        if (strcmp(entry.d_name, "..") == 0) return Next(listing);
+        return kListDirectory;
       case DT_REG:
-        success = HandleFile(entry.d_name,
-                             path,
-                             listing) && success;
-        break;
+        return kListFile;
       case DT_LNK:
-        if (!follow_links) {
-          success = HandleLink(entry.d_name,
-                               path,
-                               listing) && success;
-          break;
+        if (!listing->follow_links()) {
+          return kListLink;
         }
         // Else fall through to next case.
         // Fall through.
@@ -180,103 +130,77 @@
         // the actual entry type. Notice that stat returns the type of
         // the file pointed to.
         struct stat entry_info;
-        if (!path->Add(entry.d_name)) {
-          success = false;
-          break;
-        }
         int stat_success;
-        stat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
+        stat_success = TEMP_FAILURE_RETRY(
+            lstat(listing->path_buffer().AsString(), &entry_info));
         if (stat_success == -1) {
-          success = false;
-          PostError(listing, path->data);
-          break;
+          return kListError;
         }
-        if (follow_links && S_ISLNK(entry_info.st_mode)) {
+        if (listing->follow_links() && S_ISLNK(entry_info.st_mode)) {
           // Check to see if we are in a loop created by a symbolic link.
           LinkList current_link = { entry_info.st_dev,
                                     entry_info.st_ino,
-                                    seen };
-          LinkList* previous = seen;
-          bool looping_link = false;
+                                    link_ };
+          LinkList* previous = link_;
           while (previous != NULL) {
             if (previous->dev == current_link.dev &&
                 previous->ino == current_link.ino) {
               // Report the looping link as a link, rather than following it.
-              path->Reset(path_length);
-              success = HandleLink(entry.d_name,
-                                   path,
-                                   listing) && success;
-              looping_link = true;
-              break;
+              return kListLink;
             }
             previous = previous->next;
           }
-          if (looping_link) break;
-          stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
+          stat_success = TEMP_FAILURE_RETRY(
+              stat(listing->path_buffer().AsString(), &entry_info));
           if (stat_success == -1) {
             // Report a broken link as a link, even if follow_links is true.
-            path->Reset(path_length);
-            success = HandleLink(entry.d_name,
-                                 path,
-                                 listing) && success;
-            break;
+            return kListLink;
           }
           if (S_ISDIR(entry_info.st_mode)) {
             // Recurse into the subdirectory with current_link added to the
             // linked list of seen file system links.
-            path->Reset(path_length);
-            success = HandleDir(entry.d_name,
-                                path,
-                                recursive,
-                                follow_links,
-                                &current_link,
-                                listing) && success;
-            break;
+            link_ = new LinkList(current_link);
+            if (strcmp(entry.d_name, ".") == 0) return Next(listing);
+            if (strcmp(entry.d_name, "..") == 0) return Next(listing);
+            return kListDirectory;
           }
         }
-        path->Reset(path_length);
         if (S_ISDIR(entry_info.st_mode)) {
-          success = HandleDir(entry.d_name,
-                              path,
-                              recursive,
-                              follow_links,
-                              seen,
-                              listing) && success;
+          if (strcmp(entry.d_name, ".") == 0) return Next(listing);
+          if (strcmp(entry.d_name, "..") == 0) return Next(listing);
+          return kListDirectory;
         } else if (S_ISREG(entry_info.st_mode)) {
-          success = HandleFile(entry.d_name,
-                               path,
-                               listing) && success;
+          return kListFile;
         } else if (S_ISLNK(entry_info.st_mode)) {
-          success = HandleLink(entry.d_name,
-                               path,
-                               listing) && success;
+          return kListLink;
         }
-        break;
       }
+
       default:
         break;
     }
-    path->Reset(path_length);
   }
+  done_ = true;
 
   if (status != 0) {
     errno = status;
-    success = false;
-    PostError(listing, path->data);
+    return kListError;
   }
 
-  if (closedir(dir_pointer) == -1) {
-    success = false;
-    PostError(listing, path->data);
+  if (closedir(reinterpret_cast<DIR*>(lister_)) == -1) {
+    return kListError;
   }
 
-  return success;
+  return kListDone;
 }
 
 
+static bool DeleteRecursively(PathBuffer* path);
+
+
 static bool DeleteFile(char* file_name,
                        PathBuffer* path) {
-  return path->Add(file_name) && unlink(path->data) == 0;
+  return path->Add(file_name) && unlink(path->AsString()) == 0;
 }
 
 
@@ -292,10 +216,10 @@
   // Do not recurse into links for deletion. Instead delete the link.
   // If it's a file, delete it.
   struct stat st;
-  if (TEMP_FAILURE_RETRY(lstat(path->data, &st)) == -1) {
+  if (TEMP_FAILURE_RETRY(lstat(path->AsString(), &st)) == -1) {
     return false;
   } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
-    return (unlink(path->data) == 0);
+    return (unlink(path->AsString()) == 0);
   }
 
   if (!path->Add(File::PathSeparator())) return false;
@@ -304,7 +228,7 @@
   // directory.
   DIR* dir_pointer;
   do {
-    dir_pointer = opendir(path->data);
+    dir_pointer = opendir(path->AsString());
   } while (dir_pointer == NULL && errno == EINTR);
 
   if (dir_pointer == NULL) {
@@ -312,7 +236,7 @@
   }
 
   // Iterate the directory and delete all files and directories.
-  int path_length = path->length;
+  int path_length = path->length();
   int read = 0;
   bool success = true;
   dirent entry;
@@ -342,7 +266,8 @@
           success = false;
           break;
         }
-        int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
+        int lstat_success = TEMP_FAILURE_RETRY(
+            lstat(path->AsString(), &entry_info));
         if (lstat_success == -1) {
           success = false;
           break;
@@ -366,26 +291,13 @@
 
   if ((read != 0) ||
       (closedir(dir_pointer) == -1) ||
-      (remove(path->data) == -1)) {
+      (remove(path->AsString()) == -1)) {
     return false;
   }
   return success;
 }
 
 
-bool Directory::List(const char* dir_name,
-                     bool recursive,
-                     bool follow_links,
-                     DirectoryListing *listing) {
-  PathBuffer path;
-  if (!path.Add(dir_name)) {
-    PostError(listing, dir_name);
-    return false;
-  }
-  return ListRecursively(&path, recursive, follow_links, NULL, listing);
-}
-
-
 Directory::ExistsResult Directory::Exists(const char* dir_name) {
   struct stat entry_info;
   int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
@@ -445,9 +357,9 @@
   // The return value must be freed by the caller.
   PathBuffer path;
   path.Add(const_template);
-  if (path.length == 0) {
+  if (path.length() == 0) {
     path.Add("/tmp/temp_dir1_");
-  } else if ((path.data)[path.length - 1] == '/') {
+  } else if ((path.AsString())[path.length() - 1] == '/') {
     path.Add("temp_dir_");
   }
   if (!path.Add("XXXXXX")) {
@@ -456,14 +368,14 @@
   }
   char* result;
   do {
-    result = mkdtemp(path.data);
+    result = mkdtemp(path.AsString());
   } while (result == NULL && errno == EINTR);
   if (result == NULL) {
     return NULL;
   }
-  int length = strlen(path.data);
+  int length = strlen(path.AsString());
   result = static_cast<char*>(malloc(length + 1));
-  strncpy(result, path.data, length);
+  strncpy(result, path.AsString(), length);
   result[length] = '\0';
   return result;
 }
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 8f97f0e..9e3cf30 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -19,41 +19,47 @@
 namespace dart {
 namespace bin {
 
-class PathBuffer {
- public:
-  PathBuffer() : length(0) {
-    data = new wchar_t[MAX_PATH + 1];
-  }
+PathBuffer::PathBuffer() : length_(0) {
+  data_ = new wchar_t[MAX_PATH + 1];
+}
 
-  ~PathBuffer() {
-    delete[] data;
-  }
+char* PathBuffer::AsString() const {
+  return StringUtils::WideToUtf8(AsStringW());
+}
 
-  wchar_t* data;
-  int length;
+wchar_t* PathBuffer::AsStringW() const {
+  return reinterpret_cast<wchar_t*>(data_);
+}
 
-  bool Add(const wchar_t* name) {
-    int written = _snwprintf(data + length,
-                             MAX_PATH - length,
-                             L"%s",
-                             name);
-    data[MAX_PATH] = L'\0';
-    if (written <= MAX_PATH - length &&
-        written >= 0 &&
-        static_cast<size_t>(written) == wcsnlen(name, MAX_PATH + 1)) {
-      length += written;
-      return true;
-    } else {
-      SetLastError(ERROR_BUFFER_OVERFLOW);
-      return false;
-    }
-  }
+bool PathBuffer::Add(const char* name) {
+  const wchar_t* wide_name = StringUtils::Utf8ToWide(name);
+  bool success = AddW(wide_name);
+  free(const_cast<wchar_t*>(wide_name));
+  return success;
+}
 
-  void Reset(int new_length) {
-    length = new_length;
-    data[length] = L'\0';
+bool PathBuffer::AddW(const wchar_t* name) {
+  wchar_t* data = AsStringW();
+  int written = _snwprintf(data + length_,
+                           MAX_PATH - length_,
+                           L"%s",
+                           name);
+  data[MAX_PATH] = L'\0';
+  if (written <= MAX_PATH - length_ &&
+      written >= 0 &&
+      static_cast<size_t>(written) == wcsnlen(name, MAX_PATH + 1)) {
+    length_ += written;
+    return true;
+  } else {
+    SetLastError(ERROR_BUFFER_OVERFLOW);
+    return false;
   }
-};
+}
+
+void PathBuffer::Reset(int new_length) {
+  length_ = new_length;
+  AsStringW()[length_] = L'\0';
+}
 
 // If link_name points to a link, IsBrokenLink will return true if link_name
 // points to an invalid target.
@@ -84,96 +90,31 @@
 };
 
 // Forward declarations.
-static bool ListRecursively(PathBuffer* path,
-                            bool recursive,
-                            bool follow_links,
-                            LinkList* seen,
-                            DirectoryListing* listing);
 static bool DeleteRecursively(PathBuffer* path);
 
 
-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,
-                      PathBuffer* path,
-                      bool recursive,
-                      bool follow_links,
-                      LinkList* seen,
-                      DirectoryListing* 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;
+static ListType HandleFindFile(DirectoryListing* listing,
+                               DirectoryListingEntry* entry,
+                               WIN32_FIND_DATAW& find_file_data) {
+  if (!listing->path_buffer().AddW(find_file_data.cFileName)) {
+    return kListError;
   }
-  char* utf8_path = StringUtils::WideToUtf8(path->data);
-  bool ok = listing->HandleDirectory(utf8_path);
-  free(utf8_path);
-  return ok &&
-      (!recursive ||
-       ListRecursively(path, recursive, follow_links, seen, listing));
-}
-
-
-static bool HandleFile(wchar_t* file_name,
-                       PathBuffer* path,
-                       DirectoryListing* listing) {
-  if (!path->Add(file_name)) {
-    PostError(listing, path->data);
-    return false;
-  }
-  char* utf8_path = StringUtils::WideToUtf8(path->data);
-  bool ok = listing->HandleFile(utf8_path);
-  free(utf8_path);
-  return ok;
-}
-
-
-static bool HandleLink(wchar_t* link_name,
-                       PathBuffer* path,
-                       DirectoryListing* listing) {
-  if (!path->Add(link_name)) {
-    PostError(listing, path->data);
-    return false;
-  }
-  char* utf8_path = StringUtils::WideToUtf8(path->data);
-  bool ok = listing->HandleLink(utf8_path);
-  free(utf8_path);
-  return ok;
-}
-
-
-static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data,
-                        PathBuffer* path,
-                        bool recursive,
-                        bool follow_links,
-                        LinkList* seen,
-                        DirectoryListing* listing) {
-  DWORD attributes = find_file_data->dwFileAttributes;
+  DWORD attributes = find_file_data.dwFileAttributes;
   if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
-    if (!follow_links) {
-      return HandleLink(find_file_data->cFileName, path, listing);
+    if (!listing->follow_links()) {
+      return kListLink;
     }
-    int path_length = path->length;
-    if (!path->Add(find_file_data->cFileName)) return false;
     HANDLE handle = CreateFileW(
-        path->data,
+        listing->path_buffer().AsStringW(),
         0,
         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
         NULL,
         OPEN_EXISTING,
         FILE_FLAG_BACKUP_SEMANTICS,
         NULL);
-    path->Reset(path_length);
     if (handle == INVALID_HANDLE_VALUE) {
       // Report as (broken) link.
-      return HandleLink(find_file_data->cFileName, path, listing);
+      return kListLink;
     }
     if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
       // Check the seen link targets to see if we are in a file system loop.
@@ -184,103 +125,99 @@
         DWORD error = GetLastError();
         CloseHandle(handle);
         SetLastError(error);
-        PostError(listing, path->data);
-        return false;
+        return kListError;
       }
       CloseHandle(handle);
       current_link.volume = info.dwVolumeSerialNumber;
       current_link.id_low = info.nFileIndexLow;
       current_link.id_high = info.nFileIndexHigh;
-      current_link.next = seen;
-      LinkList* previous = seen;
+      current_link.next = entry->link();
+      LinkList* previous = entry->link();
       while (previous != NULL) {
         if (previous->volume == current_link.volume &&
             previous->id_low == current_link.id_low &&
             previous->id_high == current_link.id_high) {
           // Report the looping link as a link, rather than following it.
-          return HandleLink(find_file_data->cFileName, path, listing);
+          return kListLink;
         }
         previous = previous->next;
       }
       // Recurse into the directory, adding current link to the seen links list.
-      return HandleDir(find_file_data->cFileName,
-                       path,
-                       recursive,
-                       follow_links,
-                       &current_link,
-                       listing);
+      if (wcscmp(find_file_data.cFileName, L".") == 0 ||
+          wcscmp(find_file_data.cFileName, L"..") == 0) {
+        return entry->Next(listing);
+      }
+      entry->set_link(new LinkList(current_link));
+      return kListDirectory;
     }
   }
   if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
-    return HandleDir(find_file_data->cFileName,
-                     path,
-                     recursive,
-                     follow_links,
-                     seen,
-                     listing);
+    if (wcscmp(find_file_data.cFileName, L".") == 0 ||
+        wcscmp(find_file_data.cFileName, L"..") == 0) {
+      return entry->Next(listing);
+    }
+    return kListDirectory;
   } else {
-    return HandleFile(find_file_data->cFileName, path, listing);
+    return kListFile;
   }
 }
 
-
-static bool ListRecursively(PathBuffer* path,
-                            bool recursive,
-                            bool follow_links,
-                            LinkList* seen,
-                            DirectoryListing* listing) {
-  if (!path->Add(L"\\*")) {
-    PostError(listing, path->data);
-    return false;
+ListType DirectoryListingEntry::Next(DirectoryListing* listing) {
+  if (done_) {
+    return kListDone;
   }
 
   WIN32_FIND_DATAW find_file_data;
-  HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
 
-  // Adjust the path by removing the '*' used for the search.
-  path->Reset(path->length - 1);
+  if (lister_ == 0) {
+    if (!listing->path_buffer().AddW(L"\\*")) {
+      done_ = true;
+      return kListError;
+    }
 
-  if (find_handle == INVALID_HANDLE_VALUE) {
-    PostError(listing, path->data);
-    return false;
+    path_length_ = listing->path_buffer().length() - 1;
+
+    HANDLE find_handle = FindFirstFileW(listing->path_buffer().AsStringW(),
+                                        &find_file_data);
+
+    if (find_handle == INVALID_HANDLE_VALUE) {
+      done_ = true;
+      return kListError;
+    }
+
+    lister_ = reinterpret_cast<intptr_t>(find_handle);
+
+    listing->path_buffer().Reset(path_length_);
+
+    return HandleFindFile(listing, this, find_file_data);
   }
 
-  int path_length = path->length;
-  bool success = HandleEntry(&find_file_data,
-                             path,
-                             recursive,
-                             follow_links,
-                             seen,
-                             listing);
+  // Reset.
+  listing->path_buffer().Reset(path_length_);
+  ResetLink();
 
-  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,
-                          recursive,
-                          follow_links,
-                          seen,
-                          listing) && success;
+  if (FindNextFileW(reinterpret_cast<HANDLE>(lister_), &find_file_data) != 0) {
+    return HandleFindFile(listing, this, find_file_data);
   }
 
+  done_ = true;
+
   if (GetLastError() != ERROR_NO_MORE_FILES) {
-    success = false;
-    PostError(listing, path->data);
+    return kListError;
   }
 
-  if (FindClose(find_handle) == 0) {
-    success = false;
-    PostError(listing, path->data);
+  if (FindClose(reinterpret_cast<HANDLE>(lister_)) == 0) {
+    return kListError;
   }
 
-  return success;
+  return kListDone;
 }
 
 
 static bool DeleteFile(wchar_t* file_name, PathBuffer* path) {
-  if (!path->Add(file_name)) return false;
+  if (!path->AddW(file_name)) return false;
 
-  if (DeleteFileW(path->data) != 0) {
+  if (DeleteFileW(path->AsStringW()) != 0) {
     return true;
   }
 
@@ -288,7 +225,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->data);
+    DWORD attributes = GetFileAttributesW(path->AsStringW());
     if (attributes == INVALID_FILE_ATTRIBUTES) {
       return false;
     }
@@ -296,11 +233,11 @@
     if ((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) {
       attributes &= ~FILE_ATTRIBUTE_READONLY;
 
-      if (SetFileAttributesW(path->data, attributes) == 0) {
+      if (SetFileAttributesW(path->AsStringW(), attributes) == 0) {
         return false;
       }
 
-      return DeleteFileW(path->data) != 0;
+      return DeleteFileW(path->AsStringW()) != 0;
     }
   }
 
@@ -311,7 +248,7 @@
 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);
+  return path->AddW(dir_name) && DeleteRecursively(path);
 }
 
 
@@ -327,7 +264,7 @@
 
 
 static bool DeleteRecursively(PathBuffer* path) {
-  DWORD attributes = GetFileAttributesW(path->data);
+  DWORD attributes = GetFileAttributesW(path->AsStringW());
   if ((attributes == INVALID_FILE_ATTRIBUTES)) {
     return false;
   }
@@ -335,20 +272,20 @@
   // filesystem that we do not want to recurse into.
   if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
     // Just delete the junction itself.
-    return RemoveDirectoryW(path->data) != 0;
+    return RemoveDirectoryW(path->AsStringW()) != 0;
   }
   // If it's a file, remove it directly.
   if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
     return DeleteFile(L"", path);
   }
 
-  if (!path->Add(L"\\*")) return false;
+  if (!path->AddW(L"\\*")) return false;
 
   WIN32_FIND_DATAW find_file_data;
-  HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
+  HANDLE find_handle = FindFirstFileW(path->AsStringW(), &find_file_data);
 
   // Adjust the path by removing the '*' used for the search.
-  int path_length = path->length - 1;
+  int path_length = path->length() - 1;
   path->Reset(path_length);
 
   if (find_handle == INVALID_HANDLE_VALUE) {
@@ -365,7 +302,7 @@
   path->Reset(path_length - 1);  // Drop the "\" from the end of the path.
   if ((GetLastError() != ERROR_NO_MORE_FILES) ||
       (FindClose(find_handle) == 0) ||
-      (RemoveDirectoryW(path->data) == 0)) {
+      (RemoveDirectoryW(path->AsStringW()) == 0)) {
     return false;
   }
 
@@ -373,21 +310,6 @@
 }
 
 
-bool Directory::List(const char* dir_name,
-                     bool recursive,
-                     bool follow_links,
-                     DirectoryListing* listing) {
-  const wchar_t* system_name = StringUtils::Utf8ToWide(dir_name);
-  PathBuffer path;
-  if (!path.Add(system_name)) {
-    PostError(listing, system_name);
-    return false;
-  }
-  free(const_cast<wchar_t*>(system_name));
-  return ListRecursively(&path, recursive, follow_links, NULL, listing);
-}
-
-
 static Directory::ExistsResult ExistsHelper(const wchar_t* dir_name) {
   DWORD attributes = GetFileAttributesW(dir_name);
   if (attributes == INVALID_FILE_ATTRIBUTES) {
@@ -456,22 +378,22 @@
   // The return value must be freed by the caller.
   PathBuffer path;
   if (0 == strncmp(const_template, "", 1)) {
-    path.length = GetTempPathW(MAX_PATH, path.data);
-    if (path.length == 0) {
+    path.Reset(GetTempPathW(MAX_PATH, path.AsStringW()));
+    if (path.length() == 0) {
       return NULL;
     }
   } else {
     const wchar_t* system_template = StringUtils::Utf8ToWide(const_template);
-    path.Add(system_template);
+    path.AddW(system_template);
     free(const_cast<wchar_t*>(system_template));
   }
   // Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44.
-  if (path.length > MAX_PATH - 44) {
+  if (path.length() > MAX_PATH - 44) {
     return NULL;
   }
-  if ((path.data)[path.length - 1] == L'\\') {
+  if ((path.AsStringW())[path.length() - 1] == L'\\') {
     // No base name for the directory - use "tempdir".
-    path.Add(L"tempdir");
+    path.AddW(L"tempdir");
   }
 
   UUID uuid;
@@ -485,14 +407,14 @@
     return NULL;
   }
 
-  path.Add(L"-");
+  path.AddW(L"-");
   // RPC_WSTR is an unsigned short*, so we cast to wchar_t*.
-  path.Add(reinterpret_cast<wchar_t*>(uuid_string));
+  path.AddW(reinterpret_cast<wchar_t*>(uuid_string));
   RpcStringFreeW(&uuid_string);
-  if (!CreateDirectoryW(path.data, NULL)) {
+  if (!CreateDirectoryW(path.AsStringW(), NULL)) {
     return NULL;
   }
-  char* result = StringUtils::WideToUtf8(path.data);
+  char* result = path.AsString();
   return result;
 }
 
@@ -508,7 +430,7 @@
     }
   } else {
     PathBuffer path;
-    if (path.Add(system_dir_name)) {
+    if (path.AddW(system_dir_name)) {
       result = DeleteRecursively(&path);
     }
   }
diff --git a/runtime/bin/native_service.h b/runtime/bin/native_service.h
index ff1b0bf..c001750 100644
--- a/runtime/bin/native_service.h
+++ b/runtime/bin/native_service.h
@@ -6,6 +6,7 @@
 #define BIN_NATIVE_SERVICE_H_
 
 #include "include/dart_api.h"
+#include "include/dart_native_api.h"
 #include "platform/globals.h"
 #include "platform/thread.h"
 
diff --git a/runtime/dart-runtime.gyp b/runtime/dart-runtime.gyp
index 795e3d4..b00105d 100644
--- a/runtime/dart-runtime.gyp
+++ b/runtime/dart-runtime.gyp
@@ -50,8 +50,12 @@
       'sources': [
         'include/dart_api.h',
         'include/dart_debugger_api.h',
+        'include/dart_mirrors_api.h',
+        'include/dart_native_api.h',
         'vm/dart_api_impl.cc',
         'vm/debugger_api_impl.cc',
+        'vm/mirrors_api_impl.cc',
+        'vm/native_api_impl.cc',
         'vm/version.h',
         '<(version_cc_file)',
       ],
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 075ce12..cd09095b 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -65,7 +65,11 @@
 
 #include <assert.h>
 
-/* --- Handles --- */
+/*
+ * =======
+ * Handles
+ * =======
+ */
 
 /**
  * An object reference managed by the Dart VM garbage collector.
@@ -483,7 +487,12 @@
     Dart_WeakPersistentHandle* values,
     intptr_t num_values);
 
-/* --- Garbage Collection Callbacks --- */
+
+/*
+ * ============================
+ * Garbage Collection Callbacks
+ * ============================
+ */
 
 /**
  * Callbacks signal the beginning and end of a garbage collection.
@@ -553,7 +562,12 @@
 DART_EXPORT Dart_Handle Dart_RemoveGcEpilogueCallback(
     Dart_GcEpilogueCallback callback);
 
-/* --- Initialization and Globals --- */
+
+/*
+ * ==========================
+ * Initialization and Globals
+ * ==========================
+ */
 
 /**
  * Gets the version string for the Dart VM.
@@ -744,7 +758,12 @@
  */
 DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name);
 
-/* --- Isolates --- */
+
+/*
+ * ========
+ * Isolates
+ * ========
+ */
 
 /**
  * Creates a new isolate. The new isolate becomes the current isolate.
@@ -865,7 +884,6 @@
 DART_EXPORT Dart_Handle Dart_CreateScriptSnapshot(uint8_t** buffer,
                                                   intptr_t* size);
 
-
 /**
  * Schedules an interrupt for the specified isolate.
  *
@@ -880,7 +898,6 @@
  */
 DART_EXPORT void Dart_InterruptIsolate(Dart_Isolate isolate);
 
-
 /**
  * Make isolate runnable.
  *
@@ -894,7 +911,11 @@
 DART_EXPORT bool Dart_IsolateMakeRunnable(Dart_Isolate isolate);
 
 
-/* --- Messages and Ports --- */
+/*
+ * ==================
+ * Messages and Ports
+ * ==================
+ */
 
 /**
  * A port is used to send or receive inter-isolate messages
@@ -996,7 +1017,12 @@
  */
 DART_EXPORT Dart_Handle Dart_GetReceivePort(Dart_Port port_id);
 
-/* --- Scopes ---- */
+
+/*
+ * ======
+ * Scopes
+ * ======
+ */
 
 /**
  * Enters a new scope.
@@ -1042,7 +1068,12 @@
  */
 DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size);
 
-/* --- Objects ---- */
+
+/*
+ * =======
+ * Objects
+ * =======
+ */
 
 /**
  * Returns the null object.
@@ -1093,7 +1124,39 @@
                                           Dart_Handle type,
                                           bool* instanceof);
 
-/* --- Instances ----
+
+/**
+ * Query object type.
+ *
+ * \param object Some Object.
+ *
+ * \return true if Object is of the specified type.
+ */
+DART_EXPORT bool Dart_IsInstance(Dart_Handle object);
+DART_EXPORT bool Dart_IsNumber(Dart_Handle object);
+DART_EXPORT bool Dart_IsInteger(Dart_Handle object);
+DART_EXPORT bool Dart_IsDouble(Dart_Handle object);
+DART_EXPORT bool Dart_IsBoolean(Dart_Handle object);
+DART_EXPORT bool Dart_IsString(Dart_Handle object);
+DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object);  /* (ISO-8859-1) */
+DART_EXPORT bool Dart_IsExternalString(Dart_Handle object);
+DART_EXPORT bool Dart_IsList(Dart_Handle object);
+DART_EXPORT bool Dart_IsLibrary(Dart_Handle object);
+DART_EXPORT bool Dart_IsClass(Dart_Handle handle);
+DART_EXPORT bool Dart_IsAbstractClass(Dart_Handle handle);
+DART_EXPORT bool Dart_IsFunction(Dart_Handle handle);
+DART_EXPORT bool Dart_IsVariable(Dart_Handle handle);
+DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle);
+DART_EXPORT bool Dart_IsClosure(Dart_Handle object);
+
+
+/*
+ * =========
+ * Instances
+ * =========
+ */
+
+/*
  * For the purposes of the embedding api, not all objects returned are
  * Dart language objects.  Within the api, we use the term 'Instance'
  * to indicate handles which refer to true Dart language objects.
@@ -1102,11 +1165,6 @@
  * any functions that more properly belong here. */
 
 /**
- * Does this handle refer to some Dart language object?
- */
-DART_EXPORT bool Dart_IsInstance(Dart_Handle object);
-
-/**
  * Gets the class for some Dart language object.
  *
  * \param instance Some Dart object.
@@ -1116,19 +1174,12 @@
  */
 DART_EXPORT Dart_Handle Dart_InstanceGetClass(Dart_Handle instance);
 
-/* --- Numbers ---- */
 
-/**
- * Is this object a Number?
+/*
+ * =============================
+ * Numbers, Integers and Doubles
+ * =============================
  */
-DART_EXPORT bool Dart_IsNumber(Dart_Handle object);
-
-/* --- Integers ---- */
-
-/**
- * Is this object an Integer?
- */
-DART_EXPORT bool Dart_IsInteger(Dart_Handle object);
 
 /**
  * Does this Integer fit into a 64-bit signed integer?
@@ -1213,7 +1264,32 @@
 DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer,
                                                  const char** value);
 
-/* --- Booleans ---- */
+/**
+ * Returns a Double with the provided value.
+ *
+ * \param value A double.
+ *
+ * \return The Double object if no error occurs. Otherwise returns
+ *   an error handle.
+ */
+DART_EXPORT Dart_Handle Dart_NewDouble(double value);
+
+/**
+ * Gets the value of a Double
+ *
+ * \param double_obj A Double
+ * \param value Returns the value of the Double.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj, double* value);
+
+
+/*
+ * ========
+ * Booleans
+ * ========
+ */
 
 /**
  * Returns the True object.
@@ -1234,11 +1310,6 @@
 DART_EXPORT Dart_Handle Dart_False();
 
 /**
- * Is this object a Boolean?
- */
-DART_EXPORT bool Dart_IsBoolean(Dart_Handle object);
-
-/**
  * Returns a Boolean with the provided value.
  *
  * \param value true or false.
@@ -1258,44 +1329,12 @@
  */
 DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj, bool* value);
 
-/* --- Doubles --- */
 
-/**
- * Is this object a Double?
+/*
+ * =======
+ * Strings
+ * =======
  */
-DART_EXPORT bool Dart_IsDouble(Dart_Handle object);
-
-/**
- * Returns a Double with the provided value.
- *
- * \param value A double.
- *
- * \return The Double object if no error occurs. Otherwise returns
- *   an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewDouble(double value);
-
-/**
- * Gets the value of a Double
- *
- * \param double_obj A Double
- * \param value Returns the value of the Double.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj, double* value);
-
-/* --- Strings --- */
-
-/**
- * Is this object a String?
- */
-DART_EXPORT bool Dart_IsString(Dart_Handle object);
-
-/**
- * Is this object a Latin-1 (ISO-8859-1) String?
- */
-DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object);
 
 /**
  * Gets the length of a String.
@@ -1359,14 +1398,6 @@
                                                 intptr_t length);
 
 /**
- * Is this object an external String?
- *
- * An external String is a String which references a fixed array of
- * codepoints which is external to the Dart heap.
- */
-DART_EXPORT bool Dart_IsExternalString(Dart_Handle object);
-
-/**
  * Retrieves the peer pointer associated with an external String.
  */
 DART_EXPORT Dart_Handle Dart_ExternalStringGetPeer(Dart_Handle object,
@@ -1512,12 +1543,11 @@
                                                 Dart_PeerFinalizer cback);
 
 
-/* --- Lists --- */
-
-/**
- * Is this object a List?
+/*
+ * =====
+ * Lists
+ * =====
  */
-DART_EXPORT bool Dart_IsList(Dart_Handle object);
 
 /**
  * Returns a List of the desired length.
@@ -1590,7 +1620,12 @@
                                             uint8_t* native_array,
                                             intptr_t length);
 
-/* --- Typed Data --- */
+
+/*
+ * ==========
+ * Typed Data
+ * ==========
+ */
 
 typedef enum {
   Dart_TypedData_kByteData = 0,
@@ -1689,378 +1724,11 @@
 DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object);
 
 
-/* --- Closures --- */
-
-/**
- * Is this object a Closure?
+/*
+ * ============================================================
+ * Invoking Constructors, Methods, Closures and Field accessors
+ * ============================================================
  */
-DART_EXPORT bool Dart_IsClosure(Dart_Handle object);
-
-/**
- * Retrieves the function of a closure.
- *
- * \return A handle to the function of the closure, or an error handle if the
- *   argument is not a closure.
- */
-DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure);
-
-/**
- * Invokes a Closure with the given arguments.
- *
- * May generate an unhandled exception error.
- *
- * \return If no error occurs during execution, then the result of
- *   invoking the closure is returned. If an error occurs during
- *   execution, then an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_InvokeClosure(Dart_Handle closure,
-                                           int number_of_arguments,
-                                           Dart_Handle* arguments);
-
-/* --- Classes and Interfaces --- */
-
-/**
- * Is this a class handle?
- */
-DART_EXPORT bool Dart_IsClass(Dart_Handle handle);
-
-/**
- * Is this an abstract class handle?
- */
-DART_EXPORT bool Dart_IsAbstractClass(Dart_Handle handle);
-
-/**
- * Returns the class name for the provided class or interface.
- */
-DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle clazz);
-
-/**
- * Returns the library for the provided class or interface.
- */
-DART_EXPORT Dart_Handle Dart_ClassGetLibrary(Dart_Handle clazz);
-
-/**
- * Returns the number of interfaces directly implemented by some class
- * or interface.
- *
- * TODO(turnidge): Finish documentation.
- */
-DART_EXPORT Dart_Handle Dart_ClassGetInterfaceCount(Dart_Handle clazz,
-                                                    intptr_t* count);
-
-/**
- * Returns the interface at some index in the list of interfaces some
- * class or inteface.
- *
- * TODO(turnidge): Finish documentation.
- */
-DART_EXPORT Dart_Handle Dart_ClassGetInterfaceAt(Dart_Handle clazz,
-                                                 intptr_t index);
-
-/**
- * Is this class defined by a typedef?
- *
- * Typedef definitions from the main program are represented as a
- * special kind of class handle.  See Dart_ClassGetTypedefReferent.
- *
- * TODO(turnidge): Finish documentation.
- */
-DART_EXPORT bool Dart_ClassIsTypedef(Dart_Handle clazz);
-
-/**
- * Returns a handle to the type to which a typedef refers.
- *
- * It is an error to call this function on a handle for which
- * Dart_ClassIsTypedef is not true.
- *
- * TODO(turnidge): Finish documentation.
- */
-DART_EXPORT Dart_Handle Dart_ClassGetTypedefReferent(Dart_Handle clazz);
-
-/**
- * Does this class represent the type of a function?
- */
-DART_EXPORT bool Dart_ClassIsFunctionType(Dart_Handle clazz);
-
-/**
- * Returns a function handle representing the signature associated
- * with a function type.
- *
- * The return value is a function handle (See Dart_IsFunction, etc.).
- *
- * TODO(turnidge): Finish documentation.
- */
-DART_EXPORT Dart_Handle Dart_ClassGetFunctionTypeSignature(Dart_Handle clazz);
-
-/* --- Function and Variable Declarations --- */
-
-/**
- * Returns a list of the names of all functions or methods declared in
- * a library or class.
- *
- * \param target A library or class.
- *
- * \return If no error occurs, a list of strings is returned.
- *   Otherwise an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_GetFunctionNames(Dart_Handle target);
-
-/**
- * Looks up a function or method declaration by name from a library or
- * class.
- *
- * \param target The library or class containing the function.
- * \param function_name The name of the function.
- *
- * \return If an error is encountered, returns an error handle.
- *   Otherwise returns a function handle if the function is found of
- *   Dart_Null() if the function is not found.
- */
-DART_EXPORT Dart_Handle Dart_LookupFunction(Dart_Handle target,
-                                            Dart_Handle function_name);
-
-/**
- * Is this a function or method declaration handle?
- */
-DART_EXPORT bool Dart_IsFunction(Dart_Handle handle);
-
-/**
- * Returns the name for the provided function or method.
- *
- * \return A valid string handle if no error occurs during the
- *   operation.
- */
-DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function);
-
-/**
- * Returns a handle to the owner of a function.
- *
- * The owner of an instance method or a static method is its defining
- * class. The owner of a top-level function is its defining
- * library. The owner of the function of a non-implicit closure is the
- * function of the method or closure that defines the non-implicit
- * closure.
- *
- * \return A valid handle to the owner of the function, or an error
- *   handle if the argument is not a valid handle to a function.
- */
-DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function);
-
-/**
- * Determines whether a function handle refers to an abstract method.
- *
- * \param function A handle to a function or method declaration.
- * \param is_static Returns whether the handle refers to an abstract method.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_FunctionIsAbstract(Dart_Handle function,
-                                                bool* is_abstract);
-
-/**
- * Determines whether a function handle referes to a static function
- * of method.
- *
- * For the purposes of the embedding API, a top-level function is
- * implicitly declared static.
- *
- * \param function A handle to a function or method declaration.
- * \param is_static Returns whether the function or method is declared static.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
-                                              bool* is_static);
-
-/**
- * Determines whether a function handle referes to a constructor.
- *
- * \param function A handle to a function or method declaration.
- * \param is_static Returns whether the function or method is a constructor.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_FunctionIsConstructor(Dart_Handle function,
-                                                   bool* is_constructor);
-/* TODO(turnidge): Document behavior for factory constructors too. */
-
-/**
- * Determines whether a function or method is a getter.
- *
- * \param function A handle to a function or method declaration.
- * \param is_static Returns whether the function or method is a getter.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_FunctionIsGetter(Dart_Handle function,
-                                              bool* is_getter);
-
-/**
- * Determines whether a function or method is a setter.
- *
- * \param function A handle to a function or method declaration.
- * \param is_static Returns whether the function or method is a setter.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_FunctionIsSetter(Dart_Handle function,
-                                              bool* is_setter);
-
-/**
- * Returns the return type of a function.
- *
- * \return A valid handle to a type or an error handle if the argument
- *   is not valid.
- */
-DART_EXPORT Dart_Handle Dart_FunctionReturnType(Dart_Handle function);
-
-/**
- * Determines the number of required and optional parameters.
- *
- * \param function A handle to a function or method declaration.
- * \param fixed_param_count Returns the number of required parameters.
- * \param opt_param_count Returns the number of optional parameters.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_FunctionParameterCounts(
-  Dart_Handle function,
-  int64_t* fixed_param_count,
-  int64_t* opt_param_count);
-
-/**
- * Returns a handle to the type of a function parameter.
- *
- * \return A valid handle to a type or an error handle if the argument
- *   is not valid.
- */
-DART_EXPORT Dart_Handle Dart_FunctionParameterType(Dart_Handle function,
-                                                   int parameter_index);
-
-/**
- * Returns a list of the names of all variables declared in a library
- * or class.
- *
- * \param target A library or class.
- *
- * \return If no error occurs, a list of strings is returned.
- *   Otherwise an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_GetVariableNames(Dart_Handle target);
-
-/**
- * Looks up a variable declaration by name from a library or class.
- *
- * \param target The library or class containing the variable.
- * \param variable_name The name of the variable.
- *
- * \return If an error is encountered, returns an error handle.
- *   Otherwise returns a variable handle if the variable is found or
- *   Dart_Null() if the variable is not found.
- */
-DART_EXPORT Dart_Handle Dart_LookupVariable(Dart_Handle target,
-                                            Dart_Handle variable_name);
-
-/**
- * Is this a variable declaration handle?
- */
-DART_EXPORT bool Dart_IsVariable(Dart_Handle handle);
-
-/**
- * Returns the name for the provided variable.
- */
-DART_EXPORT Dart_Handle Dart_VariableName(Dart_Handle variable);
-
-/**
- * Determines whether a variable is declared static.
- *
- * For the purposes of the embedding API, a top-level variable is
- * implicitly declared static.
- *
- * \param variable A handle to a variable declaration.
- * \param is_static Returns whether the variable is declared static.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_VariableIsStatic(Dart_Handle variable,
-                                              bool* is_static);
-
-/**
- * Determines whether a variable is declared final.
- *
- * \param variable A handle to a variable declaration.
- * \param is_final Returns whether the variable is declared final.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_VariableIsFinal(Dart_Handle variable,
-                                             bool* is_final);
-
-/**
- * Returns the type of a variable.
- *
- * \return A valid handle to a type of or an error handle if the
- *   argument is not valid.
- */
-DART_EXPORT Dart_Handle Dart_VariableType(Dart_Handle function);
-
-/**
- * Returns a list of the names of all type variables declared in a class.
- *
- * The type variables list preserves the original declaration order.
- *
- * \param clazz A class.
- *
- * \return If no error occurs, a list of strings is returned.
- *   Otherwise an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_GetTypeVariableNames(Dart_Handle clazz);
-
-/**
- * Looks up a type variable declaration by name from a class.
- *
- * \param clazz The class containing the type variable.
- * \param variable_name The name of the type variable.
- *
- * \return If an error is encountered, returns an error handle.
- *   Otherwise returns a type variable handle if the type variable is
- *   found or Dart_Null() if the type variable is not found.
- */
-DART_EXPORT Dart_Handle Dart_LookupTypeVariable(Dart_Handle clazz,
-                                                Dart_Handle type_variable_name);
-
-/**
- * Is this a type variable handle?
- */
-DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle);
-
-/**
- * Returns the name for the provided type variable.
- */
-DART_EXPORT Dart_Handle Dart_TypeVariableName(Dart_Handle type_variable);
-
-/**
- * Returns the owner of a function.
- *
- * The owner of a type variable is its defining class.
- *
- * \return A valid handle to the owner of the type variable, or an error
- *   handle if the argument is not a valid handle to a type variable.
- */
-DART_EXPORT Dart_Handle Dart_TypeVariableOwner(Dart_Handle type_variable);
-
-/**
- * Returns the upper bound of a type variable.
- *
- * The upper bound of a type variable is ...
- *
- * \return A valid handle to a type, or an error handle if the
- *   argument is not a valid handle.
- */
-DART_EXPORT Dart_Handle Dart_TypeVariableUpperBound(Dart_Handle type_variable);
-/* TODO(turnidge): Finish documentation. */
-
-/* --- Constructors, Methods, and Fields --- */
 
 /**
  * Invokes a constructor, creating a new object.
@@ -2113,6 +1781,19 @@
 /* TODO(turnidge): Document how to invoke operators. */
 
 /**
+ * Invokes a Closure with the given arguments.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \return If no error occurs during execution, then the result of
+ *   invoking the closure is returned. If an error occurs during
+ *   execution, then an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_InvokeClosure(Dart_Handle closure,
+                                           int number_of_arguments,
+                                           Dart_Handle* arguments);
+
+/**
  * Gets the value of a field.
  *
  * The 'container' parameter may be an object, class, or library.  If
@@ -2157,39 +1838,14 @@
                                       Dart_Handle name,
                                       Dart_Handle value);
 
-/**
- * Creates a native wrapper class.
- *
- * TODO(turnidge): Document.
- */
-DART_EXPORT Dart_Handle Dart_CreateNativeWrapperClass(Dart_Handle library,
-                                                      Dart_Handle class_name,
-                                                      int field_count);
 
-/**
- * Gets the number of native instance fields in an object.
+/*
+ * ==========
+ * Exceptions
+ * ==========
  */
-DART_EXPORT Dart_Handle Dart_GetNativeInstanceFieldCount(Dart_Handle obj,
-                                                         int* count);
 
-/**
- * Gets the value of a native field.
- *
- * TODO(turnidge): Document.
- */
-DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj,
-                                                    int index,
-                                                    intptr_t* value);
-/**
- * Sets the value of a native field.
- *
- * TODO(turnidge): Document.
- */
-DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj,
-                                                    int index,
-                                                    intptr_t value);
-
-/* --- Exceptions ----
+/*
  * TODO(turnidge): Remove these functions from the api and replace all
  * uses with Dart_NewUnhandledExceptionError. */
 
@@ -2224,7 +1880,45 @@
 DART_EXPORT Dart_Handle Dart_RethrowException(Dart_Handle exception,
                                               Dart_Handle stacktrace);
 
-/* --- Native functions --- */
+
+/*
+ * ===========================
+ * Native fields and functions
+ * ===========================
+ */
+
+/**
+ * Creates a native wrapper class.
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT Dart_Handle Dart_CreateNativeWrapperClass(Dart_Handle library,
+                                                      Dart_Handle class_name,
+                                                      int field_count);
+
+/**
+ * Gets the number of native instance fields in an object.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeInstanceFieldCount(Dart_Handle obj,
+                                                         int* count);
+
+/**
+ * Gets the value of a native field.
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj,
+                                                    int index,
+                                                    intptr_t* value);
+
+/**
+ * Sets the value of a native field.
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj,
+                                                    int index,
+                                                    intptr_t value);
 
 /**
  * The arguments to a native function.
@@ -2274,24 +1968,26 @@
 /* TODO(turnidge): Consider renaming to NativeFunctionResolver or
  * NativeResolver. */
 
-
-/* --- Metadata support --- */
-
 /**
- * Get metadata associated with an object.
+ * Sets the callback used to resolve native functions for a library.
  *
- * \param obj Object for which the metadata is retrieved.
+ * \param library A library.
+ * \param resolver A native entry resolver.
  *
- * \return If no error occurs, returns an array of metadata values.
- *   Returns an empty array if there is no metadata for the object.
- *   Returns an error if the evaluation of the metadata expressions fails.
- *
+ * \return A valid handle if the native resolver was set successfully.
  */
-DART_EXPORT Dart_Handle Dart_GetMetadata(Dart_Handle obj);
+DART_EXPORT Dart_Handle Dart_SetNativeResolver(
+    Dart_Handle library,
+    Dart_NativeEntryResolver resolver);
+/* TODO(turnidge): Rename to Dart_LibrarySetNativeResolver? */
 
 
-/* --- Scripts and Libraries ---
- * TODO(turnidge): Finish documenting this section. */
+/*
+ * =====================
+ * Scripts and Libraries
+ * =====================
+ */
+/* TODO(turnidge): Finish documenting this section. */
 
 typedef enum {
   Dart_kLibraryTag = 0,
@@ -2362,25 +2058,6 @@
 DART_EXPORT Dart_Handle Dart_RootLibrary();
 
 /**
- * Forces all loaded classes and functions to be compiled eagerly in
- * the current isolate..
- *
- * TODO(turnidge): Document.
- */
-DART_EXPORT Dart_Handle Dart_CompileAll();
-
-/**
- * Check that all function fingerprints are OK.
- *
- */
-DART_EXPORT Dart_Handle Dart_CheckFunctionFingerprints();
-
-/**
- * Is this object a Library?
- */
-DART_EXPORT bool Dart_IsLibrary(Dart_Handle object);
-
-/**
  * Lookup a class or interface by name from a Library.
  *
  * \param library The library containing the class or interface.
@@ -2395,24 +2072,10 @@
  * not found to distinguish that from a true error case. */
 
 /**
- * Returns the name of a library as declared in the #library directive.
- */
-DART_EXPORT Dart_Handle Dart_LibraryName(Dart_Handle library);
-
-/**
  * Returns the url from which a library was loaded.
  */
 DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library);
 
-/**
- * Returns a list of the names of all classes and interfaces declared
- * in a library.
- *
- * \return If no error occurs, a list of strings is returned.
- *   Otherwise an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_LibraryGetClassNames(Dart_Handle library);
-
 DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url);
 /* TODO(turnidge): Consider returning Dart_Null() when the library is
  * not found to distinguish that from a true error case. */
@@ -2461,46 +2124,12 @@
                                        Dart_Handle url,
                                        Dart_Handle patch_source);
 
-/**
- * Sets the callback used to resolve native functions for a library.
- *
- * \param library A library.
- * \param resolver A native entry resolver.
- *
- * \return A valid handle if the native resolver was set successfully.
+
+/*
+ * =====
+ * Peers
+ * =====
  */
-DART_EXPORT Dart_Handle Dart_SetNativeResolver(
-    Dart_Handle library,
-    Dart_NativeEntryResolver resolver);
-/* TODO(turnidge): Rename to Dart_LibrarySetNativeResolver? */
-
-/* --- Profiling support ---- */
-
-/* External pprof support for gathering and dumping symbolic
- * information that can be used for better profile reports for
- * dynamically generated code. */
-DART_EXPORT void Dart_InitPprofSupport();
-DART_EXPORT void Dart_GetPprofSymbolInfo(void** buffer, int* buffer_size);
-
-/* Support for generating symbol maps for use by the Linux perf tool. */
-DART_EXPORT void Dart_InitPerfEventsSupport(void* perf_events_file);
-
-/* --- Heap Profiler --- */
-
-/**
- * Generates a heap profile.
- *
- * \param callback A function pointer that will be repeatedly invoked
- *   with heap profile data.
- * \param stream A pointer that will be passed to the callback.  This
- *   is a convenient way to provide an open stream to the callback.
- *
- * \return Success if the heap profile is successful.
- */
-DART_EXPORT Dart_Handle Dart_HeapProfile(Dart_FileWriteCallback callback,
-                                         void* stream);
-
-/* --- Peers --- */
 
 /**
  * The peer field is a lazily allocated field intendend for storage of
@@ -2533,124 +2162,4 @@
  */
 DART_EXPORT Dart_Handle Dart_SetPeer(Dart_Handle object, void* peer);
 
-/* --- Message sending/receiving from native code ---- */
-
-/**
- * A Dart_CObject is used for representing Dart objects as native C
- * data outside the Dart heap. These objects are totally detached from
- * the Dart heap. Only a subset of the Dart objects have a
- * representation as a Dart_CObject.
- *
- * The string encoding in the 'value.as_string' is UTF-8.
- *
- * All the different types from dart:typed_data are exposed as type
- * kTypedData. The specific type from dart:typed_data is in the type
- * field of the as_typed_data structure. The length in the
- * as_typed_data structure is always in bytes.
- */
-typedef enum {
-  Dart_CObject_kNull = 0,
-  Dart_CObject_kBool,
-  Dart_CObject_kInt32,
-  Dart_CObject_kInt64,
-  Dart_CObject_kBigint,
-  Dart_CObject_kDouble,
-  Dart_CObject_kString,
-  Dart_CObject_kArray,
-  Dart_CObject_kTypedData,
-  Dart_CObject_kExternalTypedData,
-  Dart_CObject_kUnsupported,
-  Dart_CObject_kNumberOfTypes
-} Dart_CObject_Type;
-
-typedef struct _Dart_CObject {
-  Dart_CObject_Type type;
-  union {
-    bool as_bool;
-    int32_t as_int32;
-    int64_t as_int64;
-    double as_double;
-    char* as_string;
-    char* as_bigint;
-    struct {
-      int length;
-      struct _Dart_CObject** values;
-    } as_array;
-    struct {
-      Dart_TypedData_Type type;
-      int length;
-      uint8_t* values;
-    } as_typed_data;
-    struct {
-      Dart_TypedData_Type type;
-      int length;
-      uint8_t* data;
-      void* peer;
-      Dart_WeakPersistentHandleFinalizer callback;
-    } as_external_typed_data;
-  } value;
-} Dart_CObject;
-
-/**
- * Posts a message on some port. The message will contain the
- * Dart_CObject object graph rooted in 'message'.
- *
- * While the message is being sent the state of the graph of
- * Dart_CObject structures rooted in 'message' should not be accessed,
- * as the message generation will make temporary modifications to the
- * data. When the message has been sent the graph will be fully
- * restored.
- *
- * \param port_id The destination port.
- * \param message The message to send.
- *
- * \return True if the message was posted.
- */
-DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message);
-
-/**
- * A native message handler.
- *
- * This handler is associated with a native port by calling
- * Dart_NewNativePort.
- *
- * The message received is decoded into the message structure. The
- * lifetime of the message data is controlled by the caller. All the
- * data references from the message are allocated by the caller and
- * will be reclaimed when returning to it.
- */
-
-typedef void (*Dart_NativeMessageHandler)(Dart_Port dest_port_id,
-Dart_Port reply_port_id,
-Dart_CObject* message);
-
-/**
- * Creates a new native port.  When messages are received on this
- * native port, then they will be dispatched to the provided native
- * message handler.
- *
- * \param name The name of this port in debugging messages.
- * \param handler The C handler to run when messages arrive on the port.
- * \param handle_concurrently Is it okay to process requests on this
- *                            native port concurrently?
- *
- * \return If successful, returns the port id for the native port.  In
- *   case of error, returns ILLEGAL_PORT.
- */
-DART_EXPORT Dart_Port Dart_NewNativePort(const char* name,
-                                         Dart_NativeMessageHandler handler,
-                                         bool handle_concurrently);
-/* TODO(turnidge): Currently handle_concurrently is ignored. */
-
-/**
- * Closes the native port with the given id.
- *
- * The port must have been allocated by a call to Dart_NewNativePort.
- *
- * \param native_port_id The id of the native port to close.
- *
- * \return Returns true if the port was closed successfully.
- */
-DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id);
-
 #endif  /* INCLUDE_DART_API_H_ */  /* NOLINT */
diff --git a/runtime/include/dart_mirrors_api.h b/runtime/include/dart_mirrors_api.h
new file mode 100644
index 0000000..60e499a
--- /dev/null
+++ b/runtime/include/dart_mirrors_api.h
@@ -0,0 +1,393 @@
+/*
+ * 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 INCLUDE_DART_MIRRORS_API_H_
+#define INCLUDE_DART_MIRRORS_API_H_
+
+#include "include/dart_api.h"
+
+/*
+ * =================================
+ * Classes and Interfaces Reflection
+ * =================================
+ */
+
+/**
+ * Returns the class name for the provided class or interface.
+ */
+DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle clazz);
+
+/**
+ * Returns the library for the provided class or interface.
+ */
+DART_EXPORT Dart_Handle Dart_ClassGetLibrary(Dart_Handle clazz);
+
+/**
+ * Returns the number of interfaces directly implemented by some class
+ * or interface.
+ *
+ * TODO(turnidge): Finish documentation.
+ */
+DART_EXPORT Dart_Handle Dart_ClassGetInterfaceCount(Dart_Handle clazz,
+                                                    intptr_t* count);
+
+/**
+ * Returns the interface at some index in the list of interfaces some
+ * class or inteface.
+ *
+ * TODO(turnidge): Finish documentation.
+ */
+DART_EXPORT Dart_Handle Dart_ClassGetInterfaceAt(Dart_Handle clazz,
+                                                 intptr_t index);
+
+/**
+ * Is this class defined by a typedef?
+ *
+ * Typedef definitions from the main program are represented as a
+ * special kind of class handle.  See Dart_ClassGetTypedefReferent.
+ *
+ * TODO(turnidge): Finish documentation.
+ */
+DART_EXPORT bool Dart_ClassIsTypedef(Dart_Handle clazz);
+
+/**
+ * Returns a handle to the type to which a typedef refers.
+ *
+ * It is an error to call this function on a handle for which
+ * Dart_ClassIsTypedef is not true.
+ *
+ * TODO(turnidge): Finish documentation.
+ */
+DART_EXPORT Dart_Handle Dart_ClassGetTypedefReferent(Dart_Handle clazz);
+
+/**
+ * Does this class represent the type of a function?
+ */
+DART_EXPORT bool Dart_ClassIsFunctionType(Dart_Handle clazz);
+
+/**
+ * Returns a function handle representing the signature associated
+ * with a function type.
+ *
+ * The return value is a function handle (See Dart_IsFunction, etc.).
+ *
+ * TODO(turnidge): Finish documentation.
+ */
+DART_EXPORT Dart_Handle Dart_ClassGetFunctionTypeSignature(Dart_Handle clazz);
+
+
+/*
+ * =================================
+ * Function and Variables Reflection
+ * =================================
+ */
+
+/**
+ * Returns a list of the names of all functions or methods declared in
+ * a library or class.
+ *
+ * \param target A library or class.
+ *
+ * \return If no error occurs, a list of strings is returned.
+ *   Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_GetFunctionNames(Dart_Handle target);
+
+/**
+ * Looks up a function or method declaration by name from a library or
+ * class.
+ *
+ * \param target The library or class containing the function.
+ * \param function_name The name of the function.
+ *
+ * \return If an error is encountered, returns an error handle.
+ *   Otherwise returns a function handle if the function is found of
+ *   Dart_Null() if the function is not found.
+ */
+DART_EXPORT Dart_Handle Dart_LookupFunction(Dart_Handle target,
+                                            Dart_Handle function_name);
+
+/**
+ * Returns the name for the provided function or method.
+ *
+ * \return A valid string handle if no error occurs during the
+ *   operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function);
+
+/**
+ * Returns a handle to the owner of a function.
+ *
+ * The owner of an instance method or a static method is its defining
+ * class. The owner of a top-level function is its defining
+ * library. The owner of the function of a non-implicit closure is the
+ * function of the method or closure that defines the non-implicit
+ * closure.
+ *
+ * \return A valid handle to the owner of the function, or an error
+ *   handle if the argument is not a valid handle to a function.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function);
+
+/**
+ * Determines whether a function handle refers to an abstract method.
+ *
+ * \param function A handle to a function or method declaration.
+ * \param is_static Returns whether the handle refers to an abstract method.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionIsAbstract(Dart_Handle function,
+                                                bool* is_abstract);
+
+/**
+ * Determines whether a function handle referes to a static function
+ * of method.
+ *
+ * For the purposes of the embedding API, a top-level function is
+ * implicitly declared static.
+ *
+ * \param function A handle to a function or method declaration.
+ * \param is_static Returns whether the function or method is declared static.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
+                                              bool* is_static);
+
+/**
+ * Determines whether a function handle referes to a constructor.
+ *
+ * \param function A handle to a function or method declaration.
+ * \param is_static Returns whether the function or method is a constructor.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionIsConstructor(Dart_Handle function,
+                                                   bool* is_constructor);
+/* TODO(turnidge): Document behavior for factory constructors too. */
+
+/**
+ * Determines whether a function or method is a getter.
+ *
+ * \param function A handle to a function or method declaration.
+ * \param is_static Returns whether the function or method is a getter.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionIsGetter(Dart_Handle function,
+                                              bool* is_getter);
+
+/**
+ * Determines whether a function or method is a setter.
+ *
+ * \param function A handle to a function or method declaration.
+ * \param is_static Returns whether the function or method is a setter.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionIsSetter(Dart_Handle function,
+                                              bool* is_setter);
+
+/**
+ * Returns the return type of a function.
+ *
+ * \return A valid handle to a type or an error handle if the argument
+ *   is not valid.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionReturnType(Dart_Handle function);
+
+/**
+ * Determines the number of required and optional parameters.
+ *
+ * \param function A handle to a function or method declaration.
+ * \param fixed_param_count Returns the number of required parameters.
+ * \param opt_param_count Returns the number of optional parameters.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionParameterCounts(
+  Dart_Handle function,
+  int64_t* fixed_param_count,
+  int64_t* opt_param_count);
+
+/**
+ * Returns a handle to the type of a function parameter.
+ *
+ * \return A valid handle to a type or an error handle if the argument
+ *   is not valid.
+ */
+DART_EXPORT Dart_Handle Dart_FunctionParameterType(Dart_Handle function,
+                                                   int parameter_index);
+
+/**
+ * Returns a list of the names of all variables declared in a library
+ * or class.
+ *
+ * \param target A library or class.
+ *
+ * \return If no error occurs, a list of strings is returned.
+ *   Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_GetVariableNames(Dart_Handle target);
+
+/**
+ * Looks up a variable declaration by name from a library or class.
+ *
+ * \param target The library or class containing the variable.
+ * \param variable_name The name of the variable.
+ *
+ * \return If an error is encountered, returns an error handle.
+ *   Otherwise returns a variable handle if the variable is found or
+ *   Dart_Null() if the variable is not found.
+ */
+DART_EXPORT Dart_Handle Dart_LookupVariable(Dart_Handle target,
+                                            Dart_Handle variable_name);
+
+/**
+ * Returns the name for the provided variable.
+ */
+DART_EXPORT Dart_Handle Dart_VariableName(Dart_Handle variable);
+
+/**
+ * Determines whether a variable is declared static.
+ *
+ * For the purposes of the embedding API, a top-level variable is
+ * implicitly declared static.
+ *
+ * \param variable A handle to a variable declaration.
+ * \param is_static Returns whether the variable is declared static.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_VariableIsStatic(Dart_Handle variable,
+                                              bool* is_static);
+
+/**
+ * Determines whether a variable is declared final.
+ *
+ * \param variable A handle to a variable declaration.
+ * \param is_final Returns whether the variable is declared final.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_VariableIsFinal(Dart_Handle variable,
+                                             bool* is_final);
+
+/**
+ * Returns the type of a variable.
+ *
+ * \return A valid handle to a type of or an error handle if the
+ *   argument is not valid.
+ */
+DART_EXPORT Dart_Handle Dart_VariableType(Dart_Handle function);
+
+/**
+ * Returns a list of the names of all type variables declared in a class.
+ *
+ * The type variables list preserves the original declaration order.
+ *
+ * \param clazz A class.
+ *
+ * \return If no error occurs, a list of strings is returned.
+ *   Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_GetTypeVariableNames(Dart_Handle clazz);
+
+/**
+ * Looks up a type variable declaration by name from a class.
+ *
+ * \param clazz The class containing the type variable.
+ * \param variable_name The name of the type variable.
+ *
+ * \return If an error is encountered, returns an error handle.
+ *   Otherwise returns a type variable handle if the type variable is
+ *   found or Dart_Null() if the type variable is not found.
+ */
+DART_EXPORT Dart_Handle Dart_LookupTypeVariable(Dart_Handle clazz,
+                                                Dart_Handle type_variable_name);
+
+/**
+ * Returns the name for the provided type variable.
+ */
+DART_EXPORT Dart_Handle Dart_TypeVariableName(Dart_Handle type_variable);
+
+/**
+ * Returns the owner of a function.
+ *
+ * The owner of a type variable is its defining class.
+ *
+ * \return A valid handle to the owner of the type variable, or an error
+ *   handle if the argument is not a valid handle to a type variable.
+ */
+DART_EXPORT Dart_Handle Dart_TypeVariableOwner(Dart_Handle type_variable);
+
+/**
+ * Returns the upper bound of a type variable.
+ *
+ * The upper bound of a type variable is ...
+ *
+ * \return A valid handle to a type, or an error handle if the
+ *   argument is not a valid handle.
+ */
+DART_EXPORT Dart_Handle Dart_TypeVariableUpperBound(Dart_Handle type_variable);
+/* TODO(turnidge): Finish documentation. */
+
+
+/*
+ * ====================
+ * Libraries Reflection
+ * ====================
+ */
+
+/**
+ * Returns the name of a library as declared in the #library directive.
+ */
+DART_EXPORT Dart_Handle Dart_LibraryName(Dart_Handle library);
+
+/**
+ * Returns a list of the names of all classes and interfaces declared
+ * in a library.
+ *
+ * \return If no error occurs, a list of strings is returned.
+ *   Otherwise an error handle is returned.
+ */
+DART_EXPORT Dart_Handle Dart_LibraryGetClassNames(Dart_Handle library);
+
+
+/*
+ * ===================
+ * Closures Reflection
+ * ===================
+ */
+
+/**
+ * Retrieves the function of a closure.
+ *
+ * \return A handle to the function of the closure, or an error handle if the
+ *   argument is not a closure.
+ */
+DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure);
+
+/*
+ * ===================
+ * Metadata Reflection
+ * ===================
+ */
+
+/**
+ * Get metadata associated with an object.
+ *
+ * \param obj Object for which the metadata is retrieved.
+ *
+ * \return If no error occurs, returns an array of metadata values.
+ *   Returns an empty array if there is no metadata for the object.
+ *   Returns an error if the evaluation of the metadata expressions fails.
+ *
+ */
+DART_EXPORT Dart_Handle Dart_GetMetadata(Dart_Handle obj);
+
+#endif  /* INCLUDE_DART_MIRRORS_API_H_ */  /* NOLINT */
diff --git a/runtime/include/dart_native_api.h b/runtime/include/dart_native_api.h
new file mode 100644
index 0000000..7691d5c
--- /dev/null
+++ b/runtime/include/dart_native_api.h
@@ -0,0 +1,193 @@
+/*
+ * 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 INCLUDE_DART_NATIVE_API_H_
+#define INCLUDE_DART_NATIVE_API_H_
+
+#include "include/dart_api.h"
+
+/*
+ * ==========================================
+ * Message sending/receiving from native code
+ * ==========================================
+ */
+
+/**
+ * A Dart_CObject is used for representing Dart objects as native C
+ * data outside the Dart heap. These objects are totally detached from
+ * the Dart heap. Only a subset of the Dart objects have a
+ * representation as a Dart_CObject.
+ *
+ * The string encoding in the 'value.as_string' is UTF-8.
+ *
+ * All the different types from dart:typed_data are exposed as type
+ * kTypedData. The specific type from dart:typed_data is in the type
+ * field of the as_typed_data structure. The length in the
+ * as_typed_data structure is always in bytes.
+ */
+typedef enum {
+  Dart_CObject_kNull = 0,
+  Dart_CObject_kBool,
+  Dart_CObject_kInt32,
+  Dart_CObject_kInt64,
+  Dart_CObject_kBigint,
+  Dart_CObject_kDouble,
+  Dart_CObject_kString,
+  Dart_CObject_kArray,
+  Dart_CObject_kTypedData,
+  Dart_CObject_kExternalTypedData,
+  Dart_CObject_kUnsupported,
+  Dart_CObject_kNumberOfTypes
+} Dart_CObject_Type;
+
+typedef struct _Dart_CObject {
+  Dart_CObject_Type type;
+  union {
+    bool as_bool;
+    int32_t as_int32;
+    int64_t as_int64;
+    double as_double;
+    char* as_string;
+    char* as_bigint;
+    struct {
+      int length;
+      struct _Dart_CObject** values;
+    } as_array;
+    struct {
+      Dart_TypedData_Type type;
+      int length;
+      uint8_t* values;
+    } as_typed_data;
+    struct {
+      Dart_TypedData_Type type;
+      int length;
+      uint8_t* data;
+      void* peer;
+      Dart_WeakPersistentHandleFinalizer callback;
+    } as_external_typed_data;
+  } value;
+} Dart_CObject;
+
+/**
+ * Posts a message on some port. The message will contain the
+ * Dart_CObject object graph rooted in 'message'.
+ *
+ * While the message is being sent the state of the graph of
+ * Dart_CObject structures rooted in 'message' should not be accessed,
+ * as the message generation will make temporary modifications to the
+ * data. When the message has been sent the graph will be fully
+ * restored.
+ *
+ * \param port_id The destination port.
+ * \param message The message to send.
+ *
+ * \return True if the message was posted.
+ */
+DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message);
+
+/**
+ * A native message handler.
+ *
+ * This handler is associated with a native port by calling
+ * Dart_NewNativePort.
+ *
+ * The message received is decoded into the message structure. The
+ * lifetime of the message data is controlled by the caller. All the
+ * data references from the message are allocated by the caller and
+ * will be reclaimed when returning to it.
+ */
+
+typedef void (*Dart_NativeMessageHandler)(Dart_Port dest_port_id,
+Dart_Port reply_port_id,
+Dart_CObject* message);
+
+/**
+ * Creates a new native port.  When messages are received on this
+ * native port, then they will be dispatched to the provided native
+ * message handler.
+ *
+ * \param name The name of this port in debugging messages.
+ * \param handler The C handler to run when messages arrive on the port.
+ * \param handle_concurrently Is it okay to process requests on this
+ *                            native port concurrently?
+ *
+ * \return If successful, returns the port id for the native port.  In
+ *   case of error, returns ILLEGAL_PORT.
+ */
+DART_EXPORT Dart_Port Dart_NewNativePort(const char* name,
+                                         Dart_NativeMessageHandler handler,
+                                         bool handle_concurrently);
+/* TODO(turnidge): Currently handle_concurrently is ignored. */
+
+/**
+ * Closes the native port with the given id.
+ *
+ * The port must have been allocated by a call to Dart_NewNativePort.
+ *
+ * \param native_port_id The id of the native port to close.
+ *
+ * \return Returns true if the port was closed successfully.
+ */
+DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id);
+
+
+/*
+ * =================
+ * Profiling support
+ * =================
+ */
+
+/* External pprof support for gathering and dumping symbolic
+ * information that can be used for better profile reports for
+ * dynamically generated code. */
+DART_EXPORT void Dart_InitPprofSupport();
+DART_EXPORT void Dart_GetPprofSymbolInfo(void** buffer, int* buffer_size);
+
+/* Support for generating symbol maps for use by the Linux perf tool. */
+DART_EXPORT void Dart_InitPerfEventsSupport(void* perf_events_file);
+
+
+/*
+ * =============
+ * Heap Profiler
+ * =============
+ */
+
+/**
+ * Generates a heap profile.
+ *
+ * \param callback A function pointer that will be repeatedly invoked
+ *   with heap profile data.
+ * \param stream A pointer that will be passed to the callback.  This
+ *   is a convenient way to provide an open stream to the callback.
+ *
+ * \return Success if the heap profile is successful.
+ */
+DART_EXPORT Dart_Handle Dart_HeapProfile(Dart_FileWriteCallback callback,
+                                         void* stream);
+
+
+/*
+ * ==================
+ * Verification Tools
+ * ==================
+ */
+
+/**
+ * Forces all loaded classes and functions to be compiled eagerly in
+ * the current isolate..
+ *
+ * TODO(turnidge): Document.
+ */
+DART_EXPORT Dart_Handle Dart_CompileAll();
+
+/**
+ * Check that all function fingerprints are OK.
+ *
+ */
+DART_EXPORT Dart_Handle Dart_CheckFunctionFingerprints();
+
+#endif  /* INCLUDE_DART_NATIVE_API_H_ */  /* NOLINT */
diff --git a/runtime/lib/event_loop_patch.dart b/runtime/lib/event_loop_patch.dart
index c4b25b7..fe04c06 100644
--- a/runtime/lib/event_loop_patch.dart
+++ b/runtime/lib/event_loop_patch.dart
@@ -5,6 +5,6 @@
 patch class _AsyncRun {
   /* patch */ static void _enqueueImmediate(void callback()) {
     // TODO(9001): don't use the Timer to enqueue the immediate callback.
-    Timer.run(callback);
+    _createTimer(Duration.ZERO, callback);
   }
 }
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index a6ea151..7825319 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -4,6 +4,7 @@
 
 #include "include/dart_api.h"
 #include "include/dart_debugger_api.h"
+#include "include/dart_mirrors_api.h"
 #include "vm/dart_api_impl.h"
 #include "vm/bootstrap_natives.h"
 #include "vm/dart_entry.h"
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index cb18187..407060b 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -253,55 +253,6 @@
       native 'LocalObjectMirrorImpl_setField';
 }
 
-// Prints a string as it might appear in dart program text.
-// TODO(turnidge): Consider truncating.
-String _dartEscape(String str) {
-  bool isNice(int code) => (code >= 32 && code <= 126);
-
-  StringBuffer buf = new StringBuffer();
-  for (int i = 0; i < str.length; i++) {
-    var input = str[i];
-    String output;
-    switch (input) {
-      case '\\' :
-        output = r'\\';
-        break;
-      case "\'" :
-        output = r"\'";
-        break;
-      case '\n' :
-        output = r'\n';
-        break;
-      case '\r' :
-        output = r'\r';
-        break;
-      case '\f' :
-        output = r'\f';
-        break;
-      case '\b' :
-        output = r'\b';
-        break;
-      case '\t' :
-        output = r'\t';
-        break;
-      case '\v' :
-        output = r'\v';
-        break;
-      default:
-        // TODO(lrn): Someone decide if this should combine surrogate pairs.
-        int code = input.codeUnitAt(0);
-        if (isNice(code)) {
-          output = input;
-        } else {
-          output = '\\u{${code.toRadixString(16)}}';
-        }
-        break;
-    }
-    buf.write(output);
-  }
-  return buf.toString();
-}
-
 class _LocalInstanceMirrorImpl extends _LocalObjectMirrorImpl
     implements InstanceMirror {
   // TODO(ahe): This is a hack, see delegate below.
@@ -340,17 +291,7 @@
     return _invokeOnClosure(reflectee, invocation);
   }
 
-  String toString() {
-    if (_isSimpleValue(_reflectee)) {
-      if (_reflectee is String) {
-        return "InstanceMirror on <'${_dartEscape(_reflectee)}'>";
-      } else {
-        return "InstanceMirror on <$_reflectee>";
-      }
-    } else {
-      return "InstanceMirror on instance of '${type.simpleName}'";
-    }
-  }
+  String toString() => 'InstanceMirror on ${Error.safeToString(_reflectee)}';
 }
 
 class _LocalClosureMirrorImpl extends _LocalInstanceMirrorImpl
@@ -402,6 +343,8 @@
 
   static _apply(ref, positionalArguments, async)
       native 'LocalClosureMirrorImpl_apply';
+
+  String toString() => "ClosureMirror on '${Error.safeToString(_reflectee)}'";
 }
 
 class _LazyTypeMirror {
@@ -568,7 +511,10 @@
         'ClassMirror.originalDeclaration is not implemented');
   }
 
-  String toString() => "ClassMirror on '$simpleName'";
+  String toString() {
+    String prettyName = isClass ? 'ClassMirror' : 'TypeMirror';
+    return "$prettyName on '${_n(simpleName)}'";
+  }
 
   InstanceMirror newInstance(Symbol constructorName,
                              List positionalArguments,
@@ -653,7 +599,7 @@
 
   final List<ParameterMirror> parameters;
 
-  String toString() => "FunctionTypeMirror on '$simpleName'";
+  String toString() => "FunctionTypeMirror on '${_n(simpleName)}'";
 }
 
 
@@ -716,7 +662,7 @@
   // reflect() and then make them into a Dart list
   List<InstanceMirror> get metadata => _metadata(this).map(reflect).toList();
 
-  String toString() => "TypeVariableMirror on '$simpleName'";
+  String toString() => "TypeVariableMirror on '${_n(simpleName)}'";
 }
 
 
@@ -762,7 +708,7 @@
     return _referent;
   }
 
-  String toString() => "TypedefMirror on '$simpleName'";
+  String toString() => "TypedefMirror on '${_n(simpleName)}'";
 }
 
 
@@ -859,7 +805,7 @@
   // reflect() and then make them into a Dart list
   List<InstanceMirror> get metadata => _metadata(this).map(reflect).toList();
 
-  String toString() => "LibraryMirror on '$simpleName'";
+  String toString() => "LibraryMirror on '${_n(simpleName)}'";
 }
 
 class _LocalMethodMirrorImpl extends _LocalMirrorImpl
@@ -966,7 +912,7 @@
     return _metadata(this).map(reflect).toList();
   }
 
-  String toString() => "MethodMirror on '$simpleName'";
+  String toString() => "MethodMirror on '${_n(simpleName)}'";
 }
 
 class _LocalVariableMirrorImpl extends _LocalMirrorImpl
@@ -1027,7 +973,7 @@
     return _metadata(this).map(reflect).toList();
   }
 
-  String toString() => "VariableMirror on '$simpleName'";
+  String toString() => "VariableMirror on '${_n(simpleName)}'";
 }
 
 class _LocalParameterMirrorImpl extends _LocalVariableMirrorImpl
diff --git a/runtime/lib/timer_patch.dart b/runtime/lib/timer_patch.dart
index 2db2343..87026b1 100644
--- a/runtime/lib/timer_patch.dart
+++ b/runtime/lib/timer_patch.dart
@@ -2,27 +2,26 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-patch class Timer {
-  /* patch */ factory Timer(Duration duration, void callback()) {
-    if (_TimerFactory._factory == null) {
-      throw new UnsupportedError("Timer interface not supported.");
-    }
-    int milliseconds = duration.inMilliseconds;
-    if (milliseconds < 0) milliseconds = 0;
-    return _TimerFactory._factory(milliseconds, (_) { callback(); }, false);
+patch Timer _createTimer(Duration duration, void callback()) {
+  if (_TimerFactory._factory == null) {
+    throw new UnsupportedError("Timer interface not supported.");
   }
-
-  /* patch */ factory Timer.periodic(Duration duration,
-                                     void callback(Timer timer)) {
-    if (_TimerFactory._factory == null) {
-      throw new UnsupportedError("Timer interface not supported.");
-    }
-    int milliseconds = duration.inMilliseconds;
-    if (milliseconds < 0) milliseconds = 0;
-    return _TimerFactory._factory(milliseconds, callback, true);
-  }
+  int milliseconds = duration.inMilliseconds;
+  if (milliseconds < 0) milliseconds = 0;
+  return _TimerFactory._factory(milliseconds, (_) { callback(); }, false);
 }
 
+patch Timer _createPeriodicTimer(Duration duration,
+                                 void callback(Timer timer)) {
+  if (_TimerFactory._factory == null) {
+    throw new UnsupportedError("Timer interface not supported.");
+  }
+  int milliseconds = duration.inMilliseconds;
+  if (milliseconds < 0) milliseconds = 0;
+  return _TimerFactory._factory(milliseconds, callback, true);
+}
+
+
 typedef Timer _TimerFactoryClosure(int milliseconds,
                                    void callback(Timer timer),
                                    bool repeating);
diff --git a/runtime/tests/vm/dart/isolate_mirror_local_test.dart b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
index 39f5948..1ec7093 100644
--- a/runtime/tests/vm/dart/isolate_mirror_local_test.dart
+++ b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
@@ -351,7 +351,7 @@
   Expect.equals(const Symbol('int'), mirror.type.simpleName);
   Expect.isTrue(mirror.hasReflectee);
   Expect.equals(1001, mirror.reflectee);
-  Expect.equals("InstanceMirror on <1001>", mirror.toString());
+  Expect.equals("InstanceMirror on 1001", mirror.toString());
 
   // Invoke (mirror + mirror).
   mirror.invokeAsync(const Symbol('+'), [ mirror ]).then(
@@ -367,7 +367,7 @@
   Expect.equals(const Symbol('String'), mirror.type.simpleName);
   Expect.isTrue(mirror.hasReflectee);
   Expect.equals('This\nis\na\nString', mirror.reflectee);
-  Expect.equals("InstanceMirror on <'This\\nis\\na\\nString'>",
+  Expect.equals('InstanceMirror on "This\\nis\\na\\nString"',
                 mirror.toString());
 
   // Invoke mirror[0].
@@ -384,7 +384,7 @@
   Expect.equals(const Symbol('bool'), mirror.type.simpleName);
   Expect.isTrue(mirror.hasReflectee);
   Expect.equals(true, mirror.reflectee);
-  Expect.equals("InstanceMirror on <true>", mirror.toString());
+  Expect.equals("InstanceMirror on true", mirror.toString());
   testDone('testBoolInstanceMirror');
 }
 
@@ -393,7 +393,7 @@
   Expect.equals(const Symbol('Object'), mirror.type.simpleName);
   Expect.isTrue(mirror.hasReflectee);
   Expect.equals(null, mirror.reflectee);
-  Expect.equals("InstanceMirror on <null>", mirror.toString());
+  Expect.equals("InstanceMirror on null", mirror.toString());
   testDone('testNullInstanceMirror');
 }
 
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 3b35560..55e0f44 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -10,6 +10,7 @@
 #include "vm/heap.h"
 #include "vm/memory_region.h"
 #include "vm/runtime_entry.h"
+#include "vm/stack_frame.h"
 #include "vm/stub_code.h"
 
 namespace dart {
@@ -2188,15 +2189,16 @@
 
 
 void Assembler::EnterDartFrame(intptr_t frame_size) {
-  const intptr_t offset = CodeSize();
   EnterFrame(0);
   Label dart_entry;
   call(&dart_entry);
   Bind(&dart_entry);
-  // Adjust saved PC for any intrinsic code that could have been generated
-  // before a frame is created.
+  // The runtime system assumes that the code marker address is
+  // kEntryPointToPcMarkerOffset bytes from the entry.  If there is any code
+  // generated before entering the frame, the address needs to be adjusted.
+  const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize();
   if (offset != 0) {
-    addl(Address(ESP, 0), Immediate(-offset));
+    addl(Address(ESP, 0), Immediate(offset));
   }
   if (frame_size != 0) {
     subl(ESP, Immediate(frame_size));
@@ -2204,6 +2206,29 @@
 }
 
 
+// On entry to a function compiled for OSR, the caller's frame pointer, the
+// stack locals, and any copied parameters are already in place.  The frame
+// pointer is already set up.  The PC marker is not correct for the
+// optimized function and there may be extra space for spill slots to
+// allocate.
+void Assembler::EnterOsrFrame(intptr_t extra_size) {
+  Label dart_entry;
+  call(&dart_entry);
+  Bind(&dart_entry);
+  // The runtime system assumes that the code marker address is
+  // kEntryPointToPcMarkerOffset bytes from the entry.  Since there is no
+  // code to set up the frame pointer, the address needs to be adjusted.
+  const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize();
+  if (offset != 0) {
+    addl(Address(ESP, 0), Immediate(offset));
+  }
+  popl(Address(EBP, kPcMarkerSlotFromFp * kWordSize));
+  if (extra_size != 0) {
+    subl(ESP, Immediate(extra_size));
+  }
+}
+
+
 void Assembler::EnterStubFrame() {
   EnterFrame(0);
   pushl(Immediate(0));  // Push 0 in the saved PC area for stub frames.
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 7ed62a8..df68c46 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -714,6 +714,11 @@
   //   .....
   void EnterDartFrame(intptr_t frame_size);
 
+  // Set up a Dart frame for a function compiled for on-stack replacement.
+  // The frame layout is a normal Dart frame, but the frame is partially set
+  // up on entry (it is the frame of the unoptimized code).
+  void EnterOsrFrame(intptr_t extra_size);
+
   // Set up a stub frame so that the stack traversal code can easily identify
   // a stub frame.
   // The stub frame layout is as follows:
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index 8f43046..f4f3de1 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -346,14 +346,14 @@
     // Setup pool pointer for this stub.
     Label next;
     bal(&next);
-    delay_slot()->mov(T0, RA);
+    delay_slot()->mov(TMP1, RA);
 
     const intptr_t object_pool_pc_dist =
         Instructions::HeaderSize() - Instructions::object_pool_offset() +
         CodeSize();
 
     Bind(&next);
-    lw(PP, Address(T0, -object_pool_pc_dist));
+    lw(PP, Address(TMP1, -object_pool_pc_dist));
   } else {
     addiu(SP, SP, Immediate(-3 * kWordSize));
     sw(ZR, Address(SP, 2 * kWordSize));  // PC marker is 0 in stubs.
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 9b22f3e..0b74365 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -67,6 +67,9 @@
     return Utils::IsInt(kImmBits, offset);
   }
 
+  Register base() const { return base_; }
+  int32_t offset() const { return offset_; }
+
  private:
   Register base_;
   int32_t offset_;
@@ -439,6 +442,12 @@
     EmitRType(SPECIAL2, rs, rd, rd, 0, CLZ);
   }
 
+  // Convert a 32-bit float in fs to a 64-bit double in dd.
+  void cvtds(DRegister dd, FRegister fs) {
+    FRegister fd = static_cast<FRegister>(dd * 2);
+    EmitFpuRType(COP1, FMT_S, F0, fs, fd, COP1_CVT_D);
+  }
+
   // Converts a 32-bit signed int in fs to a double in fd.
   void cvtdw(DRegister dd, FRegister fs) {
     FRegister fd = static_cast<FRegister>(dd * 2);
@@ -553,10 +562,20 @@
     EmitFpuRType(COP1, FMT_D, F0, fs, fd, COP1_MOV);
   }
 
+  // Move if floating point false.
+  void movf(Register rd, Register rs) {
+    EmitRType(SPECIAL, rs, R0, rd, 0, MOVCI);
+  }
+
   void movn(Register rd, Register rs, Register rt) {
     EmitRType(SPECIAL, rs, rt, rd, 0, MOVN);
   }
 
+  // Move if floating point true.
+  void movt(Register rd, Register rs) {
+    EmitRType(SPECIAL, rs, R1, rd, 0, MOVCI);
+  }
+
   void movz(Register rd, Register rs, Register rt) {
     EmitRType(SPECIAL, rs, rt, rd, 0, MOVZ);
   }
@@ -972,6 +991,20 @@
     sra(reg, reg, kSmiTagSize);
   }
 
+  void StoreDToOffset(DRegister reg, Register base, int32_t offset) {
+    FRegister lo = static_cast<FRegister>(reg * 2);
+    FRegister hi = static_cast<FRegister>(reg * 2 + 1);
+    swc1(lo, Address(base, offset));
+    swc1(hi, Address(base, offset + kWordSize));
+  }
+
+  void LoadDFromOffset(DRegister reg, Register base, int32_t offset) {
+    FRegister lo = static_cast<FRegister>(reg * 2);
+    FRegister hi = static_cast<FRegister>(reg * 2 + 1);
+    lwc1(lo, Address(base, offset));
+    lwc1(hi, Address(base, offset + kWordSize));
+  }
+
   void ReserveAlignedFrameSpace(intptr_t frame_space);
 
   // Create a frame for calling into runtime that preserves all volatile
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 2385749..c1d90db 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -9,6 +9,7 @@
 #include "vm/heap.h"
 #include "vm/memory_region.h"
 #include "vm/runtime_entry.h"
+#include "vm/stack_frame.h"
 #include "vm/stub_code.h"
 
 namespace dart {
@@ -2279,15 +2280,16 @@
 
 
 void Assembler::EnterDartFrame(intptr_t frame_size) {
-  const intptr_t offset = CodeSize();
   EnterFrame(0);
   Label dart_entry;
   call(&dart_entry);
   Bind(&dart_entry);
-  // Adjust saved PC for any intrinsic code that could have been generated
-  // before a frame is created.
+  // The runtime system assumes that the code marker address is
+  // kEntryPointToPcMarkerOffset bytes from the entry.  If there is any code
+  // generated before entering the frame, the address needs to be adjusted.
+  const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize();
   if (offset != 0) {
-    addq(Address(RSP, 0), Immediate(-offset));
+    addq(Address(RSP, 0), Immediate(offset));
   }
   if (frame_size != 0) {
     subq(RSP, Immediate(frame_size));
@@ -2295,6 +2297,29 @@
 }
 
 
+// On entry to a function compiled for OSR, the caller's frame pointer, the
+// stack locals, and any copied parameters are already in place.  The frame
+// pointer is already set up.  The PC marker is not correct for the
+// optimized function and there may be extra space for spill slots to
+// allocate.
+void Assembler::EnterOsrFrame(intptr_t extra_size) {
+  Label dart_entry;
+  call(&dart_entry);
+  Bind(&dart_entry);
+  // The runtime system assumes that the code marker address is
+  // kEntryPointToPcMarkerOffset bytes from the entry.  Since there is no
+  // code to set up the frame pointer, the address needs to be adjusted.
+  const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize();
+  if (offset != 0) {
+    addq(Address(RSP, 0), Immediate(offset));
+  }
+  popq(Address(RBP, kPcMarkerSlotFromFp * kWordSize));
+  if (extra_size != 0) {
+    subq(RSP, Immediate(extra_size));
+  }
+}
+
+
 void Assembler::EnterStubFrame() {
   EnterFrame(0);
   pushq(Immediate(0));  // Push 0 in the saved PC area for stub frames.
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index c213506..919b1c5 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -735,6 +735,11 @@
   //   .....
   void EnterDartFrame(intptr_t frame_size);
 
+  // Set up a Dart frame for a function compiled for on-stack replacement.
+  // The frame layout is a normal Dart frame, but the frame is partially set
+  // up on entry (it is the frame of the unoptimized code).
+  void EnterOsrFrame(intptr_t extra_size);
+
   // Set up a stub frame so that the stack traversal code can easily identify
   // a stub frame.
   // The stub frame layout is as follows:
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 68e167f..6eec38d 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -54,6 +54,13 @@
 DEFINE_FLAG(int, max_subtype_cache_entries, 100,
     "Maximum number of subtype cache entries (number of checks cached).");
 
+#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
+DEFINE_FLAG(bool, use_osr, true, "Use on-stack replacement.");
+#else
+DEFINE_FLAG(bool, use_osr, false, "Use on-stack replacement.");
+#endif
+DEFINE_FLAG(bool, trace_osr, false, "Trace attempts at on-stack replacement.");
+
 
 DEFINE_RUNTIME_ENTRY(TraceFunctionEntry, 1) {
   ASSERT(arguments.ArgCount() ==
@@ -1265,6 +1272,39 @@
       (*callback)();
     }
   }
+
+  if (FLAG_use_osr && (interrupt_bits == 0)) {
+    DartFrameIterator iterator;
+    StackFrame* frame = iterator.NextFrame();
+    const Function& function = Function::Handle(frame->LookupDartFunction());
+    ASSERT(!function.IsNull());
+    if (!function.is_optimizable()) return;
+    intptr_t osr_id =
+        Code::Handle(function.unoptimized_code()).GetDeoptIdForOsr(frame->pc());
+    if (FLAG_trace_osr) {
+      OS::Print("Attempting OSR for %s at id=%"Pd"\n",
+                function.ToFullyQualifiedCString(),
+                osr_id);
+    }
+
+    const Code& original_code = Code::Handle(function.CurrentCode());
+    const Error& error =
+        Error::Handle(Compiler::CompileOptimizedFunction(function, osr_id));
+    if (!error.IsNull()) Exceptions::PropagateError(error);
+
+    const Code& optimized_code = Code::Handle(function.CurrentCode());
+    // The current code will not be changed in the case that the compiler
+    // bailed out during OSR compilation.
+    if (optimized_code.raw() != original_code.raw()) {
+      // The OSR code does not work for calling the function, so restore the
+      // unoptimized code.  Patch the stack frame to return into the OSR
+      // code.
+      uword optimized_entry =
+          Instructions::Handle(optimized_code.instructions()).EntryPoint();
+      function.SetCode(original_code);
+      frame->set_pc(optimized_entry);
+    }
+  }
 }
 
 
@@ -1328,9 +1368,8 @@
     }
     const Code& optimized_code = Code::Handle(function.CurrentCode());
     ASSERT(!optimized_code.IsNull());
-    // Set usage counter for reoptimization.
-    function.set_usage_counter(
-        function.usage_counter() - FLAG_reoptimization_counter_threshold);
+    // Reset usage counter for reoptimization.
+    function.set_usage_counter(0);
   } else {
     if (FLAG_trace_failed_optimization_attempts) {
       OS::PrintErr("Not Optimizable: %s\n", function.ToFullyQualifiedCString());
diff --git a/runtime/vm/code_patcher_mips.cc b/runtime/vm/code_patcher_mips.cc
index 96088fd..5cd9108 100644
--- a/runtime/vm/code_patcher_mips.cc
+++ b/runtime/vm/code_patcher_mips.cc
@@ -47,7 +47,9 @@
 
 
 void CodePatcher::InsertCallAt(uword start, uword target) {
-  UNIMPLEMENTED();
+  // The inserted call should not overlap the lazy deopt jump code.
+  ASSERT(start + CallPattern::kFixedLengthInBytes <= target);
+  CallPattern::InsertAt(start, target);
 }
 
 
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index a0f5306..0fba07c 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -12,7 +12,6 @@
 #include "vm/dart_entry.h"
 #include "vm/debugger.h"
 #include "vm/deopt_instructions.h"
-#include "vm/disassembler.h"
 #include "vm/exceptions.h"
 #include "vm/flags.h"
 #include "vm/flow_graph.h"
@@ -241,7 +240,8 @@
 
 // Return false if bailed out.
 static bool CompileParsedFunctionHelper(ParsedFunction* parsed_function,
-                                        bool optimized) {
+                                        bool optimized,
+                                        intptr_t osr_id) {
   const Function& function = parsed_function->function();
   if (optimized && !function.is_optimizable()) {
     return false;
@@ -281,13 +281,18 @@
       // Build the flow graph.
       FlowGraphBuilder builder(parsed_function,
                                ic_data_array,
-                               NULL);  // NULL = not inlining.
+                               NULL,  // NULL = not inlining.
+                               osr_id);
       flow_graph = builder.BuildGraph();
     }
 
     if (FLAG_print_flow_graph ||
         (optimized && FLAG_print_flow_graph_optimized)) {
-      FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph);
+      if (osr_id == Isolate::kNoDeoptId) {
+        FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph);
+      } else {
+        FlowGraphPrinter::PrintGraph("For OSR", flow_graph);
+      }
     }
 
     if (optimized) {
@@ -508,12 +513,14 @@
       graph_compiler.FinalizeStaticCallTargetsTable(code);
 
       if (optimized) {
-        CodePatcher::PatchEntry(Code::Handle(function.CurrentCode()));
-        function.SetCode(code);
-        if (FLAG_trace_compiler) {
-          OS::Print("--> patching entry %#"Px"\n",
-                    Code::Handle(function.unoptimized_code()).EntryPoint());
+        if (osr_id == Isolate::kNoDeoptId) {
+          CodePatcher::PatchEntry(Code::Handle(function.CurrentCode()));
+          if (FLAG_trace_compiler) {
+            OS::Print("--> patching entry %#"Px"\n",
+                      Code::Handle(function.unoptimized_code()).EntryPoint());
+          }
         }
+        function.SetCode(code);
 
         for (intptr_t i = 0; i < guarded_fields.length(); i++) {
           const Field& field = *guarded_fields[i];
@@ -551,12 +558,7 @@
             optimized ? "optimized " : "",
             function_fullname);
   const Code& code = Code::Handle(function.CurrentCode());
-  const Instructions& instructions =
-      Instructions::Handle(code.instructions());
-  uword start = instructions.EntryPoint();
-  Disassembler::Disassemble(start,
-                            start + instructions.size(),
-                            code.comments());
+  code.Disassemble();
   OS::Print("}\n");
 
   OS::Print("Pointer offsets for function: {\n");
@@ -576,6 +578,7 @@
       PcDescriptors::Handle(code.pc_descriptors());
   OS::Print("%s}\n", descriptors.ToCString());
 
+  uword start = Instructions::Handle(code.instructions()).EntryPoint();
   const Array& deopt_table = Array::Handle(code.deopt_info_array());
   intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
   if (deopt_table_length > 0) {
@@ -675,7 +678,8 @@
 
 
 static RawError* CompileFunctionHelper(const Function& function,
-                                       bool optimized) {
+                                       bool optimized,
+                                       intptr_t osr_id) {
   Isolate* isolate = Isolate::Current();
   StackZone zone(isolate);
   LongJump* base = isolate->long_jump_base();
@@ -694,7 +698,8 @@
     ParsedFunction* parsed_function = new ParsedFunction(
         Function::ZoneHandle(function.raw()));
     if (FLAG_trace_compiler) {
-      OS::Print("Compiling %sfunction: '%s' @ token %"Pd", size %"Pd"\n",
+      OS::Print("Compiling %s%sfunction: '%s' @ token %"Pd", size %"Pd"\n",
+                (osr_id == Isolate::kNoDeoptId ? "" : "osr "),
                 (optimized ? "optimized " : ""),
                 function.ToFullyQualifiedCString(),
                 function.token_pos(),
@@ -707,7 +712,7 @@
     }
 
     const bool success =
-        CompileParsedFunctionHelper(parsed_function, optimized);
+        CompileParsedFunctionHelper(parsed_function, optimized, osr_id);
     if (optimized && !success) {
       // Optimizer bailed out. Disable optimizations and to never try again.
       if (FLAG_trace_compiler) {
@@ -759,12 +764,13 @@
 
 
 RawError* Compiler::CompileFunction(const Function& function) {
-  return CompileFunctionHelper(function, false);  // Non-optimized.
+  return CompileFunctionHelper(function, false, Isolate::kNoDeoptId);
 }
 
 
-RawError* Compiler::CompileOptimizedFunction(const Function& function) {
-  return CompileFunctionHelper(function, true);  // Optimized.
+RawError* Compiler::CompileOptimizedFunction(const Function& function,
+                                             intptr_t osr_id) {
+  return CompileFunctionHelper(function, true, osr_id);
 }
 
 
@@ -776,7 +782,7 @@
   isolate->set_long_jump_base(&jump);
   if (setjmp(*jump.Set()) == 0) {
     // Non-optimized code generator.
-    CompileParsedFunctionHelper(parsed_function, false);
+    CompileParsedFunctionHelper(parsed_function, false, Isolate::kNoDeoptId);
     if (FLAG_disassemble) {
       DisassembleCode(parsed_function->function(), false);
     }
@@ -863,7 +869,7 @@
     parsed_function->AllocateVariables();
 
     // Non-optimized code generator.
-    CompileParsedFunctionHelper(parsed_function, false);
+    CompileParsedFunctionHelper(parsed_function, false, Isolate::kNoDeoptId);
 
     const Object& result = Object::Handle(
         DartEntry::InvokeFunction(func, Object::empty_array()));
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index 352ac4f..ab49c80 100644
--- a/runtime/vm/compiler.h
+++ b/runtime/vm/compiler.h
@@ -44,7 +44,9 @@
   // Generates optimized code for function.
   //
   // Returns Error::null() if there is no compilation error.
-  static RawError* CompileOptimizedFunction(const Function& function);
+  static RawError* CompileOptimizedFunction(
+      const Function& function,
+      intptr_t osr_id = Isolate::kNoDeoptId);
 
   // Generates code for given parsed function (without parsing it again) and
   // sets its code field.
diff --git a/runtime/vm/constants_mips.h b/runtime/vm/constants_mips.h
index e016f7b..b1f910a 100644
--- a/runtime/vm/constants_mips.h
+++ b/runtime/vm/constants_mips.h
@@ -156,9 +156,13 @@
   kNoDRegister = -1,
 };
 
+const DRegister DTMP = D9;
+const FRegister STMP1 = F18;
+const FRegister STMP2 = F19;
+
 // Architecture independent aliases.
 typedef DRegister FpuRegister;
-const FpuRegister FpuTMP = D0;
+const FpuRegister FpuTMP = DTMP;
 const int kNumberOfFpuRegisters = kNumberOfDRegisters;
 const FpuRegister kNoFpuRegister = kNoDRegister;
 
@@ -172,13 +176,6 @@
 const Register SPREG = SP;  // Stack pointer register.
 const Register FPREG = FP;  // Frame pointer register.
 
-// NULLREG holds reinterpret_cast<intptr_t>(Object::null()).
-// TODO(zra): Is it worthwhile to devote a register to this? Investigate
-// performance effects when we are running on real hardware. Same with
-// CMPRES. Try moving CTX and PP to T8 and T9 and shifting kLastCpuRegister
-// down to S7.
-const Register NULLREG = T8;
-
 // The code that generates a comparison can be far away from the code that
 // generates the branch that uses the result of that comparison. In this case,
 // CMPRES is used for the result of the comparison.
diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc
index 70fb4c7..a32c36e9 100644
--- a/runtime/vm/custom_isolate_test.cc
+++ b/runtime/vm/custom_isolate_test.cc
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "include/dart_api.h"
+#include "include/dart_native_api.h"
 
 #include "vm/unit_test.h"
 
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 323e4f0..176407c 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "include/dart_api.h"
+#include "include/dart_mirrors_api.h"
+#include "include/dart_native_api.h"
 
 #include "platform/assert.h"
 #include "vm/bigint_operations.h"
@@ -18,8 +20,8 @@
 #include "vm/flags.h"
 #include "vm/growable_array.h"
 #include "vm/message.h"
+#include "vm/message_handler.h"
 #include "vm/native_entry.h"
-#include "vm/native_message_handler.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
 #include "vm/port.h"
@@ -51,37 +53,23 @@
 }
 
 
-#define RETURN_TYPE_ERROR(isolate, dart_handle, type)                          \
-  do {                                                                         \
-    const Object& tmp =                                                        \
-        Object::Handle(isolate, Api::UnwrapHandle((dart_handle)));             \
-    if (tmp.IsNull()) {                                                        \
-      return Api::NewError("%s expects argument '%s' to be non-null.",         \
-                           CURRENT_FUNC, #dart_handle);                        \
-    } else if (tmp.IsError()) {                                                \
-      return dart_handle;                                                      \
-    } else {                                                                   \
-      return Api::NewError("%s expects argument '%s' to be of type %s.",       \
-                           CURRENT_FUNC, #dart_handle, #type);                 \
-    }                                                                          \
-  } while (0)
-
-
-#define RETURN_NULL_ERROR(parameter)                                           \
-  return Api::NewError("%s expects argument '%s' to be non-null.",             \
-                       CURRENT_FUNC, #parameter);
-
-
-#define CHECK_LENGTH(length, max_elements)                                     \
-  do {                                                                         \
-    intptr_t len = (length);                                                   \
-    intptr_t max = (max_elements);                                             \
-    if (len < 0 || len > max) {                                                \
-      return Api::NewError(                                                    \
-          "%s expects argument '%s' to be in the range [0..%"Pd"].",           \
-          CURRENT_FUNC, #length, max);                                         \
-    }                                                                          \
-  } while (0)
+static RawInstance* GetListInstance(Isolate* isolate, const Object& obj) {
+  if (obj.IsInstance()) {
+    const Instance& instance = Instance::Cast(obj);
+    const Class& obj_class = Class::Handle(isolate, obj.clazz());
+    const Class& list_class =
+        Class::Handle(isolate, isolate->object_store()->list_class());
+    Error& malformed_type_error = Error::Handle(isolate);
+    if (obj_class.IsSubtypeOf(TypeArguments::Handle(isolate),
+                              list_class,
+                              TypeArguments::Handle(isolate),
+                              &malformed_type_error)) {
+      ASSERT(malformed_type_error.IsNull());  // Type is a raw List.
+      return instance.raw();
+    }
+  }
+  return Instance::null();
+}
 
 
 Dart_Handle Api::NewHandle(Isolate* isolate, RawObject* raw) {
@@ -92,6 +80,7 @@
   return reinterpret_cast<Dart_Handle>(ref);
 }
 
+
 RawObject* Api::UnwrapHandle(Dart_Handle object) {
 #if defined(DEBUG)
   Isolate* isolate = Isolate::Current();
@@ -108,6 +97,7 @@
   return (reinterpret_cast<LocalHandle*>(object))->raw();
 }
 
+
 #define DEFINE_UNWRAP(type)                                                    \
   const type& Api::Unwrap##type##Handle(Isolate* iso,                          \
                                         Dart_Handle dart_handle) {             \
@@ -267,36 +257,8 @@
 }
 
 
-// When we want to return a handle to a type to the user, we handle
-// class-types differently than some other types.
-static Dart_Handle TypeToHandle(Isolate* isolate,
-                                const char* function_name,
-                                const AbstractType& type) {
-  if (type.IsMalformed()) {
-    const Error& error = Error::Handle(type.malformed_error());
-    return Api::NewError("%s: malformed type encountered: %s.",
-        function_name, error.ToErrorCString());
-  } else if (type.HasResolvedTypeClass()) {
-    const Class& cls = Class::Handle(isolate, type.type_class());
-#if defined(DEBUG)
-    const Library& lib = Library::Handle(cls.library());
-    if (lib.IsNull()) {
-      ASSERT(cls.IsDynamicClass() || cls.IsVoidClass());
-    }
-#endif
-    return Api::NewHandle(isolate, cls.raw());
-  } else if (type.IsTypeParameter()) {
-    return Api::NewHandle(isolate, type.raw());
-  } else {
-    return Api::NewError("%s: unexpected type '%s' encountered.",
-                         function_name, type.ToCString());
-  }
-}
-
-
 // --- Handles ---
 
-
 DART_EXPORT bool Dart_IsError(Dart_Handle handle) {
   return RawObject::IsErrorClassId(Api::ClassId(handle));
 }
@@ -674,7 +636,6 @@
 
 // --- Garbage Collection Callbacks --
 
-
 DART_EXPORT Dart_Handle Dart_AddGcPrologueCallback(
     Dart_GcPrologueCallback callback) {
   Isolate* isolate = Isolate::Current();
@@ -737,17 +698,6 @@
 }
 
 
-DART_EXPORT Dart_Handle Dart_HeapProfile(Dart_FileWriteCallback callback,
-                                         void* stream) {
-  Isolate* isolate = Isolate::Current();
-  CHECK_ISOLATE(isolate);
-  if (callback == NULL) {
-    RETURN_NULL_ERROR(callback);
-  }
-  isolate->heap()->Profile(callback, stream);
-  return Api::Success();
-}
-
 // --- Initialization and Globals ---
 
 DART_EXPORT const char* Dart_VersionString() {
@@ -787,7 +737,6 @@
 
 // --- Isolates ---
 
-
 static char* BuildIsolateName(const char* script_uri,
                               const char* main) {
   if (script_uri == NULL) {
@@ -1049,34 +998,6 @@
 }
 
 
-DART_EXPORT bool Dart_PostIntArray(Dart_Port port_id,
-                                   intptr_t len,
-                                   intptr_t* data) {
-  uint8_t* buffer = NULL;
-  ApiMessageWriter writer(&buffer, &allocator);
-  writer.WriteMessage(len, data);
-
-  // Post the message at the given port.
-  return PortMap::PostMessage(new Message(
-      port_id, Message::kIllegalPort, buffer, writer.BytesWritten(),
-      Message::kNormalPriority));
-}
-
-
-DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message) {
-  uint8_t* buffer = NULL;
-  ApiMessageWriter writer(&buffer, allocator);
-  bool success = writer.WriteCMessage(message);
-
-  if (!success) return success;
-
-  // Post the message at the given port.
-  return PortMap::PostMessage(new Message(
-      port_id, Message::kIllegalPort, buffer, writer.BytesWritten(),
-      Message::kNormalPriority));
-}
-
-
 DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle handle) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
@@ -1090,38 +1011,6 @@
 }
 
 
-DART_EXPORT Dart_Port Dart_NewNativePort(const char* name,
-                                         Dart_NativeMessageHandler handler,
-                                         bool handle_concurrently) {
-  if (name == NULL) {
-    name = "<UnnamedNativePort>";
-  }
-  if (handler == NULL) {
-    OS::PrintErr("%s expects argument 'handler' to be non-null.\n",
-                 CURRENT_FUNC);
-    return ILLEGAL_PORT;
-  }
-  // Start the native port without a current isolate.
-  IsolateSaver saver(Isolate::Current());
-  Isolate::SetCurrent(NULL);
-
-  NativeMessageHandler* nmh = new NativeMessageHandler(name, handler);
-  Dart_Port port_id = PortMap::CreatePort(nmh);
-  nmh->Run(Dart::thread_pool(), NULL, NULL, 0);
-  return port_id;
-}
-
-
-DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id) {
-  // Close the native port without a current isolate.
-  IsolateSaver saver(Isolate::Current());
-  Isolate::SetCurrent(NULL);
-
-  // TODO(turnidge): Check that the port is native before trying to close.
-  return PortMap::ClosePort(native_port_id);
-}
-
-
 DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
@@ -1164,8 +1053,8 @@
   return isolate->main_port();
 }
 
-// --- Scopes ----
 
+// --- Scopes ----
 
 DART_EXPORT void Dart_EnterScope() {
   Isolate* isolate = Isolate::Current();
@@ -1209,7 +1098,6 @@
 
 // --- Objects ----
 
-
 DART_EXPORT Dart_Handle Dart_Null() {
   Isolate* isolate = Isolate::Current();
   CHECK_ISOLATE_SCOPE(isolate);
@@ -1286,9 +1174,6 @@
 }
 
 
-// --- Instances ----
-
-
 DART_EXPORT bool Dart_IsInstance(Dart_Handle object) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
@@ -1297,6 +1182,104 @@
 }
 
 
+DART_EXPORT bool Dart_IsNumber(Dart_Handle object) {
+  return RawObject::IsNumberClassId(Api::ClassId(object));
+}
+
+
+DART_EXPORT bool Dart_IsInteger(Dart_Handle object) {
+  return RawObject::IsIntegerClassId(Api::ClassId(object));
+}
+
+
+DART_EXPORT bool Dart_IsDouble(Dart_Handle object) {
+  return Api::ClassId(object) == kDoubleCid;
+}
+
+
+DART_EXPORT bool Dart_IsBoolean(Dart_Handle object) {
+  return Api::ClassId(object) == kBoolCid;
+}
+
+
+DART_EXPORT bool Dart_IsString(Dart_Handle object) {
+  return RawObject::IsStringClassId(Api::ClassId(object));
+}
+
+
+DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object) {
+  return RawObject::IsOneByteStringClassId(Api::ClassId(object));
+}
+
+
+DART_EXPORT bool Dart_IsExternalString(Dart_Handle object) {
+  return RawObject::IsExternalStringClassId(Api::ClassId(object));
+}
+
+
+DART_EXPORT bool Dart_IsList(Dart_Handle object) {
+  if (RawObject::IsBuiltinListClassId(Api::ClassId(object))) {
+    return true;
+  }
+
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+  return GetListInstance(isolate, obj) != Instance::null();
+}
+
+
+DART_EXPORT bool Dart_IsLibrary(Dart_Handle object) {
+  return Api::ClassId(object) == kLibraryCid;
+}
+
+
+DART_EXPORT bool Dart_IsClass(Dart_Handle handle) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle));
+  return obj.IsClass();
+}
+
+
+DART_EXPORT bool Dart_IsAbstractClass(Dart_Handle handle) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle));
+  if (obj.IsClass()) {
+    return Class::Cast(obj).is_abstract();
+  }
+  return false;
+}
+
+
+DART_EXPORT bool Dart_IsFunction(Dart_Handle handle) {
+  return Api::ClassId(handle) == kFunctionCid;
+}
+
+
+DART_EXPORT bool Dart_IsVariable(Dart_Handle handle) {
+  return Api::ClassId(handle) == kFieldCid;
+}
+
+
+DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle) {
+  return Api::ClassId(handle) == kTypeParameterCid;
+}
+
+
+DART_EXPORT bool Dart_IsClosure(Dart_Handle object) {
+  // We can't use a fast class index check here because there are many
+  // different signature classes for closures.
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Instance& closure_obj = Api::UnwrapInstanceHandle(isolate, object);
+  return (!closure_obj.IsNull() && closure_obj.IsClosure());
+}
+
+
+// --- Instances ----
+
 // TODO(turnidge): Technically, null has a class.  Should we allow it?
 DART_EXPORT Dart_Handle Dart_InstanceGetClass(Dart_Handle instance) {
   Isolate* isolate = Isolate::Current();
@@ -1309,21 +1292,7 @@
 }
 
 
-// --- Numbers ----
-
-
-DART_EXPORT bool Dart_IsNumber(Dart_Handle object) {
-  return RawObject::IsNumberClassId(Api::ClassId(object));
-}
-
-
-// --- Integers ----
-
-
-DART_EXPORT bool Dart_IsInteger(Dart_Handle object) {
-  return RawObject::IsIntegerClassId(Api::ClassId(object));
-}
-
+// --- Numbers, Integers and Doubles ----
 
 DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer,
                                                   bool* fits) {
@@ -1486,9 +1455,29 @@
 }
 
 
-// --- Booleans ----
+DART_EXPORT Dart_Handle Dart_NewDouble(double value) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  CHECK_CALLBACK_STATE(isolate);
+  return Api::NewHandle(isolate, Double::New(value));
+}
 
 
+DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj,
+                                         double* value) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Double& obj = Api::UnwrapDoubleHandle(isolate, double_obj);
+  if (obj.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, double_obj, Double);
+  }
+  *value = obj.value();
+  return Api::Success();
+}
+
+
+// --- Booleans ----
+
 DART_EXPORT Dart_Handle Dart_True() {
   Isolate* isolate = Isolate::Current();
   CHECK_ISOLATE_SCOPE(isolate);
@@ -1503,11 +1492,6 @@
 }
 
 
-DART_EXPORT bool Dart_IsBoolean(Dart_Handle object) {
-  return Api::ClassId(object) == kBoolCid;
-}
-
-
 DART_EXPORT Dart_Handle Dart_NewBoolean(bool value) {
   Isolate* isolate = Isolate::Current();
   CHECK_ISOLATE_SCOPE(isolate);
@@ -1528,48 +1512,9 @@
 }
 
 
-// --- Doubles ---
-
-
-DART_EXPORT bool Dart_IsDouble(Dart_Handle object) {
-  return Api::ClassId(object) == kDoubleCid;
-}
-
-
-DART_EXPORT Dart_Handle Dart_NewDouble(double value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  return Api::NewHandle(isolate, Double::New(value));
-}
-
-
-DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj,
-                                         double* value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Double& obj = Api::UnwrapDoubleHandle(isolate, double_obj);
-  if (obj.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, double_obj, Double);
-  }
-  *value = obj.value();
-  return Api::Success();
-}
-
-
 // --- Strings ---
 
 
-DART_EXPORT bool Dart_IsString(Dart_Handle object) {
-  return RawObject::IsStringClassId(Api::ClassId(object));
-}
-
-
-DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object) {
-  return RawObject::IsOneByteStringClassId(Api::ClassId(object));
-}
-
-
 DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* len) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
@@ -1636,11 +1581,6 @@
 }
 
 
-DART_EXPORT bool Dart_IsExternalString(Dart_Handle object) {
-  return RawObject::IsExternalStringClassId(Api::ClassId(object));
-}
-
-
 DART_EXPORT Dart_Handle Dart_ExternalStringGetPeer(Dart_Handle object,
                                                    void** peer) {
   if (peer == NULL) {
@@ -1863,38 +1803,6 @@
 
 // --- Lists ---
 
-
-static RawInstance* GetListInstance(Isolate* isolate, const Object& obj) {
-  if (obj.IsInstance()) {
-    const Instance& instance = Instance::Cast(obj);
-    const Class& obj_class = Class::Handle(isolate, obj.clazz());
-    const Class& list_class =
-        Class::Handle(isolate, isolate->object_store()->list_class());
-    Error& malformed_type_error = Error::Handle(isolate);
-    if (obj_class.IsSubtypeOf(TypeArguments::Handle(isolate),
-                              list_class,
-                              TypeArguments::Handle(isolate),
-                              &malformed_type_error)) {
-      ASSERT(malformed_type_error.IsNull());  // Type is a raw List.
-      return instance.raw();
-    }
-  }
-  return Instance::null();
-}
-
-
-DART_EXPORT bool Dart_IsList(Dart_Handle object) {
-  if (RawObject::IsBuiltinListClassId(Api::ClassId(object))) {
-    return true;
-  }
-
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
-  return GetListInstance(isolate, obj) != Instance::null();
-}
-
-
 DART_EXPORT Dart_Handle Dart_NewList(intptr_t length) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
@@ -2358,7 +2266,6 @@
 
 // --- Typed Data ---
 
-
 // Helper method to get the type of a TypedData object.
 static Dart_TypedData_Type GetType(intptr_t class_id) {
   Dart_TypedData_Type type;
@@ -2750,840 +2657,7 @@
 }
 
 
-// --- Closures ---
-
-
-DART_EXPORT bool Dart_IsClosure(Dart_Handle object) {
-  // We can't use a fast class index check here because there are many
-  // different signature classes for closures.
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Instance& closure_obj = Api::UnwrapInstanceHandle(isolate, object);
-  return (!closure_obj.IsNull() && closure_obj.IsClosure());
-}
-
-
-DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Instance& closure_obj = Api::UnwrapInstanceHandle(isolate, closure);
-  if (closure_obj.IsNull() || !closure_obj.IsClosure()) {
-    RETURN_TYPE_ERROR(isolate, closure, Instance);
-  }
-
-  ASSERT(ClassFinalizer::AllClassesFinalized());
-
-  RawFunction* rf = Closure::function(closure_obj);
-  return Api::NewHandle(isolate, rf);
-}
-
-
-DART_EXPORT Dart_Handle Dart_InvokeClosure(Dart_Handle closure,
-                                           int number_of_arguments,
-                                           Dart_Handle* arguments) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  const Instance& closure_obj = Api::UnwrapInstanceHandle(isolate, closure);
-  if (closure_obj.IsNull() || !closure_obj.IsCallable(NULL, NULL)) {
-    RETURN_TYPE_ERROR(isolate, closure, Instance);
-  }
-  if (number_of_arguments < 0) {
-    return Api::NewError(
-        "%s expects argument 'number_of_arguments' to be non-negative.",
-        CURRENT_FUNC);
-  }
-  ASSERT(ClassFinalizer::AllClassesFinalized());
-
-  // Set up arguments to include the closure as the first argument.
-  const Array& args = Array::Handle(isolate,
-                                    Array::New(number_of_arguments + 1));
-  Object& obj = Object::Handle(isolate);
-  args.SetAt(0, closure_obj);
-  for (int i = 0; i < number_of_arguments; i++) {
-    obj = Api::UnwrapHandle(arguments[i]);
-    if (!obj.IsNull() && !obj.IsInstance()) {
-      RETURN_TYPE_ERROR(isolate, arguments[i], Instance);
-    }
-    args.SetAt(i + 1, obj);
-  }
-  // Now try to invoke the closure.
-  return Api::NewHandle(isolate, DartEntry::InvokeClosure(args));
-}
-
-
-// --- Classes ---
-
-
-DART_EXPORT bool Dart_IsClass(Dart_Handle handle) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle));
-  return obj.IsClass();
-}
-
-
-DART_EXPORT bool Dart_IsAbstractClass(Dart_Handle handle) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle));
-  if (obj.IsClass()) {
-    return Class::Cast(obj).is_abstract();
-  }
-  return false;
-}
-
-
-DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle clazz) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
-  if (cls.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, clazz, Class);
-  }
-  return Api::NewHandle(isolate, cls.UserVisibleName());
-}
-
-
-DART_EXPORT Dart_Handle Dart_ClassGetLibrary(Dart_Handle clazz) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
-  if (cls.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, clazz, Class);
-  }
-
-#if defined(DEBUG)
-  const Library& lib = Library::Handle(cls.library());
-  if (lib.IsNull()) {
-    // ASSERT(cls.IsDynamicClass() || cls.IsVoidClass());
-    if (!cls.IsDynamicClass() && !cls.IsVoidClass()) {
-      fprintf(stderr, "NO LIBRARY: %s\n", cls.ToCString());
-    }
-  }
-#endif
-
-  return Api::NewHandle(isolate, cls.library());
-}
-
-
-DART_EXPORT Dart_Handle Dart_ClassGetInterfaceCount(Dart_Handle clazz,
-                                                    intptr_t* count) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
-  if (cls.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, clazz, Class);
-  }
-
-  const Array& interface_types = Array::Handle(isolate, cls.interfaces());
-  if (interface_types.IsNull()) {
-    *count = 0;
-  } else {
-    *count = interface_types.Length();
-  }
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_ClassGetInterfaceAt(Dart_Handle clazz,
-                                                 intptr_t index) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
-  if (cls.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, clazz, Class);
-  }
-
-  // Finalize all classes.
-  Dart_Handle state = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(state)) {
-    return state;
-  }
-
-  const Array& interface_types = Array::Handle(isolate, cls.interfaces());
-  if (index < 0 || index >= interface_types.Length()) {
-    return Api::NewError("%s: argument 'index' out of bounds.", CURRENT_FUNC);
-  }
-  Type& interface_type = Type::Handle(isolate);
-  interface_type ^= interface_types.At(index);
-  if (interface_type.HasResolvedTypeClass()) {
-    return Api::NewHandle(isolate, interface_type.type_class());
-  }
-  const String& type_name =
-      String::Handle(isolate, interface_type.TypeClassName());
-  return Api::NewError("%s: internal error: found unresolved type class '%s'.",
-                       CURRENT_FUNC, type_name.ToCString());
-}
-
-
-DART_EXPORT bool Dart_ClassIsTypedef(Dart_Handle clazz) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
-  if (cls.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, clazz, Class);
-  }
-  // For now we represent typedefs as non-canonical signature classes.
-  // I anticipate this may change if we make typedefs more general.
-  return cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass();
-}
-
-
-DART_EXPORT Dart_Handle Dart_ClassGetTypedefReferent(Dart_Handle clazz) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
-  if (cls.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, clazz, Class);
-  }
-
-  if (!cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass()) {
-    const String& cls_name = String::Handle(cls.UserVisibleName());
-    return Api::NewError("%s: class '%s' is not a typedef class. "
-                         "See Dart_ClassIsTypedef.",
-                         CURRENT_FUNC, cls_name.ToCString());
-  }
-
-  const Function& func = Function::Handle(isolate, cls.signature_function());
-  return Api::NewHandle(isolate, func.signature_class());
-}
-
-
-DART_EXPORT bool Dart_ClassIsFunctionType(Dart_Handle clazz) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
-  if (cls.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, clazz, Class);
-  }
-  // A class represents a function type when it is a canonical
-  // signature class.
-  return cls.IsCanonicalSignatureClass();
-}
-
-
-DART_EXPORT Dart_Handle Dart_ClassGetFunctionTypeSignature(Dart_Handle clazz) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
-  if (cls.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, clazz, Class);
-  }
-  if (!cls.IsCanonicalSignatureClass()) {
-    const String& cls_name = String::Handle(cls.UserVisibleName());
-    return Api::NewError("%s: class '%s' is not a function-type class. "
-                         "See Dart_ClassIsFunctionType.",
-                         CURRENT_FUNC, cls_name.ToCString());
-  }
-  return Api::NewHandle(isolate, cls.signature_function());
-}
-
-
-// --- Function and Variable Reflection ---
-
-
-// Outside of the vm, we expose setter names with a trailing '='.
-static bool HasExternalSetterSuffix(const String& name) {
-  return name.CharAt(name.Length() - 1) == '=';
-}
-
-
-static RawString* RemoveExternalSetterSuffix(const String& name) {
-  ASSERT(HasExternalSetterSuffix(name));
-  return String::SubString(name, 0, name.Length() - 1);
-}
-
-
-DART_EXPORT Dart_Handle Dart_GetFunctionNames(Dart_Handle target) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
-  if (obj.IsError()) {
-    return target;
-  }
-
-  const GrowableObjectArray& names =
-      GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
-  Function& func = Function::Handle();
-  String& name = String::Handle();
-
-  if (obj.IsClass()) {
-    const Class& cls = Class::Cast(obj);
-    const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
-    if (!error.IsNull()) {
-      return Api::NewHandle(isolate, error.raw());
-    }
-    const Array& func_array = Array::Handle(cls.functions());
-
-    // Some special types like 'dynamic' have a null functions list.
-    if (!func_array.IsNull()) {
-      for (intptr_t i = 0; i < func_array.Length(); ++i) {
-        func ^= func_array.At(i);
-
-        // Skip implicit getters and setters.
-        if (func.kind() == RawFunction::kImplicitGetter ||
-            func.kind() == RawFunction::kImplicitSetter ||
-            func.kind() == RawFunction::kConstImplicitGetter ||
-            func.kind() == RawFunction::kMethodExtractor) {
-          continue;
-        }
-
-        name = func.UserVisibleName();
-        names.Add(name);
-      }
-    }
-  } else if (obj.IsLibrary()) {
-    const Library& lib = Library::Cast(obj);
-    DictionaryIterator it(lib);
-    Object& obj = Object::Handle();
-    while (it.HasNext()) {
-      obj = it.GetNext();
-      if (obj.IsFunction()) {
-        func ^= obj.raw();
-        name = func.UserVisibleName();
-        names.Add(name);
-      }
-    }
-  } else {
-    return Api::NewError(
-        "%s expects argument 'target' to be a class or library.",
-        CURRENT_FUNC);
-  }
-  return Api::NewHandle(isolate, Array::MakeArray(names));
-}
-
-
-DART_EXPORT Dart_Handle Dart_LookupFunction(Dart_Handle target,
-                                            Dart_Handle function_name) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
-  if (obj.IsError()) {
-    return target;
-  }
-  const String& func_name = Api::UnwrapStringHandle(isolate, function_name);
-  if (func_name.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function_name, String);
-  }
-
-  Function& func = Function::Handle(isolate);
-  String& tmp_name = String::Handle(isolate);
-  if (obj.IsClass()) {
-    const Class& cls = Class::Cast(obj);
-
-    // Case 1.  Lookup the unmodified function name.
-    func = cls.LookupFunctionAllowPrivate(func_name);
-
-    // Case 2.  Lookup the function without the external setter suffix
-    // '='.  Make sure to do this check after the regular lookup, so
-    // that we don't interfere with operator lookups (like ==).
-    if (func.IsNull() && HasExternalSetterSuffix(func_name)) {
-      tmp_name = RemoveExternalSetterSuffix(func_name);
-      tmp_name = Field::SetterName(tmp_name);
-      func = cls.LookupFunctionAllowPrivate(tmp_name);
-    }
-
-    // Case 3.  Lookup the funciton with the getter prefix prepended.
-    if (func.IsNull()) {
-      tmp_name = Field::GetterName(func_name);
-      func = cls.LookupFunctionAllowPrivate(tmp_name);
-    }
-
-    // Case 4.  Lookup the function with a . appended to find the
-    // unnamed constructor.
-    if (func.IsNull()) {
-      tmp_name = String::Concat(func_name, Symbols::Dot());
-      func = cls.LookupFunctionAllowPrivate(tmp_name);
-    }
-  } else if (obj.IsLibrary()) {
-    const Library& lib = Library::Cast(obj);
-
-    // Case 1.  Lookup the unmodified function name.
-    func = lib.LookupFunctionAllowPrivate(func_name);
-
-    // Case 2.  Lookup the function without the external setter suffix
-    // '='.  Make sure to do this check after the regular lookup, so
-    // that we don't interfere with operator lookups (like ==).
-    if (func.IsNull() && HasExternalSetterSuffix(func_name)) {
-      tmp_name = RemoveExternalSetterSuffix(func_name);
-      tmp_name = Field::SetterName(tmp_name);
-      func = lib.LookupFunctionAllowPrivate(tmp_name);
-    }
-
-    // Case 3.  Lookup the function with the getter prefix prepended.
-    if (func.IsNull()) {
-      tmp_name = Field::GetterName(func_name);
-      func = lib.LookupFunctionAllowPrivate(tmp_name);
-    }
-  } else {
-    return Api::NewError(
-        "%s expects argument 'target' to be a class or library.",
-        CURRENT_FUNC);
-  }
-
-#if defined(DEBUG)
-  if (!func.IsNull()) {
-    // We only provide access to a subset of function kinds.
-    RawFunction::Kind func_kind = func.kind();
-    ASSERT(func_kind == RawFunction::kRegularFunction ||
-           func_kind == RawFunction::kGetterFunction ||
-           func_kind == RawFunction::kSetterFunction ||
-           func_kind == RawFunction::kConstructor);
-  }
-#endif
-  return Api::NewHandle(isolate, func.raw());
-}
-
-
-DART_EXPORT bool Dart_IsFunction(Dart_Handle handle) {
-  return Api::ClassId(handle) == kFunctionCid;
-}
-
-
-DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
-  if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
-  }
-  return Api::NewHandle(isolate, func.UserVisibleName());
-}
-
-
-DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
-  if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
-  }
-  if (func.IsNonImplicitClosureFunction()) {
-    RawFunction* parent_function = func.parent_function();
-    return Api::NewHandle(isolate, parent_function);
-  }
-  const Class& owner = Class::Handle(func.Owner());
-  ASSERT(!owner.IsNull());
-  if (owner.IsTopLevel()) {
-    // Top-level functions are implemented as members of a hidden class. We hide
-    // that class here and instead answer the library.
-#if defined(DEBUG)
-    const Library& lib = Library::Handle(owner.library());
-    if (lib.IsNull()) {
-      ASSERT(owner.IsDynamicClass() || owner.IsVoidClass());
-    }
-#endif
-    return Api::NewHandle(isolate, owner.library());
-  } else {
-    return Api::NewHandle(isolate, owner.raw());
-  }
-}
-
-
-DART_EXPORT Dart_Handle Dart_FunctionIsAbstract(Dart_Handle function,
-                                                bool* is_abstract) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (is_abstract == NULL) {
-    RETURN_NULL_ERROR(is_abstract);
-  }
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
-  if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
-  }
-  *is_abstract = func.is_abstract();
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
-                                              bool* is_static) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (is_static == NULL) {
-    RETURN_NULL_ERROR(is_static);
-  }
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
-  if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
-  }
-  *is_static = func.is_static();
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_FunctionIsConstructor(Dart_Handle function,
-                                                   bool* is_constructor) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (is_constructor == NULL) {
-    RETURN_NULL_ERROR(is_constructor);
-  }
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
-  if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
-  }
-  *is_constructor = func.kind() == RawFunction::kConstructor;
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_FunctionIsGetter(Dart_Handle function,
-                                              bool* is_getter) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (is_getter == NULL) {
-    RETURN_NULL_ERROR(is_getter);
-  }
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
-  if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
-  }
-  *is_getter = func.IsGetterFunction();
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_FunctionIsSetter(Dart_Handle function,
-                                              bool* is_setter) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (is_setter == NULL) {
-    RETURN_NULL_ERROR(is_setter);
-  }
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
-  if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
-  }
-  *is_setter = (func.kind() == RawFunction::kSetterFunction);
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_FunctionReturnType(Dart_Handle function) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
-  if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
-  }
-
-  if (func.kind() == RawFunction::kConstructor) {
-    // Special case the return type for constructors.  Inside the vm
-    // we mark them as returning dynamic, but for the purposes of
-    // reflection, they return the type of the class being
-    // constructed.
-    return Api::NewHandle(isolate, func.Owner());
-  } else {
-    const AbstractType& return_type =
-        AbstractType::Handle(isolate, func.result_type());
-    return TypeToHandle(isolate, "Dart_FunctionReturnType", return_type);
-  }
-}
-
-
-DART_EXPORT Dart_Handle Dart_FunctionParameterCounts(
-    Dart_Handle function,
-    int64_t* fixed_param_count,
-    int64_t* opt_param_count) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (fixed_param_count == NULL) {
-    RETURN_NULL_ERROR(fixed_param_count);
-  }
-  if (opt_param_count == NULL) {
-    RETURN_NULL_ERROR(opt_param_count);
-  }
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
-  if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
-  }
-
-  // We hide implicit parameters, such as a method's receiver. This is
-  // consistent with Invoke or New, which don't expect their callers to
-  // provide them in the argument lists they are handed.
-  *fixed_param_count = func.num_fixed_parameters() -
-                       func.NumImplicitParameters();
-  // TODO(regis): Separately report named and positional optional param counts.
-  *opt_param_count = func.NumOptionalParameters();
-
-  ASSERT(*fixed_param_count >= 0);
-  ASSERT(*opt_param_count >= 0);
-
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_FunctionParameterType(Dart_Handle function,
-                                                   int parameter_index) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
-  if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
-  }
-
-  const intptr_t num_implicit_params = func.NumImplicitParameters();
-  const intptr_t num_params = func.NumParameters() - num_implicit_params;
-  if (parameter_index < 0 || parameter_index >= num_params) {
-    return Api::NewError(
-        "%s: argument 'parameter_index' out of range. "
-        "Expected 0..%"Pd" but saw %d.",
-        CURRENT_FUNC, num_params, parameter_index);
-  }
-  const AbstractType& param_type =
-      AbstractType::Handle(isolate, func.ParameterTypeAt(
-          num_implicit_params + parameter_index));
-  return TypeToHandle(isolate, "Dart_FunctionParameterType", param_type);
-}
-
-
-DART_EXPORT Dart_Handle Dart_GetVariableNames(Dart_Handle target) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
-  if (obj.IsError()) {
-    return target;
-  }
-
-  const GrowableObjectArray& names =
-      GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
-  Field& field = Field::Handle(isolate);
-  String& name = String::Handle(isolate);
-
-  if (obj.IsClass()) {
-    const Class& cls = Class::Cast(obj);
-    const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
-    if (!error.IsNull()) {
-      return Api::NewHandle(isolate, error.raw());
-    }
-    const Array& field_array = Array::Handle(cls.fields());
-
-    // Some special types like 'dynamic' have a null fields list.
-    //
-    // TODO(turnidge): Fix 'dynamic' so that it does not have a null
-    // fields list.  This will have to wait until the empty array is
-    // allocated in the vm isolate.
-    if (!field_array.IsNull()) {
-      for (intptr_t i = 0; i < field_array.Length(); ++i) {
-        field ^= field_array.At(i);
-        name = field.UserVisibleName();
-        names.Add(name);
-      }
-    }
-  } else if (obj.IsLibrary()) {
-    const Library& lib = Library::Cast(obj);
-    DictionaryIterator it(lib);
-    Object& obj = Object::Handle(isolate);
-    while (it.HasNext()) {
-      obj = it.GetNext();
-      if (obj.IsField()) {
-        field ^= obj.raw();
-        name = field.UserVisibleName();
-        names.Add(name);
-      }
-    }
-  } else {
-    return Api::NewError(
-        "%s expects argument 'target' to be a class or library.",
-        CURRENT_FUNC);
-  }
-  return Api::NewHandle(isolate, Array::MakeArray(names));
-}
-
-
-DART_EXPORT Dart_Handle Dart_LookupVariable(Dart_Handle target,
-                                            Dart_Handle variable_name) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
-  if (obj.IsError()) {
-    return target;
-  }
-  const String& var_name = Api::UnwrapStringHandle(isolate, variable_name);
-  if (var_name.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, variable_name, String);
-  }
-  if (obj.IsClass()) {
-    const Class& cls = Class::Cast(obj);
-    return Api::NewHandle(isolate, cls.LookupField(var_name));
-  }
-  if (obj.IsLibrary()) {
-    const Library& lib = Library::Cast(obj);
-    return Api::NewHandle(isolate, lib.LookupFieldAllowPrivate(var_name));
-  }
-  return Api::NewError(
-      "%s expects argument 'target' to be a class or library.",
-      CURRENT_FUNC);
-}
-
-
-DART_EXPORT bool Dart_IsVariable(Dart_Handle handle) {
-  return Api::ClassId(handle) == kFieldCid;
-}
-
-
-DART_EXPORT Dart_Handle Dart_VariableName(Dart_Handle variable) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Field& var = Api::UnwrapFieldHandle(isolate, variable);
-  if (var.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, variable, Field);
-  }
-  return Api::NewHandle(isolate, var.UserVisibleName());
-}
-
-
-DART_EXPORT Dart_Handle Dart_VariableIsStatic(Dart_Handle variable,
-                                              bool* is_static) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (is_static == NULL) {
-    RETURN_NULL_ERROR(is_static);
-  }
-  const Field& var = Api::UnwrapFieldHandle(isolate, variable);
-  if (var.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, variable, Field);
-  }
-  *is_static = var.is_static();
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_VariableIsFinal(Dart_Handle variable,
-                                             bool* is_final) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (is_final == NULL) {
-    RETURN_NULL_ERROR(is_final);
-  }
-  const Field& var = Api::UnwrapFieldHandle(isolate, variable);
-  if (var.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, variable, Field);
-  }
-  *is_final = var.is_final();
-  return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_VariableType(Dart_Handle variable) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Field& var = Api::UnwrapFieldHandle(isolate, variable);
-  if (var.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, variable, Field);
-  }
-
-  const AbstractType& type = AbstractType::Handle(isolate, var.type());
-  return TypeToHandle(isolate, "Dart_VariableType", type);
-}
-
-
-DART_EXPORT Dart_Handle Dart_GetTypeVariableNames(Dart_Handle clazz) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
-  if (cls.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, clazz, Class);
-  }
-
-  const intptr_t num_type_params = cls.NumTypeParameters();
-  const TypeArguments& type_params =
-      TypeArguments::Handle(cls.type_parameters());
-
-  const GrowableObjectArray& names =
-      GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
-  TypeParameter& type_param = TypeParameter::Handle(isolate);
-  String& name = String::Handle(isolate);
-  for (intptr_t i = 0; i < num_type_params; i++) {
-    type_param ^= type_params.TypeAt(i);
-    name = type_param.name();
-    names.Add(name);
-  }
-  return Api::NewHandle(isolate, Array::MakeArray(names));
-}
-
-
-DART_EXPORT Dart_Handle Dart_LookupTypeVariable(
-    Dart_Handle clazz,
-    Dart_Handle type_variable_name) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
-  if (cls.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, clazz, Class);
-  }
-  const String& var_name = Api::UnwrapStringHandle(isolate, type_variable_name);
-  if (var_name.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, type_variable_name, String);
-  }
-
-  const intptr_t num_type_params = cls.NumTypeParameters();
-  const TypeArguments& type_params =
-      TypeArguments::Handle(cls.type_parameters());
-
-  TypeParameter& type_param = TypeParameter::Handle(isolate);
-  String& name = String::Handle(isolate);
-  for (intptr_t i = 0; i < num_type_params; i++) {
-    type_param ^= type_params.TypeAt(i);
-    name = type_param.name();
-    if (name.Equals(var_name)) {
-      return Api::NewHandle(isolate, type_param.raw());
-    }
-  }
-  const String& cls_name = String::Handle(cls.UserVisibleName());
-  return Api::NewError(
-      "%s: Could not find type variable named '%s' for class %s.\n",
-      CURRENT_FUNC, var_name.ToCString(), cls_name.ToCString());
-}
-
-
-DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle) {
-  return Api::ClassId(handle) == kTypeParameterCid;
-}
-
-DART_EXPORT Dart_Handle Dart_TypeVariableName(Dart_Handle type_variable) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const TypeParameter& type_var =
-      Api::UnwrapTypeParameterHandle(isolate, type_variable);
-  if (type_var.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, type_variable, TypeParameter);
-  }
-  return Api::NewHandle(isolate, type_var.name());
-}
-
-
-DART_EXPORT Dart_Handle Dart_TypeVariableOwner(Dart_Handle type_variable) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const TypeParameter& type_var =
-      Api::UnwrapTypeParameterHandle(isolate, type_variable);
-  if (type_var.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, type_variable, TypeParameter);
-  }
-  const Class& owner = Class::Handle(type_var.parameterized_class());
-  ASSERT(!owner.IsNull() && owner.IsClass());
-  return Api::NewHandle(isolate, owner.raw());
-}
-
-
-DART_EXPORT Dart_Handle Dart_TypeVariableUpperBound(Dart_Handle type_variable) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const TypeParameter& type_var =
-      Api::UnwrapTypeParameterHandle(isolate, type_variable);
-  if (type_var.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, type_variable, TypeParameter);
-  }
-  const AbstractType& bound = AbstractType::Handle(type_var.bound());
-  return TypeToHandle(isolate, "Dart_TypeVariableUpperBound", bound);
-}
-
-
-// --- Constructors, Methods, and Fields ---
-
+// ---  Invoking Constructors, Methods, and Field accessors ---
 
 static RawObject* ResolveConstructor(const char* current_func,
                                      const Class& cls,
@@ -3879,6 +2953,40 @@
 }
 
 
+DART_EXPORT Dart_Handle Dart_InvokeClosure(Dart_Handle closure,
+                                           int number_of_arguments,
+                                           Dart_Handle* arguments) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  CHECK_CALLBACK_STATE(isolate);
+  const Instance& closure_obj = Api::UnwrapInstanceHandle(isolate, closure);
+  if (closure_obj.IsNull() || !closure_obj.IsCallable(NULL, NULL)) {
+    RETURN_TYPE_ERROR(isolate, closure, Instance);
+  }
+  if (number_of_arguments < 0) {
+    return Api::NewError(
+        "%s expects argument 'number_of_arguments' to be non-negative.",
+        CURRENT_FUNC);
+  }
+  ASSERT(ClassFinalizer::AllClassesFinalized());
+
+  // Set up arguments to include the closure as the first argument.
+  const Array& args = Array::Handle(isolate,
+                                    Array::New(number_of_arguments + 1));
+  Object& obj = Object::Handle(isolate);
+  args.SetAt(0, closure_obj);
+  for (int i = 0; i < number_of_arguments; i++) {
+    obj = Api::UnwrapHandle(arguments[i]);
+    if (!obj.IsNull() && !obj.IsInstance()) {
+      RETURN_TYPE_ERROR(isolate, arguments[i], Instance);
+    }
+    args.SetAt(i + 1, obj);
+  }
+  // Now try to invoke the closure.
+  return Api::NewHandle(isolate, DartEntry::InvokeClosure(args));
+}
+
+
 static bool FieldIsUninitialized(Isolate* isolate, const Field& fld) {
   ASSERT(!fld.IsNull());
 
@@ -4156,6 +3264,85 @@
 }
 
 
+// --- Exceptions ----
+
+DART_EXPORT Dart_Handle Dart_ThrowException(Dart_Handle exception) {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  CHECK_CALLBACK_STATE(isolate);
+  {
+    const Instance& excp = Api::UnwrapInstanceHandle(isolate, exception);
+    if (excp.IsNull()) {
+      RETURN_TYPE_ERROR(isolate, exception, Instance);
+    }
+  }
+  if (isolate->top_exit_frame_info() == 0) {
+    // There are no dart frames on the stack so it would be illegal to
+    // throw an exception here.
+    return Api::NewError("No Dart frames on stack, cannot throw exception");
+  }
+
+  // Unwind all the API scopes till the exit frame before throwing an
+  // exception.
+  ApiState* state = isolate->api_state();
+  ASSERT(state != NULL);
+  const Instance* saved_exception;
+  {
+    NoGCScope no_gc;
+    RawInstance* raw_exception =
+        Api::UnwrapInstanceHandle(isolate, exception).raw();
+    state->UnwindScopes(isolate->top_exit_frame_info());
+    saved_exception = &Instance::Handle(raw_exception);
+  }
+  Exceptions::Throw(*saved_exception);
+  return Api::NewError("Exception was not thrown, internal error");
+}
+
+
+DART_EXPORT Dart_Handle Dart_ReThrowException(Dart_Handle exception,
+                                              Dart_Handle stacktrace) {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  CHECK_CALLBACK_STATE(isolate);
+  {
+    const Instance& excp = Api::UnwrapInstanceHandle(isolate, exception);
+    if (excp.IsNull()) {
+      RETURN_TYPE_ERROR(isolate, exception, Instance);
+    }
+    const Instance& stk = Api::UnwrapInstanceHandle(isolate, stacktrace);
+    if (stk.IsNull()) {
+      RETURN_TYPE_ERROR(isolate, stacktrace, Instance);
+    }
+  }
+  if (isolate->top_exit_frame_info() == 0) {
+    // There are no dart frames on the stack so it would be illegal to
+    // throw an exception here.
+    return Api::NewError("No Dart frames on stack, cannot throw exception");
+  }
+
+  // Unwind all the API scopes till the exit frame before throwing an
+  // exception.
+  ApiState* state = isolate->api_state();
+  ASSERT(state != NULL);
+  const Instance* saved_exception;
+  const Instance* saved_stacktrace;
+  {
+    NoGCScope no_gc;
+    RawInstance* raw_exception =
+        Api::UnwrapInstanceHandle(isolate, exception).raw();
+    RawInstance* raw_stacktrace =
+        Api::UnwrapInstanceHandle(isolate, stacktrace).raw();
+    state->UnwindScopes(isolate->top_exit_frame_info());
+    saved_exception = &Instance::Handle(raw_exception);
+    saved_stacktrace = &Instance::Handle(raw_stacktrace);
+  }
+  Exceptions::ReThrow(*saved_exception, *saved_stacktrace);
+  return Api::NewError("Exception was not re thrown, internal error");
+}
+
+
+// --- Native fields and functions ---
+
 DART_EXPORT Dart_Handle Dart_CreateNativeWrapperClass(Dart_Handle library,
                                                       Dart_Handle name,
                                                       int field_count) {
@@ -4238,87 +3425,6 @@
 }
 
 
-// --- Exceptions ----
-
-
-DART_EXPORT Dart_Handle Dart_ThrowException(Dart_Handle exception) {
-  Isolate* isolate = Isolate::Current();
-  CHECK_ISOLATE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  {
-    const Instance& excp = Api::UnwrapInstanceHandle(isolate, exception);
-    if (excp.IsNull()) {
-      RETURN_TYPE_ERROR(isolate, exception, Instance);
-    }
-  }
-  if (isolate->top_exit_frame_info() == 0) {
-    // There are no dart frames on the stack so it would be illegal to
-    // throw an exception here.
-    return Api::NewError("No Dart frames on stack, cannot throw exception");
-  }
-
-  // Unwind all the API scopes till the exit frame before throwing an
-  // exception.
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
-  const Instance* saved_exception;
-  {
-    NoGCScope no_gc;
-    RawInstance* raw_exception =
-        Api::UnwrapInstanceHandle(isolate, exception).raw();
-    state->UnwindScopes(isolate->top_exit_frame_info());
-    saved_exception = &Instance::Handle(raw_exception);
-  }
-  Exceptions::Throw(*saved_exception);
-  return Api::NewError("Exception was not thrown, internal error");
-}
-
-
-DART_EXPORT Dart_Handle Dart_ReThrowException(Dart_Handle exception,
-                                              Dart_Handle stacktrace) {
-  Isolate* isolate = Isolate::Current();
-  CHECK_ISOLATE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  {
-    const Instance& excp = Api::UnwrapInstanceHandle(isolate, exception);
-    if (excp.IsNull()) {
-      RETURN_TYPE_ERROR(isolate, exception, Instance);
-    }
-    const Instance& stk = Api::UnwrapInstanceHandle(isolate, stacktrace);
-    if (stk.IsNull()) {
-      RETURN_TYPE_ERROR(isolate, stacktrace, Instance);
-    }
-  }
-  if (isolate->top_exit_frame_info() == 0) {
-    // There are no dart frames on the stack so it would be illegal to
-    // throw an exception here.
-    return Api::NewError("No Dart frames on stack, cannot throw exception");
-  }
-
-  // Unwind all the API scopes till the exit frame before throwing an
-  // exception.
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
-  const Instance* saved_exception;
-  const Instance* saved_stacktrace;
-  {
-    NoGCScope no_gc;
-    RawInstance* raw_exception =
-        Api::UnwrapInstanceHandle(isolate, exception).raw();
-    RawInstance* raw_stacktrace =
-        Api::UnwrapInstanceHandle(isolate, stacktrace).raw();
-    state->UnwindScopes(isolate->top_exit_frame_info());
-    saved_exception = &Instance::Handle(raw_exception);
-    saved_stacktrace = &Instance::Handle(raw_stacktrace);
-  }
-  Exceptions::ReThrow(*saved_exception, *saved_stacktrace);
-  return Api::NewError("Exception was not re thrown, internal error");
-}
-
-
-// --- Native functions ---
-
-
 DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args,
                                                int index) {
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
@@ -4350,31 +3456,8 @@
 }
 
 
-// --- Metadata ----
-
-DART_EXPORT Dart_Handle Dart_GetMetadata(Dart_Handle object) {
-  Isolate* isolate = Isolate::Current();
-  CHECK_ISOLATE(isolate);
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
-  Class& cls = Class::Handle(isolate);
-  if (obj.IsClass()) {
-    cls ^= obj.raw();
-  } else if (obj.IsFunction()) {
-    cls = Function::Cast(obj).origin();
-  } else if (obj.IsField()) {
-    cls = Field::Cast(obj).origin();
-  } else {
-    return Api::NewHandle(isolate, Object::empty_array().raw());
-  }
-  const Library& lib = Library::Handle(cls.library());
-  return Api::NewHandle(isolate, lib.GetMetadata(obj));
-}
-
-
 // --- Scripts and Libraries ---
 
-
 DART_EXPORT Dart_Handle Dart_SetLibraryTagHandler(
     Dart_LibraryTagHandler handler) {
   Isolate* isolate = Isolate::Current();
@@ -4512,48 +3595,6 @@
 }
 
 
-static void CompileAll(Isolate* isolate, Dart_Handle* result) {
-  ASSERT(isolate != NULL);
-  const Error& error = Error::Handle(isolate, Library::CompileAll());
-  if (error.IsNull()) {
-    *result = Api::Success();
-  } else {
-    *result = Api::NewHandle(isolate, error.raw());
-  }
-}
-
-
-DART_EXPORT Dart_Handle Dart_CompileAll() {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  Dart_Handle result = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(result)) {
-    return result;
-  }
-  CHECK_CALLBACK_STATE(isolate);
-  CompileAll(isolate, &result);
-  return result;
-}
-
-
-DART_EXPORT Dart_Handle Dart_CheckFunctionFingerprints() {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  Dart_Handle result = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(result)) {
-    return result;
-  }
-  CHECK_CALLBACK_STATE(isolate);
-  Library::CheckFunctionFingerprints();
-  return result;
-}
-
-
-DART_EXPORT bool Dart_IsLibrary(Dart_Handle object) {
-  return Api::ClassId(object) == kLibraryCid;
-}
-
-
 DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library,
                                       Dart_Handle class_name) {
   Isolate* isolate = Isolate::Current();
@@ -4578,19 +3619,6 @@
 }
 
 
-DART_EXPORT Dart_Handle Dart_LibraryName(Dart_Handle library) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
-  if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
-  }
-  const String& name = String::Handle(isolate, lib.name());
-  ASSERT(!name.IsNull());
-  return Api::NewHandle(isolate, name.raw());
-}
-
-
 DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
@@ -4604,38 +3632,6 @@
 }
 
 
-DART_EXPORT Dart_Handle Dart_LibraryGetClassNames(Dart_Handle library) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
-  if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
-  }
-
-  const GrowableObjectArray& names =
-      GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
-  ClassDictionaryIterator it(lib);
-  Class& cls = Class::Handle();
-  String& name = String::Handle();
-  while (it.HasNext()) {
-    cls = it.GetNextClass();
-    if (cls.IsSignatureClass()) {
-      if (!cls.IsCanonicalSignatureClass()) {
-        // This is a typedef.  Add it to the list of class names.
-        name = cls.UserVisibleName();
-        names.Add(name);
-      } else {
-        // Skip canonical signature classes.  These are not named.
-      }
-    } else {
-      name = cls.UserVisibleName();
-      names.Add(name);
-    }
-  }
-  return Api::NewHandle(isolate, Array::MakeArray(names));
-}
-
-
 DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
@@ -4813,22 +3809,8 @@
 }
 
 
-// --- Profiling support ---
-
-// TODO(7565): Dartium should use the new VM flag "generate_pprof_symbols" for
-// pprof profiling. Then these symbols should be removed.
-
-DART_EXPORT void Dart_InitPprofSupport() { }
-
-DART_EXPORT void Dart_GetPprofSymbolInfo(void** buffer, int* buffer_size) {
-  *buffer = NULL;
-  *buffer_size = 0;
-}
-
-
 // --- Peer support ---
 
-
 DART_EXPORT Dart_Handle Dart_GetPeer(Dart_Handle object, void** peer) {
   if (peer == NULL) {
     RETURN_NULL_ERROR(peer);
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 3959611..c3b66e6 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -58,6 +58,39 @@
   HANDLESCOPE(__temp_isolate__);
 
 
+#define RETURN_TYPE_ERROR(isolate, dart_handle, type)                          \
+  do {                                                                         \
+    const Object& tmp =                                                        \
+        Object::Handle(isolate, Api::UnwrapHandle((dart_handle)));             \
+    if (tmp.IsNull()) {                                                        \
+      return Api::NewError("%s expects argument '%s' to be non-null.",         \
+                           CURRENT_FUNC, #dart_handle);                        \
+    } else if (tmp.IsError()) {                                                \
+      return dart_handle;                                                      \
+    } else {                                                                   \
+      return Api::NewError("%s expects argument '%s' to be of type %s.",       \
+                           CURRENT_FUNC, #dart_handle, #type);                 \
+    }                                                                          \
+  } while (0)
+
+
+#define RETURN_NULL_ERROR(parameter)                                           \
+  return Api::NewError("%s expects argument '%s' to be non-null.",             \
+                       CURRENT_FUNC, #parameter);
+
+
+#define CHECK_LENGTH(length, max_elements)                                     \
+  do {                                                                         \
+    intptr_t len = (length);                                                   \
+    intptr_t max = (max_elements);                                             \
+    if (len < 0 || len > max) {                                                \
+      return Api::NewError(                                                    \
+          "%s expects argument '%s' to be in the range [0..%"Pd"].",           \
+          CURRENT_FUNC, #length, max);                                         \
+    }                                                                          \
+  } while (0)
+
+
 class Api : AllStatic {
  public:
   // Creates a new local handle.
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 250f714..36ca32d 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -2,8 +2,10 @@
 // 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 "include/dart_api.h"
 #include "bin/builtin.h"
+#include "include/dart_api.h"
+#include "include/dart_mirrors_api.h"
+#include "include/dart_native_api.h"
 #include "platform/assert.h"
 #include "platform/json.h"
 #include "platform/utils.h"
diff --git a/runtime/vm/dart_api_message.h b/runtime/vm/dart_api_message.h
index 876c474..a2faf44 100644
--- a/runtime/vm/dart_api_message.h
+++ b/runtime/vm/dart_api_message.h
@@ -5,6 +5,7 @@
 #ifndef VM_DART_API_MESSAGE_H_
 #define VM_DART_API_MESSAGE_H_
 
+#include "include/dart_native_api.h"
 #include "vm/dart_api_state.h"
 #include "vm/snapshot.h"
 
diff --git a/runtime/vm/debugger_mips.cc b/runtime/vm/debugger_mips.cc
index c35df1b..a8721ac 100644
--- a/runtime/vm/debugger_mips.cc
+++ b/runtime/vm/debugger_mips.cc
@@ -48,7 +48,6 @@
   Instr* instr5 = Instr::At(pc_ - 1 * Instr::kInstrSize);
 
 #if defined(DEBUG)
-
   instr1->AssertIsImmInstr(LW, SP, RA, 2 * kWordSize);
   instr2->AssertIsImmInstr(LW, SP, FP, 1 * kWordSize);
   instr3->AssertIsImmInstr(LW, SP, PP, 0 * kWordSize);
diff --git a/runtime/vm/disassembler_mips.cc b/runtime/vm/disassembler_mips.cc
index ecbea4f..e97b981 100644
--- a/runtime/vm/disassembler_mips.cc
+++ b/runtime/vm/disassembler_mips.cc
@@ -329,6 +329,14 @@
       Format(instr, "mflo 'rd");
       break;
     }
+    case MOVCI: {
+      if (instr->Bit(16)) {
+        Format(instr, "movt 'rd, 'rs");
+      } else {
+        Format(instr, "movf 'rd, 'rs");
+      }
+      break;
+    }
     case MOVN: {
       Format(instr, "movn 'rd, 'rs, 'rt");
       break;
@@ -523,35 +531,35 @@
         break;
       }
       case COP1_C_F: {
-        Format(instr, "c.f.'fmt 'fd, 'fs");
+        Format(instr, "c.f.'fmt 'fs, 'ft");
         break;
       }
       case COP1_C_UN: {
-        Format(instr, "c.un.'fmt 'fd, 'fs");
+        Format(instr, "c.un.'fmt 'fs, 'ft");
         break;
       }
       case COP1_C_EQ: {
-        Format(instr, "c.eq.'fmt 'fd, 'fs");
+        Format(instr, "c.eq.'fmt 'fs, 'ft");
         break;
       }
       case COP1_C_UEQ: {
-        Format(instr, "c.ueq.'fmt 'fd, 'fs");
+        Format(instr, "c.ueq.'fmt 'fs, 'ft");
         break;
       }
       case COP1_C_OLT: {
-        Format(instr, "c.olt.'fmt 'fd, 'fs");
+        Format(instr, "c.olt.'fmt 'fs, 'ft");
         break;
       }
       case COP1_C_ULT: {
-        Format(instr, "c.ult.'fmt 'fd, 'fs");
+        Format(instr, "c.ult.'fmt 'fs, 'ft");
         break;
       }
       case COP1_C_OLE: {
-        Format(instr, "c.ole.'fmt 'fd, 'fs");
+        Format(instr, "c.ole.'fmt 'fs, 'ft");
         break;
       }
       case COP1_C_ULE: {
-        Format(instr, "c.ule.'fmt 'fd, 'fs");
+        Format(instr, "c.ule.'fmt 'fs, 'ft");
         break;
       }
       case COP1_CVT_D: {
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index 96ef188..5963f70 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -651,7 +651,8 @@
 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis,
                        VariableLivenessAnalysis* variable_liveness,
                        ZoneGrowableArray<Definition*>* inlining_parameters) {
-  if (!FLAG_optimize_try_catch && (graph_entry_->SuccessorCount() > 1)) {
+  GraphEntryInstr* entry = graph_entry();
+  if (!FLAG_optimize_try_catch && (entry->SuccessorCount() > 1)) {
     Bailout("Catch-entry support in SSA.");
   }
 
@@ -672,28 +673,32 @@
       env.Add(defn);
     }
   } else {
-    // Create new parameters.
-    for (intptr_t i = 0; i < parameter_count(); ++i) {
-      ParameterInstr* param = new ParameterInstr(i, graph_entry_);
+    // Create new parameters.  For functions compiled for OSR, the locals
+    // are unknown and so treated like parameters.
+    intptr_t count = IsCompiledForOsr() ? variable_count() : parameter_count();
+    for (intptr_t i = 0; i < count; ++i) {
+      ParameterInstr* param = new ParameterInstr(i, entry);
       param->set_ssa_temp_index(alloc_ssa_temp_index());  // New SSA temp.
       AddToInitialDefinitions(param);
       env.Add(param);
     }
   }
 
-  // Initialize all locals with #null in the renaming environment.
-  for (intptr_t i = parameter_count(); i < variable_count(); ++i) {
-    env.Add(constant_null());
+  // Initialize all locals with #null in the renaming environment.  For OSR,
+  // the locals have already been handled as parameters.
+  if (!IsCompiledForOsr()) {
+    for (intptr_t i = parameter_count(); i < variable_count(); ++i) {
+      env.Add(constant_null());
+    }
   }
 
-  if (graph_entry_->SuccessorCount() > 1) {
+  if (entry->SuccessorCount() > 1) {
     // Functions with try-catch have a fixed area of stack slots reserved
     // so that all local variables are stored at a known location when
     // on entry to the catch.
-    graph_entry_->set_fixed_slot_count(
-        num_stack_locals() + num_copied_params());
+    entry->set_fixed_slot_count(num_stack_locals() + num_copied_params());
   }
-  RenameRecursive(graph_entry_, &env, live_phis, variable_liveness);
+  RenameRecursive(entry, &env, live_phis, variable_liveness);
 }
 
 
diff --git a/runtime/vm/flow_graph.h b/runtime/vm/flow_graph.h
index 597ef71..8ed08c8 100644
--- a/runtime/vm/flow_graph.h
+++ b/runtime/vm/flow_graph.h
@@ -181,6 +181,8 @@
     loop_invariant_loads_ = loop_invariant_loads;
   }
 
+  bool IsCompiledForOsr() const { return graph_entry()->IsCompiledForOsr(); }
+
  private:
   friend class IfConverter;
   friend class BranchSimplifier;
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index fddde80..d878f8d 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -510,16 +510,7 @@
         Definition* defn = (*catch_entry->initial_definitions())[i];
         LiveRange* range = GetLiveRange(defn->ssa_temp_index());
         range->DefineAt(catch_entry->start_pos());  // Defined at block entry.
-
-        // Save range->End() because it may change in ProcessInitialDefinition.
-        intptr_t range_end = range->End();
         ProcessInitialDefinition(defn, range, catch_entry);
-        spill_slots_.Add(range_end);
-        quad_spill_slots_.Add(false);
-
-        if (defn->IsParameter() && range->spill_slot().stack_index() >= 0) {
-          MarkAsObjectAtSafepoints(range);
-        }
       }
     }
   }
@@ -532,16 +523,7 @@
     LiveRange* range = GetLiveRange(defn->ssa_temp_index());
     range->AddUseInterval(graph_entry->start_pos(), graph_entry->end_pos());
     range->DefineAt(graph_entry->start_pos());
-
-    // Save range->End() because it may change in ProcessInitialDefinition.
-    intptr_t range_end = range->End();
     ProcessInitialDefinition(defn, range, graph_entry);
-    if (defn->IsParameter() && flow_graph_.num_copied_params() > 0) {
-      spill_slots_.Add(range_end);
-      quad_spill_slots_.Add(false);
-
-      MarkAsObjectAtSafepoints(range);
-    }
   }
 }
 
@@ -549,6 +531,8 @@
 void FlowGraphAllocator::ProcessInitialDefinition(Definition* defn,
                                                   LiveRange* range,
                                                   BlockEntryInstr* block) {
+  // Save the range end because it may change below.
+  intptr_t range_end = range->End();
   if (defn->IsParameter()) {
     ParameterInstr* param = defn->AsParameter();
     // Assert that copied and non-copied parameters are mutually exclusive.
@@ -579,6 +563,17 @@
     CompleteRange(tail, Location::kRegister);
   }
   ConvertAllUses(range);
+  if (defn->IsParameter() && (range->spill_slot().stack_index() >= 0)) {
+    // Parameters above the frame pointer consume spill slots and are marked
+    // in stack maps.
+    spill_slots_.Add(range_end);
+    quad_spill_slots_.Add(false);
+    MarkAsObjectAtSafepoints(range);
+  } else if (defn->IsConstant() && block->IsCatchBlockEntry()) {
+    // Constants at catch block entries consume spill slots.
+    spill_slots_.Add(range_end);
+    quad_spill_slots_.Add(false);
+  }
 }
 
 
@@ -1617,7 +1612,6 @@
     }
   }
 
-
   // Set spill slot expiration boundary to the live range's end.
   spill_slots_[idx] = end;
   if (need_quad) {
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index b869940..c8ae244 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -6,6 +6,7 @@
 
 #include "lib/invocation_mirror.h"
 #include "vm/ast_printer.h"
+#include "vm/bit_vector.h"
 #include "vm/code_descriptors.h"
 #include "vm/dart_entry.h"
 #include "vm/flags.h"
@@ -43,7 +44,8 @@
 
 FlowGraphBuilder::FlowGraphBuilder(ParsedFunction* parsed_function,
                                    const Array& ic_data_array,
-                                   InlineExitCollector* exit_collector)
+                                   InlineExitCollector* exit_collector,
+                                   intptr_t osr_id)
   : parsed_function_(parsed_function),
     ic_data_array_(ic_data_array),
     num_copied_params_(parsed_function->num_copied_params()),
@@ -58,7 +60,8 @@
     last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
     try_index_(CatchClauseNode::kInvalidTryIndex),
     graph_entry_(NULL),
-    args_pushed_(0) { }
+    args_pushed_(0),
+    osr_id_(osr_id) { }
 
 
 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) {
@@ -474,7 +477,8 @@
 }
 
 
-void EffectGraphVisitor::TieLoop(const TestGraphVisitor& test_fragment,
+void EffectGraphVisitor::TieLoop(intptr_t token_pos,
+                                 const TestGraphVisitor& test_fragment,
                                  const EffectGraphVisitor& body_fragment) {
   // We have: a test graph fragment with zero, one, or two available exits;
   // and an effect graph fragment with zero or one available exits.  We want
@@ -494,14 +498,16 @@
   } else {
     JoinEntryInstr* join =
         new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index());
-    join->LinkTo(test_fragment.entry());
+    CheckStackOverflowInstr* check =
+        new CheckStackOverflowInstr(token_pos, true);
+    join->LinkTo(check);
+    check->LinkTo(test_fragment.entry());
     Goto(join);
     body_exit->Goto(join);
   }
 
   // 3. Set the exit to the graph to be the false successor of the test, a
   // fresh target node
-
   exit_ = test_fragment.CreateFalseSuccessor();
 }
 
@@ -1602,8 +1608,6 @@
   ASSERT(!for_test.is_empty());  // Language spec.
 
   EffectGraphVisitor for_body(owner(), temp_index());
-  for_body.AddInstruction(
-      new CheckStackOverflowInstr(node->token_pos()));
   node->body()->Visit(&for_body);
 
   // Labels are set after body traversal.
@@ -1614,7 +1618,7 @@
     if (for_body.is_open()) for_body.Goto(join);
     for_body.exit_ = join;
   }
-  TieLoop(for_test, for_body);
+  TieLoop(node->token_pos(), for_test, for_body);
   join = lbl->join_for_break();
   if (join != NULL) {
     Goto(join);
@@ -1634,8 +1638,6 @@
 void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) {
   // Traverse body first in order to generate continue and break labels.
   EffectGraphVisitor for_body(owner(), temp_index());
-  for_body.AddInstruction(
-      new CheckStackOverflowInstr(node->token_pos()));
   node->body()->Visit(&for_body);
 
   TestGraphVisitor for_test(owner(),
@@ -1657,7 +1659,10 @@
       join = new JoinEntryInstr(owner()->AllocateBlockId(),
                                 owner()->try_index());
     }
-    join->LinkTo(for_test.entry());
+    CheckStackOverflowInstr* check =
+        new CheckStackOverflowInstr(node->token_pos(), true);
+    join->LinkTo(check);
+    check->LinkTo(for_test.entry());
     if (body_exit != NULL) {
       body_exit->Goto(join);
     }
@@ -1694,39 +1699,27 @@
 
   // Compose body to set any jump labels.
   EffectGraphVisitor for_body(owner(), temp_index());
-  for_body.AddInstruction(
-      new CheckStackOverflowInstr(node->token_pos()));
   node->body()->Visit(&for_body);
 
-  // Join loop body, increment and compute their end instruction.
-  ASSERT(!for_body.is_empty());
-  Instruction* loop_increment_end = NULL;
   EffectGraphVisitor for_increment(owner(), temp_index());
   node->increment()->Visit(&for_increment);
-  JoinEntryInstr* join = node->label()->join_for_continue();
-  if (join != NULL) {
-    // Insert the join between the body and increment.
-    if (for_body.is_open()) for_body.Goto(join);
-    loop_increment_end = AppendFragment(join, for_increment);
-    ASSERT(loop_increment_end != NULL);
-  } else if (for_body.is_open()) {
-    // Do not insert an extra basic block.
-    for_body.Append(for_increment);
-    loop_increment_end = for_body.exit();
-    // 'for_body' contains at least the stack check.
-    ASSERT(loop_increment_end != NULL);
-  } else {
-    loop_increment_end = NULL;
-  }
 
-  // 'loop_increment_end' is NULL only if there is no join for continue and the
-  // body is not open, i.e., no backward branch exists.
-  if (loop_increment_end != NULL) {
+  // Join the loop body and increment and then tie the loop.
+  JoinEntryInstr* join = node->label()->join_for_continue();
+  if ((join != NULL) || for_body.is_open()) {
     JoinEntryInstr* loop_start =
         new JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index());
+    if (join != NULL) {
+      if (for_body.is_open()) for_body.Goto(join);
+      AppendFragment(join, for_increment);
+      for_increment.Goto(loop_start);
+    } else {
+      for_body.Append(for_increment);
+      for_body.Goto(loop_start);
+    }
     Goto(loop_start);
-    loop_increment_end->Goto(loop_start);
     exit_ = loop_start;
+    AddInstruction(new CheckStackOverflowInstr(node->token_pos(), true));
   }
 
   if (node->condition() == NULL) {
@@ -3463,16 +3456,15 @@
     // Print the function ast before IL generation.
     AstPrinter::PrintFunctionNodes(*parsed_function());
   }
-  // Compilation can be nested, preserve the computation-id.
   const Function& function = parsed_function()->function();
   TargetEntryInstr* normal_entry =
       new TargetEntryInstr(AllocateBlockId(),
                            CatchClauseNode::kInvalidTryIndex);
-  graph_entry_ = new GraphEntryInstr(*parsed_function(), normal_entry);
+  graph_entry_ = new GraphEntryInstr(*parsed_function(), normal_entry, osr_id_);
   EffectGraphVisitor for_effect(this, 0);
   // This check may be deleted if the generated code is leaf.
   CheckStackOverflowInstr* check =
-      new CheckStackOverflowInstr(function.token_pos());
+      new CheckStackOverflowInstr(function.token_pos(), false);
   // If we are inlining don't actually attach the stack check. We must still
   // create the stack check in order to allocate a deopt id.
   if (!IsInlining()) for_effect.AddInstruction(check);
@@ -3480,11 +3472,31 @@
   AppendFragment(normal_entry, for_effect);
   // Check that the graph is properly terminated.
   ASSERT(!for_effect.is_open());
+
+  // When compiling for OSR, use a depth first search to prune instructions
+  // unreachable from the OSR entry.  Catch entries are not (yet) properly
+  // recognized as reachable.
+  if (osr_id_ != Isolate::kNoDeoptId) {
+    if (graph_entry_->SuccessorCount() > 1) {
+      Bailout("try/catch when compiling for OSR");
+    }
+    PruneUnreachable();
+  }
+
   FlowGraph* graph = new FlowGraph(*this, graph_entry_, last_used_block_id_);
   return graph;
 }
 
 
+void FlowGraphBuilder::PruneUnreachable() {
+  ASSERT(osr_id_ != Isolate::kNoDeoptId);
+  BitVector* block_marks = new BitVector(last_used_block_id_ + 1);
+  bool found = graph_entry_->PruneUnreachable(this, graph_entry_, osr_id_,
+                                              block_marks);
+  ASSERT(found);
+}
+
+
 void FlowGraphBuilder::Bailout(const char* reason) {
   const char* kFormat = "FlowGraphBuilder Bailout: %s %s";
   const char* function_name = parsed_function_->function().ToCString();
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index 3a1c685..2ae1401 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -100,10 +100,12 @@
 // Build a flow graph from a parsed function's AST.
 class FlowGraphBuilder: public ValueObject {
  public:
-  // The inlining context is NULL if not inlining.
+  // The inlining context is NULL if not inlining.  The osr_id is the deopt
+  // id of the OSR entry or Isolate::kNoDeoptId if not compiling for OSR.
   FlowGraphBuilder(ParsedFunction* parsed_function,
                    const Array& ic_data_array,
-                   InlineExitCollector* exit_collector);
+                   InlineExitCollector* exit_collector,
+                   intptr_t osr_id);
 
   FlowGraph* BuildGraph();
 
@@ -143,6 +145,10 @@
   intptr_t args_pushed() const { return args_pushed_; }
   void add_args_pushed(intptr_t n) { args_pushed_ += n; }
 
+  // When compiling for OSR, remove blocks that are not reachable from the
+  // OSR entry point.
+  void PruneUnreachable();
+
  private:
   intptr_t parameter_count() const {
     return num_copied_params_ + num_non_copied_params_;
@@ -168,6 +174,10 @@
   // Outgoing argument stack height.
   intptr_t args_pushed_;
 
+  // The deopt id of the OSR entry or Isolate::kNoDeoptId if not compiling
+  // for OSR.
+  const intptr_t osr_id_;
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(FlowGraphBuilder);
 };
 
@@ -229,7 +239,8 @@
   // Append a 'while loop' test and back edge to this graph, depending on
   // which parts are reachable.  Afterward, the graph exit is the false
   // successor of the loop condition.
-  void TieLoop(const TestGraphVisitor& test_fragment,
+  void TieLoop(intptr_t token_pos,
+               const TestGraphVisitor& test_fragment,
                const EffectGraphVisitor& body_fragment);
 
   // Wraps a value in a push-argument instruction and adds the result to the
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index dafa68c..07cc65a 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -101,19 +101,25 @@
   pc_descriptors_list_ = new DescriptorList(64);
   exception_handlers_list_ = new ExceptionHandlerList();
   block_info_.Clear();
-  bool is_leaf = !parsed_function().function().IsClosureFunction() &&
-                 is_optimizing();
+  // Conservative detection of leaf routines used to remove the stack check
+  // on function entry.
+  bool is_leaf = !parsed_function().function().IsClosureFunction()
+      && is_optimizing()
+      && !flow_graph().IsCompiledForOsr();
+  // Initialize block info and search optimized (non-OSR) code for calls
+  // indicating a non-leaf routine and calls without IC data indicating
+  // possible reoptimization.
   for (int i = 0; i < block_order_.length(); ++i) {
     block_info_.Add(new BlockInfo());
-    if (is_optimizing()) {
+    if (is_optimizing() && !flow_graph().IsCompiledForOsr()) {
       BlockEntryInstr* entry = block_order_[i];
       for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
         Instruction* current = it.Current();
-        const ICData* ic_data = NULL;
         if (current->IsBranch()) {
           current = current->AsBranch()->comparison();
         }
         // In optimized code, ICData is always set in the instructions.
+        const ICData* ic_data = NULL;
         if (current->IsInstanceCall()) {
           ic_data = current->AsInstanceCall()->ic_data();
           ASSERT(ic_data != NULL);
@@ -126,10 +132,9 @@
         }
         if ((ic_data != NULL) && (ic_data->NumberOfChecks() == 0)) {
           may_reoptimize_ = true;
-          break;
         }
         if (is_leaf && !current->IsCheckStackOverflow()) {
-          // Note that we do no care if the code contains instructions that
+          // Note that we do not care if the code contains instructions that
           // can deoptimize.
           LocationSummary* locs = current->locs();
           if ((locs != NULL) && locs->can_call()) {
@@ -140,11 +145,10 @@
     }
   }
   if (is_leaf) {
-    // Remove check stack overflow at entry.
-    CheckStackOverflowInstr* check = flow_graph_.graph_entry()->normal_entry()
-        ->next()->AsCheckStackOverflow();
-    ASSERT(check != NULL);
-    check->RemoveFromGraph();
+    // Remove the stack overflow check at function entry.
+    Instruction* first = flow_graph_.graph_entry()->normal_entry()->next();
+    ASSERT(first->IsCheckStackOverflow());
+    if (first->IsCheckStackOverflow()) first->RemoveFromGraph();
   }
 }
 
@@ -553,7 +557,9 @@
     }
     // Emit IC call that will count and thus may need reoptimization at
     // function entry.
-    ASSERT(!is_optimizing() || may_reoptimize());
+    ASSERT(!is_optimizing()
+           || may_reoptimize()
+           || flow_graph().IsCompiledForOsr());
     switch (ic_data.num_args_tested()) {
       case 1:
         label_address = StubCode::OneArgOptimizedCheckInlineCacheEntryPoint();
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index d282034..fe154c7 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -24,6 +24,7 @@
 DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
 DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
 DECLARE_FLAG(int, optimization_counter_threshold);
+DECLARE_FLAG(int, reoptimization_counter_threshold);
 DECLARE_FLAG(bool, print_ast);
 DECLARE_FLAG(bool, print_scopes);
 DECLARE_FLAG(bool, enable_type_checks);
@@ -1077,34 +1078,43 @@
 
 void FlowGraphCompiler::EmitFrameEntry() {
   const Function& function = parsed_function().function();
-  if (CanOptimizeFunction() && function.is_optimizable()) {
-    const bool can_optimize = !is_optimizing() || may_reoptimize();
+  if (CanOptimizeFunction() &&
+      function.is_optimizable() &&
+      (!is_optimizing() || may_reoptimize())) {
     const Register function_reg = EDI;
-    if (can_optimize) {
-      __ LoadObject(function_reg, function);
-    }
+    __ LoadObject(function_reg, function);
     // Patch point is after the eventually inlined function object.
     AddCurrentDescriptor(PcDescriptors::kEntryPatch,
                          Isolate::kNoDeoptId,
                          0);  // No token position.
-    if (can_optimize) {
-      // Reoptimization of optimized function is triggered by counting in
+    if (is_optimizing()) {
+      // Reoptimization of an optimized function is triggered by counting in
       // IC stubs, but not at the entry of the function.
-      if (!is_optimizing()) {
-        __ incl(FieldAddress(function_reg, Function::usage_counter_offset()));
-      }
       __ cmpl(FieldAddress(function_reg, Function::usage_counter_offset()),
-          Immediate(FLAG_optimization_counter_threshold));
-      ASSERT(function_reg == EDI);
-      __ j(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel());
+              Immediate(FLAG_reoptimization_counter_threshold));
+    } else {
+      __ incl(FieldAddress(function_reg, Function::usage_counter_offset()));
+      __ cmpl(FieldAddress(function_reg, Function::usage_counter_offset()),
+              Immediate(FLAG_optimization_counter_threshold));
     }
-  } else {
+    ASSERT(function_reg == EDI);
+    __ j(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel());
+  } else if (!flow_graph().IsCompiledForOsr()) {
     AddCurrentDescriptor(PcDescriptors::kEntryPatch,
                          Isolate::kNoDeoptId,
                          0);  // No token position.
   }
   __ Comment("Enter frame");
-  __ EnterDartFrame(StackSize() * kWordSize);
+  if (flow_graph().IsCompiledForOsr()) {
+    intptr_t extra_slots = StackSize()
+        - flow_graph().num_stack_locals()
+        - flow_graph().num_copied_params();
+    ASSERT(extra_slots >= 0);
+    __ EnterOsrFrame(extra_slots * kWordSize);
+  } else {
+    ASSERT(StackSize() >= 0);
+    __ EnterDartFrame(StackSize() * kWordSize);
+  }
 }
 
 
@@ -1136,9 +1146,10 @@
   if (num_copied_params == 0) {
 #ifdef DEBUG
     ASSERT(!parsed_function().function().HasOptionalParameters());
-    const bool check_arguments = true;
+    const bool check_arguments = !flow_graph().IsCompiledForOsr();
 #else
-    const bool check_arguments = function.IsClosureFunction();
+    const bool check_arguments =
+        function.IsClosureFunction() && !flow_graph().IsCompiledForOsr();
 #endif
     if (check_arguments) {
       __ Comment("Check argument count");
@@ -1196,7 +1207,7 @@
     // The arguments descriptor is never saved in the absence of optional
     // parameters, since any argument definition test would always yield true.
     ASSERT(saved_args_desc_var == NULL);
-  } else {
+  } else if (!flow_graph().IsCompiledForOsr()) {
     if (saved_args_desc_var != NULL) {
       __ Comment("Save arguments descriptor");
       const Register kArgumentsDescriptorReg = EDX;
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 27abae0..a088cc6 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -166,7 +166,8 @@
                                            Label* is_false) {
   __ TraceSimMsg("BoolToJump");
   Label fall_through;
-  __ beq(bool_register, NULLREG, &fall_through);
+  __ BranchEqual(bool_register, reinterpret_cast<int32_t>(Object::null()),
+                 &fall_through);
   __ BranchEqual(bool_register, Bool::True(), is_true);
   __ b(is_false);
   __ Bind(&fall_through);
@@ -190,12 +191,12 @@
   __ LoadObject(A2, type_test_cache);
   if (test_kind == kTestTypeOneArg) {
     ASSERT(type_arguments_reg == kNoRegister);
+    __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null()));
     __ BranchLink(&StubCode::Subtype1TestCacheLabel());
-    __ delay_slot()->mov(A1, NULLREG);
   } else if (test_kind == kTestTypeTwoArgs) {
     ASSERT(type_arguments_reg == kNoRegister);
+    __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null()));
     __ BranchLink(&StubCode::Subtype2TestCacheLabel());
-    __ delay_slot()->mov(A1, NULLREG);
   } else if (test_kind == kTestTypeThreeArgs) {
     ASSERT(type_arguments_reg == A1);
     __ BranchLink(&StubCode::Subtype3TestCacheLabel());
@@ -329,7 +330,8 @@
     // Check if instance is a closure.
     __ LoadClassById(T1, kClassIdReg);
     __ lw(T1, FieldAddress(T1, Class::signature_function_offset()));
-    __ bne(T1, NULLREG, is_instance_lbl);
+    __ BranchNotEqual(T1, reinterpret_cast<int32_t>(Object::null()),
+                      is_instance_lbl);
   }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
@@ -397,7 +399,8 @@
     __ lw(A1, Address(SP, 0));  // Get instantiator type arguments.
     // A1: instantiator type arguments.
     // Check if type argument is dynamic.
-    __ beq(A1, NULLREG, is_instance_lbl);
+    __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null()));
+    __ beq(A1, T7, is_instance_lbl);
     // Can handle only type arguments that are instances of TypeArguments.
     // (runtime checks canonicalize type arguments).
     Label fall_through;
@@ -408,7 +411,7 @@
     // R2: concrete type of type.
     // Check if type argument is dynamic.
     __ BranchEqual(T2, Type::ZoneHandle(Type::DynamicType()), is_instance_lbl);
-    __ beq(T2, NULLREG, is_instance_lbl);
+    __ beq(T2, T7, is_instance_lbl);
     const Type& object_type = Type::ZoneHandle(Type::ObjectType());
     __ BranchEqual(T2, object_type, is_instance_lbl);
 
@@ -483,11 +486,11 @@
   if (TypeCheckAsClassEquality(type)) {
     const intptr_t type_cid = Class::Handle(type.type_class()).id();
     const Register kInstanceReg = A0;
-    __ andi(T0, kInstanceReg, Immediate(kSmiTagMask));
+    __ andi(CMPRES, kInstanceReg, Immediate(kSmiTagMask));
     if (type_cid == kSmiCid) {
-      __ beq(T0, ZR, is_instance_lbl);
+      __ beq(CMPRES, ZR, is_instance_lbl);
     } else {
-      __ beq(T0, ZR, is_not_instance_lbl);
+      __ beq(CMPRES, ZR, is_not_instance_lbl);
       __ LoadClassId(T0, kInstanceReg);
       __ BranchEqual(T0, type_cid, is_instance_lbl);
     }
@@ -527,12 +530,90 @@
 }
 
 
+// If instanceof type test cannot be performed successfully at compile time and
+// therefore eliminated, optimize it by adding inlined tests for:
+// - NULL -> return false.
+// - Smi -> compile time subtype check (only if dst class is not parameterized).
+// - Class equality (only if class is not parameterized).
+// Inputs:
+// - A0: object.
+// - A1: instantiator type arguments or raw_null.
+// - A2: instantiator or raw_null.
+// Returns:
+// - true or false in V0.
 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
                                            intptr_t deopt_id,
                                            const AbstractType& type,
                                            bool negate_result,
                                            LocationSummary* locs) {
-  UNIMPLEMENTED();
+  ASSERT(type.IsFinalized() && !type.IsMalformed());
+
+  // Preserve instantiator (A2) and its type arguments (A1).
+  __ addiu(SP, SP, Immediate(-2 * kWordSize));
+  __ sw(A2, Address(SP, 1 * kWordSize));
+  __ sw(A1, Address(SP, 0 * kWordSize));
+
+  Label is_instance, is_not_instance;
+  // If type is instantiated and non-parameterized, we can inline code
+  // checking whether the tested instance is a Smi.
+  if (type.IsInstantiated()) {
+    // A null object is only an instance of Object and dynamic, which has
+    // already been checked above (if the type is instantiated). So we can
+    // return false here if the instance is null (and if the type is
+    // instantiated).
+    // We can only inline this null check if the type is instantiated at compile
+    // time, since an uninstantiated type at compile time could be Object or
+    // dynamic at run time.
+    __ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()),
+                   &is_not_instance);
+  }
+
+  // Generate inline instanceof test.
+  SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+  test_cache = GenerateInlineInstanceof(token_pos, type,
+                                        &is_instance, &is_not_instance);
+
+  // test_cache is null if there is no fall-through.
+  Label done;
+  if (!test_cache.IsNull()) {
+    // Generate runtime call.
+    // Load instantiator (A2) and its type arguments (A1).
+    __ lw(A1, Address(SP, 0 * kWordSize));
+    __ lw(A2, Address(SP, 1 * kWordSize));
+
+    __ addiu(SP, SP, Immediate(-6 * kWordSize));
+    __ LoadObject(TMP, Object::ZoneHandle());
+    __ sw(TMP, Address(SP, 5 * kWordSize));  // Make room for the result.
+    __ sw(A0, Address(SP, 4 * kWordSize));  // Push the instance.
+    __ LoadObject(TMP, type);
+    __ sw(TMP, Address(SP, 3 * kWordSize));  // Push the type.
+    __ sw(A2, Address(SP, 2 * kWordSize));  // Push instantiator.
+    __ sw(A1, Address(SP, 1 * kWordSize));  // Push type arguments.
+    __ LoadObject(A0, test_cache);
+    __ sw(A0, Address(SP, 0 * kWordSize));
+    GenerateCallRuntime(token_pos, deopt_id, kInstanceofRuntimeEntry, locs);
+    // Pop the parameters supplied to the runtime entry. The result of the
+    // instanceof runtime call will be left as the result of the operation.
+    __ lw(T0, Address(SP, 5 * kWordSize));
+    __ addiu(SP, SP, Immediate(6 * kWordSize));
+    if (negate_result) {
+      __ LoadObject(V0, Bool::True());
+      __ bne(T0, V0, &done);
+      __ LoadObject(V0, Bool::False());
+    } else {
+      __ mov(V0, T0);
+    }
+    __ b(&done);
+  }
+  __ Bind(&is_not_instance);
+  __ LoadObject(V0, negate_result ? Bool::True() : Bool::False());
+  __ b(&done);
+
+  __ Bind(&is_instance);
+  __ LoadObject(V0, negate_result ? Bool::False() : Bool::True());
+  __ Bind(&done);
+  // Remove instantiator (A2) and its type arguments (A1).
+  __ Drop(2);
 }
 
 
@@ -567,7 +648,8 @@
 
   // A null object is always assignable and is returned as result.
   Label is_assignable, runtime_call;
-  __ beq(A0, NULLREG, &is_assignable);
+
+  __ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()), &is_assignable);
   __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize));
 
   if (!FLAG_eliminate_type_checks) {
@@ -804,7 +886,8 @@
     delete[] opt_param_position;
     // Check that T0 now points to the null terminator in the array descriptor.
     __ lw(T3, Address(T0));
-    __ beq(T3, NULLREG, &all_arguments_processed);
+    __ BranchEqual(T3, reinterpret_cast<int32_t>(Object::null()),
+                   &all_arguments_processed);
   } else {
     ASSERT(num_opt_pos_params > 0);
     __ Comment("There are optional positional parameters");
@@ -894,8 +977,9 @@
   __ Bind(&null_args_loop);
   __ addiu(T2, T2, Immediate(-kWordSize));
   __ addu(T3, T1, T2);
+  __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
   __ bgtz(T2, &null_args_loop);
-  __ delay_slot()->sw(NULLREG, Address(T3));
+  __ delay_slot()->sw(TMP, Address(T3));
   __ Bind(&null_args_loop_exit);
 }
 
@@ -918,8 +1002,9 @@
   __ lw(T0, Address(SP, 1 * kWordSize));  // Receiver.
   __ lw(T1, Address(SP, 0 * kWordSize));  // Value.
   __ StoreIntoObject(T0, FieldAddress(T0, offset), T1);
+  __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
   __ Ret();
-  __ delay_slot()->mov(V0, NULLREG);
+  __ delay_slot()->mov(V0, TMP);
 }
 
 
@@ -1113,7 +1198,8 @@
     const intptr_t slot_base = parsed_function().first_stack_local_index();
     for (intptr_t i = 0; i < num_locals; ++i) {
       // Subtract index i (locals lie at lower addresses than FP).
-      __ sw(NULLREG, Address(FP, (slot_base - i) * kWordSize));
+      __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
+      __ sw(TMP, Address(FP, (slot_base - i) * kWordSize));
     }
   }
 
@@ -1348,11 +1434,11 @@
     __ addiu(SP, SP, Immediate(-2 * kWordSize));
     __ sw(reg, Address(SP, 1 * kWordSize));
     __ LoadObject(TMP1, obj);
+    __ sw(TMP1, Address(SP, 0 * kWordSize));
     __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel());
     AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
                          Isolate::kNoDeoptId,
                          token_pos);
-    __ delay_slot()->sw(TMP1, Address(SP, 0 * kWordSize));
     __ TraceSimMsg("EqualityRegConstCompare return");
     __ lw(reg, Address(SP, 1 * kWordSize));  // Restore 'reg'.
     __ addiu(SP, SP, Immediate(2 * kWordSize));  // Discard constant.
@@ -1367,14 +1453,15 @@
                                                   bool needs_number_check,
                                                   intptr_t token_pos) {
   __ TraceSimMsg("EqualityRegRegCompare");
+  __ Comment("EqualityRegRegCompare");
   if (needs_number_check) {
     __ addiu(SP, SP, Immediate(-2 * kWordSize));
     __ sw(left, Address(SP, 1 * kWordSize));
+    __ sw(right, Address(SP, 0 * kWordSize));
     __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel());
     AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
                          Isolate::kNoDeoptId,
                          token_pos);
-    __ delay_slot()->sw(right, Address(SP, 0 * kWordSize));
     __ TraceSimMsg("EqualityRegRegCompare return");
     // Stub returns result in CMPRES. If it is 0, then left and right are equal.
     __ lw(right, Address(SP, 0 * kWordSize));
@@ -1395,8 +1482,9 @@
   __ TraceSimMsg("SuperEqualityCallPrologue");
   __ lw(result, Address(SP, 0 * kWordSize));  // Load right operand.
   __ lw(TMP1, Address(SP, 1 * kWordSize));  // Load left operand.
-  __ beq(result, NULLREG, &check_identity);  // Is right null?
-  __ bne(TMP1, NULLREG, &fall_through);  // If right is non-null, check left.
+  __ LoadImmediate(CMPRES, reinterpret_cast<int32_t>(Object::null()));
+  __ beq(result, CMPRES, &check_identity);  // Is right null?
+  __ bne(TMP1, CMPRES, &fall_through);  // If right is non-null, check left.
 
   __ Bind(&check_identity);
   __ bne(result, TMP1, &is_false);
@@ -1414,9 +1502,20 @@
 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
   __ TraceSimMsg("SaveLiveRegisters");
   // TODO(vegorov): consider saving only caller save (volatile) registers.
-  const intptr_t fpu_registers = locs->live_registers()->fpu_registers();
-  if (fpu_registers > 0) {
-    UNIMPLEMENTED();
+  const intptr_t fpu_regs_count= locs->live_registers()->fpu_regs_count();
+  if (fpu_regs_count > 0) {
+    __ AddImmediate(SP, -(fpu_regs_count * kFpuRegisterSize));
+    // Store fpu registers with the lowest register number at the lowest
+    // address.
+    intptr_t offset = 0;
+    for (intptr_t reg_idx = 0; reg_idx < kNumberOfFpuRegisters; ++reg_idx) {
+      DRegister fpu_reg = static_cast<DRegister>(reg_idx);
+      if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) {
+        __ StoreDToOffset(fpu_reg, SP, offset);
+        offset += kFpuRegisterSize;
+      }
+    }
+    ASSERT(offset == (fpu_regs_count * kFpuRegisterSize));
   }
 
   // Store general purpose registers with the lowest register number at the
@@ -1455,9 +1554,19 @@
   }
   __ addiu(SP, SP, Immediate(register_count * kWordSize));
 
-  const intptr_t fpu_registers = locs->live_registers()->fpu_registers();
-  if (fpu_registers > 0) {
-    UNIMPLEMENTED();
+  const intptr_t fpu_regs_count = locs->live_registers()->fpu_regs_count();
+  if (fpu_regs_count > 0) {
+    // Fpu registers have the lowest register number at the lowest address.
+    intptr_t offset = 0;
+    for (intptr_t reg_idx = 0; reg_idx < kNumberOfFpuRegisters; ++reg_idx) {
+      DRegister fpu_reg = static_cast<DRegister>(reg_idx);
+      if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) {
+        __ LoadDFromOffset(fpu_reg, SP, offset);
+        offset += kFpuRegisterSize;
+      }
+    }
+    ASSERT(offset == (fpu_regs_count * kFpuRegisterSize));
+    __ AddImmediate(SP, offset);
   }
 }
 
@@ -1481,6 +1590,7 @@
       Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
                                                  argument_names));
   __ TraceSimMsg("EmitTestAndCall");
+  __ Comment("EmitTestAndCall");
   __ LoadObject(S4, arguments_descriptor);
   for (intptr_t i = 0; i < len; i++) {
     const bool is_last_check = (i == (len - 1));
@@ -1513,7 +1623,33 @@
                                                 FpuRegister left,
                                                 FpuRegister right,
                                                 BranchInstr* branch) {
-  UNIMPLEMENTED();
+  ASSERT(branch != NULL);
+  __ Comment("DoubleCompareBranch");
+  assembler()->cund(left, right);
+  BlockEntryInstr* nan_result = (true_condition == NE) ?
+      branch->true_successor() : branch->false_successor();
+  assembler()->bc1t(GetJumpLabel(nan_result));
+
+  switch (true_condition) {
+    case EQ: assembler()->ceqd(left, right); break;
+    case LT: assembler()->coltd(left, right); break;
+    case LE: assembler()->coled(left, right); break;
+    case GT: assembler()->coltd(right, left); break;
+    case GE: assembler()->coled(right, left); break;
+    default: {
+      // Should only passing the above conditions to this function.
+      UNREACHABLE();
+      break;
+    }
+  }
+
+  assembler()->LoadImmediate(TMP, 1);
+  assembler()->movf(CMPRES, TMP);
+  assembler()->movt(CMPRES, ZR);
+  assembler()->mov(TMP, ZR);
+
+  // EmitBranchOnCondition expects ordering to be described by CMPRES, TMP1.
+  branch->EmitBranchOnCondition(this, EQ);
 }
 
 
@@ -1521,7 +1657,28 @@
                                               FpuRegister left,
                                               FpuRegister right,
                                               Register result) {
-  UNIMPLEMENTED();
+  Label done;
+  __ Comment("DoubleCompareBool");
+  assembler()->LoadObject(result, Bool::False());
+  assembler()->cund(left, right);
+  assembler()->bc1t(&done);
+
+  switch (true_condition) {
+    case EQ: assembler()->ceqd(left, right); break;
+    case LT: assembler()->coltd(left, right); break;
+    case LE: assembler()->coled(left, right); break;
+    case GT: assembler()->coltd(right, left); break;
+    case GE: assembler()->coled(right, left); break;
+    default: {
+      // Should only passing the above conditions to this function.
+      UNREACHABLE();
+      break;
+    }
+  }
+
+  assembler()->bc1f(&done);  // False is already in result.
+  assembler()->LoadObject(result, Bool::True());
+  assembler()->Bind(&done);
 }
 
 
@@ -1591,7 +1748,9 @@
       __ movd(destination.fpu_reg(), source.fpu_reg());
     } else {
       if (destination.IsDoubleStackSlot()) {
-        __ sdc1(source.fpu_reg(), destination.ToStackSlotAddress());
+        const Address& addr = destination.ToStackSlotAddress();
+        int32_t offset = addr.offset();
+        __ StoreDToOffset(source.fpu_reg(), FP, offset);
       } else {
         ASSERT(destination.IsQuadStackSlot());
         UNIMPLEMENTED();
@@ -1599,11 +1758,18 @@
     }
   } else if (source.IsDoubleStackSlot()) {
     if (destination.IsFpuRegister()) {
-      __ ldc1(destination.fpu_reg(), source.ToStackSlotAddress());
+      const Address &addr = source.ToStackSlotAddress();
+      const Register base = addr.base();
+      const int32_t offset = addr.offset();
+      __ LoadDFromOffset(destination.fpu_reg(), base, offset);
     } else {
       ASSERT(destination.IsDoubleStackSlot());
-      __ ldc1(FpuTMP, source.ToStackSlotAddress());
-      __ sdc1(FpuTMP, destination.ToStackSlotAddress());
+      const Address& saddr = source.ToStackSlotAddress();
+      const Address& daddr = destination.ToStackSlotAddress();
+      int32_t soffset = saddr.offset();
+      int32_t doffset = daddr.offset();
+      __ LoadDFromOffset(FpuTMP, FP, soffset);
+      __ StoreDToOffset(FpuTMP, FP, doffset);
     }
   } else if (source.IsQuadStackSlot()) {
     UNIMPLEMENTED();
@@ -1658,8 +1824,10 @@
         : source.ToStackSlotAddress();
 
     if (double_width) {
-      __ ldc1(FpuTMP, slot_address);
-      __ sdc1(reg, slot_address);
+      const Register base = slot_address.base();
+      const int32_t offset = slot_address.offset();
+      __ LoadDFromOffset(FpuTMP, base, offset);
+      __ StoreDToOffset(reg, base, offset);
       __ movd(reg, FpuTMP);
     } else {
       UNIMPLEMENTED();
@@ -1667,12 +1835,16 @@
   } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
     const Address& source_slot_address = source.ToStackSlotAddress();
     const Address& destination_slot_address = destination.ToStackSlotAddress();
+    const Register sbase = source_slot_address.base();
+    const int32_t soffset = source_slot_address.offset();
+    const Register dbase = destination_slot_address.base();
+    const int32_t doffset = destination_slot_address.offset();
 
     ScratchFpuRegisterScope ensure_scratch(this, FpuTMP);
-    __ ldc1(FpuTMP, source_slot_address);
-    __ ldc1(ensure_scratch.reg(), destination_slot_address);
-    __ sdc1(FpuTMP, destination_slot_address);
-    __ sdc1(ensure_scratch.reg(), source_slot_address);
+    __ LoadDFromOffset(FpuTMP, sbase, soffset);
+    __ LoadDFromOffset(ensure_scratch.reg(), dbase, doffset);
+    __ StoreDToOffset(FpuTMP, dbase, doffset);
+    __ StoreDToOffset(ensure_scratch.reg(), sbase, soffset);
   } else if (source.IsQuadStackSlot() && destination.IsQuadStackSlot()) {
     UNIMPLEMENTED();
   } else {
@@ -1746,13 +1918,13 @@
 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) {
   __ TraceSimMsg("ParallelMoveResolver::SpillFpuScratch");
   __ AddImmediate(SP, -kDoubleSize);
-  __ sdc1(reg, Address(SP));
+  __ StoreDToOffset(reg, SP, 0);
 }
 
 
 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) {
   __ TraceSimMsg("ParallelMoveResolver::RestoreFpuScratch");
-  __ ldc1(reg, Address(SP));
+  __ LoadDFromOffset(reg, SP, 0);
   __ AddImmediate(SP, kDoubleSize);
 }
 
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index d15ecea..df39bc48 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -23,6 +23,7 @@
 
 DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
 DECLARE_FLAG(int, optimization_counter_threshold);
+DECLARE_FLAG(int, reoptimization_counter_threshold);
 DECLARE_FLAG(bool, print_ast);
 DECLARE_FLAG(bool, print_scopes);
 DECLARE_FLAG(bool, enable_type_checks);
@@ -1071,34 +1072,43 @@
 
 void FlowGraphCompiler::EmitFrameEntry() {
   const Function& function = parsed_function().function();
-  if (CanOptimizeFunction() && function.is_optimizable()) {
-    const bool can_optimize = !is_optimizing() || may_reoptimize();
+  if (CanOptimizeFunction() &&
+      function.is_optimizable() &&
+      (!is_optimizing() || may_reoptimize())) {
     const Register function_reg = RDI;
-    if (can_optimize) {
-      __ LoadObject(function_reg, function);
-    }
+    __ LoadObject(function_reg, function);
     // Patch point is after the eventually inlined function object.
     AddCurrentDescriptor(PcDescriptors::kEntryPatch,
                          Isolate::kNoDeoptId,
                          0);  // No token position.
-    if (can_optimize) {
-      // Reoptimization of optimized function is triggered by counting in
+    if (is_optimizing()) {
+      // Reoptimization of an optimized function is triggered by counting in
       // IC stubs, but not at the entry of the function.
-      if (!is_optimizing()) {
-        __ incq(FieldAddress(function_reg, Function::usage_counter_offset()));
-      }
       __ cmpq(FieldAddress(function_reg, Function::usage_counter_offset()),
-          Immediate(FLAG_optimization_counter_threshold));
-      ASSERT(function_reg == RDI);
-      __ j(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel());
+              Immediate(FLAG_reoptimization_counter_threshold));
+    } else {
+      __ incq(FieldAddress(function_reg, Function::usage_counter_offset()));
+      __ cmpq(FieldAddress(function_reg, Function::usage_counter_offset()),
+              Immediate(FLAG_optimization_counter_threshold));
     }
-  } else {
+    ASSERT(function_reg == RDI);
+    __ j(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel());
+  } else if (!flow_graph().IsCompiledForOsr()) {
     AddCurrentDescriptor(PcDescriptors::kEntryPatch,
-                     Isolate::kNoDeoptId,
-                     0);  // No token position.
+                         Isolate::kNoDeoptId,
+                         0);  // No token position.
   }
   __ Comment("Enter frame");
-  __ EnterDartFrame(StackSize() * kWordSize);
+  if (flow_graph().IsCompiledForOsr()) {
+    intptr_t extra_slots = StackSize()
+        - flow_graph().num_stack_locals()
+        - flow_graph().num_copied_params();
+    ASSERT(extra_slots >= 0);
+    __ EnterOsrFrame(extra_slots * kWordSize);
+  } else {
+    ASSERT(StackSize() >= 0);
+    __ EnterDartFrame(StackSize() * kWordSize);
+  }
 }
 
 
@@ -1131,9 +1141,10 @@
   if (num_copied_params == 0) {
 #ifdef DEBUG
     ASSERT(!parsed_function().function().HasOptionalParameters());
-    const bool check_arguments = true;
+    const bool check_arguments = !flow_graph().IsCompiledForOsr();
 #else
-    const bool check_arguments = function.IsClosureFunction();
+    const bool check_arguments =
+        function.IsClosureFunction() && !flow_graph().IsCompiledForOsr();
 #endif
     if (check_arguments) {
       __ Comment("Check argument count");
@@ -1191,7 +1202,7 @@
     // The arguments descriptor is never saved in the absence of optional
     // parameters, since any argument definition test would always yield true.
     ASSERT(saved_args_desc_var == NULL);
-  } else {
+  } else if (!flow_graph().IsCompiledForOsr()) {
     if (saved_args_desc_var != NULL) {
       __ Comment("Save arguments descriptor");
       const Register kArgumentsDescriptorReg = R10;
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 911e62c..6d86710 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -494,7 +494,10 @@
       // Build the callee graph.
       InlineExitCollector* exit_collector =
           new InlineExitCollector(caller_graph_, call);
-      FlowGraphBuilder builder(parsed_function, ic_data_array, exit_collector);
+      FlowGraphBuilder builder(parsed_function,
+                               ic_data_array,
+                               exit_collector,
+                               Isolate::kNoDeoptId);
       builder.SetInitialBlockId(caller_graph_->max_block_id());
       FlowGraph* callee_graph;
       {
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 0ffb7f0..7366821 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -691,8 +691,14 @@
   // However there are parameters that are known to match their declared type:
   // for example receiver and construction phase.
   GraphEntryInstr* graph_entry = block_->AsGraphEntry();
-  // Parameters at catch-blocks have type dynamic.
-  if (graph_entry == NULL) return CompileType::Dynamic();
+  // Parameters at catch blocks and OSR entries have type dynamic.
+  //
+  // TODO(kmillikin): Use the actual type of the parameter at OSR entry.
+  // The code below is not safe for OSR because it doesn't necessarily use
+  // the correct scope.
+  if ((graph_entry == NULL) || graph_entry->IsCompiledForOsr()) {
+    return CompileType::Dynamic();
+  }
 
   const Function& function = graph_entry->parsed_function().function();
   LocalScope* scope = graph_entry->parsed_function().node_sequence()->scope();
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 1a4f025..47fa64b 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -860,6 +860,11 @@
 }
 
 
+void CheckStackOverflowInstr::PrintOperandsTo(BufferFormatter* f) const {
+  if (in_loop()) f->Print("loop");
+}
+
+
 void TargetEntryInstr::PrintTo(BufferFormatter* f) const {
   f->Print("B%"Pd"[target]:%"Pd, block_id(), GetDeoptId());
   if (HasParallelMove()) {
diff --git a/runtime/vm/instructions_mips.cc b/runtime/vm/instructions_mips.cc
index 41648b1..197efd1 100644
--- a/runtime/vm/instructions_mips.cc
+++ b/runtime/vm/instructions_mips.cc
@@ -6,6 +6,7 @@
 #if defined(TARGET_ARCH_MIPS)
 
 #include "vm/constants_mips.h"
+#include "vm/cpu.h"
 #include "vm/instructions.h"
 #include "vm/object.h"
 
@@ -158,6 +159,24 @@
 }
 
 
+void CallPattern::InsertAt(uword pc, uword target_address) {
+  Instr* lui = Instr::At(pc + (0 * Instr::kInstrSize));
+  Instr* ori = Instr::At(pc + (1 * Instr::kInstrSize));
+  Instr* jr = Instr::At(pc + (2 * Instr::kInstrSize));
+  Instr* nop = Instr::At(pc + (3 * Instr::kInstrSize));
+  uint16_t target_lo = target_address & 0xffff;
+  uint16_t target_hi = target_address >> 16;
+
+  lui->SetImmInstrBits(LUI, ZR, TMP1, target_hi);
+  ori->SetImmInstrBits(ORI, TMP1, TMP1, target_lo);
+  jr->SetSpecialInstrBits(JALR, TMP1, ZR, RA);
+  nop->SetInstructionBits(Instr::kNopInstruction);
+
+  ASSERT(kFixedLengthInBytes == 4 * Instr::kInstrSize);
+  CPU::FlushICache(pc, kFixedLengthInBytes);
+}
+
+
 JumpPattern::JumpPattern(uword pc) : pc_(pc) { }
 
 
diff --git a/runtime/vm/instructions_mips.h b/runtime/vm/instructions_mips.h
index 5567ae6..f9d7908 100644
--- a/runtime/vm/instructions_mips.h
+++ b/runtime/vm/instructions_mips.h
@@ -27,7 +27,9 @@
 
   // This constant length is only valid for inserted call patterns used for
   // lazy deoptimization. Regular call pattern may vary in length.
-  static const int kFixedLengthInBytes = 3 * Instr::kInstrSize;
+  static const int kFixedLengthInBytes = 4 * Instr::kInstrSize;
+
+  static void InsertAt(uword pc, uword target_address);
 
  private:
   uword Back(int n) const;
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 8cc2bcd..87e5407 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -245,12 +245,14 @@
 
 
 GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
-                                 TargetEntryInstr* normal_entry)
+                                 TargetEntryInstr* normal_entry,
+                                 intptr_t osr_id)
     : BlockEntryInstr(0, CatchClauseNode::kInvalidTryIndex),
       parsed_function_(parsed_function),
       normal_entry_(normal_entry),
       catch_entries_(),
       initial_definitions_(),
+      osr_id_(osr_id),
       spill_slot_count_(0),
       fixed_slot_count_(0) {
 }
@@ -787,6 +789,53 @@
 }
 
 
+bool BlockEntryInstr::PruneUnreachable(FlowGraphBuilder* builder,
+                                       GraphEntryInstr* graph_entry,
+                                       intptr_t osr_id,
+                                       BitVector* block_marks) {
+  // Search for the instruction with the OSR id.  Use a depth first search
+  // because basic blocks have not been discovered yet.  Prune unreachable
+  // blocks by replacing the normal entry with a jump to the block
+  // containing the OSR entry point.
+
+  // Do not visit blocks more than once.
+  if (block_marks->Contains(block_id())) return false;
+  block_marks->Add(block_id());
+
+  // Search this block for the OSR id.
+  Instruction* instr = this;
+  for (ForwardInstructionIterator it(this); !it.Done(); it.Advance()) {
+    instr = it.Current();
+    if (instr->GetDeoptId() == osr_id) {
+      // Sanity check that we found a stack check instruction.
+      ASSERT(instr->IsCheckStackOverflow());
+      // Loop stack check checks are always in join blocks so that they can
+      // be the target of a goto.
+      ASSERT(IsJoinEntry());
+      // The instruction should be the first instruction in the block so
+      // we can simply jump to the beginning of the block.
+      ASSERT(instr->previous() == this);
+
+      GotoInstr* goto_join = new GotoInstr(AsJoinEntry());
+      goto_join->deopt_id_ = deopt_id_;
+      graph_entry->normal_entry()->LinkTo(goto_join);
+      return true;
+    }
+  }
+
+  // Recursively search the successors.
+  for (intptr_t i = instr->SuccessorCount() - 1; i >= 0; --i) {
+    if (instr->SuccessorAt(i)->PruneUnreachable(builder,
+                                                graph_entry,
+                                                osr_id,
+                                                block_marks)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
 bool BlockEntryInstr::Dominates(BlockEntryInstr* other) const {
   // TODO(fschneider): Make this faster by e.g. storing dominators for each
   // block while computing the dominator tree.
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 0ad33b9..2285325 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -23,6 +23,7 @@
 class Definition;
 class Environment;
 class FlowGraph;
+class FlowGraphBuilder;
 class FlowGraphCompiler;
 class FlowGraphVisitor;
 class Instruction;
@@ -868,7 +869,7 @@
  private:
   friend class Definition;  // Needed for InsertBefore, InsertAfter.
 
-  // Classes that set deopt_id_.
+  // Classes that set or read deopt_id_.
   friend class UnboxIntegerInstr;
   friend class UnboxDoubleInstr;
   friend class UnboxFloat32x4Instr;
@@ -921,6 +922,7 @@
   friend class SmiToDoubleInstr;
   friend class DoubleToIntegerInstr;
   friend class BranchSimplifier;
+  friend class BlockEntryInstr;
 
   virtual void RawSetInputAt(intptr_t i, Value* value) = 0;
 
@@ -1143,6 +1145,13 @@
       intptr_t variable_count,
       intptr_t fixed_parameter_count);
 
+  // Perform a depth first search to prune code not reachable from an OSR
+  // entry point.
+  bool PruneUnreachable(FlowGraphBuilder* builder,
+                        GraphEntryInstr* graph_entry,
+                        intptr_t osr_id,
+                        BitVector* block_marks);
+
   virtual intptr_t InputCount() const { return 0; }
   virtual Value* InputAt(intptr_t i) const {
     UNREACHABLE();
@@ -1281,7 +1290,8 @@
 class GraphEntryInstr : public BlockEntryInstr {
  public:
   GraphEntryInstr(const ParsedFunction& parsed_function,
-                  TargetEntryInstr* normal_entry);
+                  TargetEntryInstr* normal_entry,
+                  intptr_t osr_id);
 
   DECLARE_INSTRUCTION(GraphEntry)
 
@@ -1302,6 +1312,8 @@
   }
   ConstantInstr* constant_null();
 
+  bool IsCompiledForOsr() const { return osr_id_ != Isolate::kNoDeoptId; }
+
   intptr_t spill_slot_count() const { return spill_slot_count_; }
   void set_spill_slot_count(intptr_t count) {
     ASSERT(count >= 0);
@@ -1336,6 +1348,7 @@
   TargetEntryInstr* normal_entry_;
   GrowableArray<CatchBlockEntryInstr*> catch_entries_;
   GrowableArray<Definition*> initial_definitions_;
+  const intptr_t osr_id_;
   intptr_t spill_slot_count_;
   intptr_t fixed_slot_count_;  // For try-catch in optimized code.
 
@@ -5907,10 +5920,11 @@
 
 class CheckStackOverflowInstr : public TemplateInstruction<0> {
  public:
-  explicit CheckStackOverflowInstr(intptr_t token_pos)
-      : token_pos_(token_pos) {}
+  CheckStackOverflowInstr(intptr_t token_pos, bool in_loop)
+      : token_pos_(token_pos), in_loop_(in_loop) {}
 
   intptr_t token_pos() const { return token_pos_; }
+  bool in_loop() const { return in_loop_; }
 
   DECLARE_INSTRUCTION(CheckStackOverflow)
 
@@ -5922,8 +5936,11 @@
 
   virtual bool MayThrow() const { return false; }
 
+  virtual void PrintOperandsTo(BufferFormatter* f) const;
+
  private:
   const intptr_t token_pos_;
+  const bool in_loop_;
 
   DISALLOW_COPY_AND_ASSIGN(CheckStackOverflowInstr);
 };
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index e6eb45b..444cd5c 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -23,6 +23,7 @@
 
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, propagate_ic_data);
+DECLARE_FLAG(bool, use_osr);
 
 // Generic summary for call instructions that have all arguments pushed
 // on the stack and return the result in a fixed register EAX.
@@ -2122,6 +2123,13 @@
                                   instruction_->deopt_id(),
                                   kStackOverflowRuntimeEntry,
                                   instruction_->locs());
+
+    if (FLAG_use_osr && !compiler->is_optimizing() && instruction_->in_loop()) {
+      // In unoptimized code, record loop stack checks as possible OSR entries.
+      compiler->AddCurrentDescriptor(PcDescriptors::kOsrEntry,
+                                     instruction_->deopt_id(),
+                                     0);  // No token position.
+    }
     compiler->pending_deoptimization_env_ = NULL;
     compiler->RestoreLiveRegisters(instruction_->locs());
     __ jmp(exit_label());
@@ -2139,6 +2147,14 @@
   __ cmpl(ESP,
           Address::Absolute(Isolate::Current()->stack_limit_address()));
   __ j(BELOW_EQUAL, slow_path->entry_label());
+  if (FLAG_use_osr && !compiler->is_optimizing() && in_loop()) {
+    // In unoptimized code check the usage counter to trigger OSR at loop
+    // stack checks.
+    __ LoadObject(EDI, compiler->parsed_function().function());
+    __ cmpl(FieldAddress(EDI, Function::usage_counter_offset()),
+            Immediate(2 * FLAG_optimization_counter_threshold));
+    __ j(GREATER_EQUAL, slow_path->entry_label());
+  }
   __ Bind(slow_path->exit_label());
 }
 
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 8bf386e..813378d 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -387,11 +387,13 @@
   const int kNumArgumentsChecked = 2;
 
   __ TraceSimMsg("EmitEqualityAsInstanceCall");
+  __ Comment("EmitEqualityAsInstanceCall");
   Label check_identity;
   __ lw(A1, Address(SP, 1 * kWordSize));
   __ lw(A0, Address(SP, 0 * kWordSize));
-  __ beq(A1, NULLREG, &check_identity);
-  __ beq(A0, NULLREG, &check_identity);
+  __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
+  __ beq(A1, TMP, &check_identity);
+  __ beq(A0, TMP, &check_identity);
 
   ICData& equality_ic_data = ICData::ZoneHandle();
   if (compiler->is_optimizing() && FLAG_propagate_ic_data) {
@@ -536,6 +538,7 @@
   Register temp = locs->temp(0).reg();
 
   __ TraceSimMsg("EmitEqualityAsPolymorphicCall");
+  __ Comment("EmitEqualityAsPolymorphicCall");
 
   LoadValueCid(compiler, temp, left,
                (ic_data.GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
@@ -608,12 +611,57 @@
 
 // Emit code when ICData's targets are all Object == (which is ===).
 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
-                                   const ICData& ic_data,
+                                   const ICData& orig_ic_data,
                                    const LocationSummary& locs,
                                    Token::Kind kind,
                                    BranchInstr* branch,
                                    intptr_t deopt_id) {
-  UNIMPLEMENTED();
+  ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
+  Register left = locs.in(0).reg();
+  Register right = locs.in(1).reg();
+  Register temp = locs.temp(0).reg();
+  Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality);
+
+  __ Comment("CheckedStrictEqual");
+
+  __ andi(CMPRES, left, Immediate(kSmiTagMask));
+  __ beq(CMPRES, ZR, deopt);
+  // 'left' is not Smi.
+  Label identity_compare;
+  __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
+  __ beq(right, TMP, &identity_compare);
+  __ beq(left, TMP, &identity_compare);
+
+  __ LoadClassId(temp, left);
+  const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
+  const intptr_t len = ic_data.NumberOfChecks();
+  for (intptr_t i = 0; i < len; i++) {
+    if (i == (len - 1)) {
+      __ BranchNotEqual(temp, ic_data.GetReceiverClassIdAt(i), deopt);
+    } else {
+      __ BranchEqual(temp, ic_data.GetReceiverClassIdAt(i), &identity_compare);
+    }
+  }
+  __ Bind(&identity_compare);
+  __ subu(CMPRES, left, right);
+  if (branch == NULL) {
+    Label done, is_equal;
+    Register result = locs.out().reg();
+    __ beq(CMPRES, ZR, &is_equal);
+    // Not equal.
+    __ LoadObject(result,
+                  (kind == Token::kEQ) ? Bool::False() : Bool::True());
+    __ b(&done);
+    __ Bind(&is_equal);
+    __ LoadObject(result,
+                  (kind == Token::kEQ) ? Bool::True() : Bool::False());
+    __ Bind(&done);
+
+  } else {
+    Condition cond = TokenKindToSmiCondition(kind);
+    __ mov(TMP, ZR);
+    branch->EmitBranchOnCondition(compiler, cond);
+  }
 }
 
 
@@ -633,8 +681,10 @@
   Register right = locs->in(1).reg();
   Label done, identity_compare, non_null_compare;
   __ TraceSimMsg("EmitGenericEqualityCompare");
-  __ beq(right, NULLREG, &identity_compare);
-  __ bne(left, NULLREG, &non_null_compare);
+  __ Comment("EmitGenericEqualityCompare");
+  __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
+  __ beq(right, TMP, &identity_compare);
+  __ bne(left, TMP, &non_null_compare);
 
   // Comparison with NULL is "===".
   __ Bind(&identity_compare);
@@ -685,6 +735,7 @@
                                 Token::Kind kind,
                                 BranchInstr* branch) {
   __ TraceSimMsg("EmitSmiComparisonOp");
+  __ Comment("EmitSmiComparisonOp");
   Location left = locs.in(0);
   Location right = locs.in(1);
   ASSERT(!left.IsConstant() || !right.IsConstant());
@@ -732,17 +783,45 @@
 }
 
 
+static Condition TokenKindToDoubleCondition(Token::Kind kind) {
+  switch (kind) {
+    case Token::kEQ: return EQ;
+    case Token::kNE: return NE;
+    case Token::kLT: return LT;
+    case Token::kGT: return GT;
+    case Token::kLTE: return LE;
+    case Token::kGTE: return GE;
+    default:
+      UNREACHABLE();
+      return VS;
+  }
+}
+
+
 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
                                    const LocationSummary& locs,
                                    Token::Kind kind,
                                    BranchInstr* branch) {
-  UNIMPLEMENTED();
+  DRegister left = locs.in(0).fpu_reg();
+  DRegister right = locs.in(1).fpu_reg();
+
+  __ Comment("DoubleComparisonOp(left=%d, right=%d)", left, right);
+
+  Condition true_condition = TokenKindToDoubleCondition(kind);
+  if (branch != NULL) {
+    compiler->EmitDoubleCompareBranch(
+        true_condition, left, right, branch);
+  } else {
+    compiler->EmitDoubleCompareBool(
+        true_condition, left, right, locs.out().reg());
+  }
 }
 
 
 void EqualityCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
   BranchInstr* kNoBranch = NULL;
+  __ Comment("EqualityCompareInstr");
   if (receiver_class_id() == kSmiCid) {
     EmitSmiComparisonOp(compiler, *locs(), kind(), kNoBranch);
     return;
@@ -785,6 +864,7 @@
 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
                                           BranchInstr* branch) {
   __ TraceSimMsg("EqualityCompareInstr");
+  __ Comment("EqualityCompareInstr:BranchCode");
   ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
   if (receiver_class_id() == kSmiCid) {
     // Deoptimizes if both arguments not Smi.
@@ -1001,7 +1081,9 @@
   // into the runtime system.
   uword entry = reinterpret_cast<uword>(native_c_function());
 #if defined(USING_SIMULATOR)
-  entry = Simulator::RedirectExternalReference(entry, Simulator::kNativeCall);
+  entry = Simulator::RedirectExternalReference(entry,
+                                               Simulator::kNativeCall,
+                                               function().NumParameters());
 #endif
   __ LoadImmediate(T5, entry);
   __ LoadImmediate(A1, NativeArguments::ComputeArgcTag(function()));
@@ -1205,7 +1287,28 @@
   if ((representation() == kUnboxedDouble) ||
       (representation() == kUnboxedMint) ||
       (representation() == kUnboxedFloat32x4)) {
-    UNIMPLEMENTED();
+    DRegister result = locs()->out().fpu_reg();
+    switch (class_id()) {
+      case kTypedDataInt32ArrayCid:
+        UNIMPLEMENTED();
+        break;
+      case kTypedDataUint32ArrayCid:
+        UNIMPLEMENTED();
+        break;
+      case kTypedDataFloat32ArrayCid:
+        // Load single precision float and promote to double.
+        __ lwc1(STMP1, element_address);
+        __ cvtds(result, STMP1);
+        break;
+      case kTypedDataFloat64ArrayCid:
+        __ LoadDFromOffset(result, index.reg(),
+            FlowGraphCompiler::DataOffsetFor(class_id()) - kHeapObjectTag);
+        break;
+      case kTypedDataFloat32x4ArrayCid:
+        UNIMPLEMENTED();
+        break;
+    }
+    return;
   }
 
   Register result = locs()->out().reg();
@@ -1582,7 +1685,8 @@
 
       if (field().is_nullable() && (field_cid != kNullCid)) {
         __ beq(CMPRES, ZR, &ok);
-        __ subu(CMPRES, value_reg, NULLREG);
+        __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
+        __ subu(CMPRES, value_reg, TMP);
       }
 
       if (ok_is_fall_through) {
@@ -1703,13 +1807,30 @@
 
 
 LocationSummary* InstanceOfInstr::MakeLocationSummary() const {
-  UNIMPLEMENTED();
-  return NULL;
+  const intptr_t kNumInputs = 3;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary =
+      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+  summary->set_in(0, Location::RegisterLocation(A0));
+  summary->set_in(1, Location::RegisterLocation(A2));
+  summary->set_in(2, Location::RegisterLocation(A1));
+  summary->set_out(Location::RegisterLocation(V0));
+  return summary;
 }
 
 
 void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
+  ASSERT(locs()->in(0).reg() == A0);  // Value.
+  ASSERT(locs()->in(1).reg() == A2);  // Instantiator.
+  ASSERT(locs()->in(2).reg() == A1);  // Instantiator type arguments.
+
+  __ Comment("InstanceOfInstr");
+  compiler->GenerateInstanceOf(token_pos(),
+                               deopt_id(),
+                               type(),
+                               negate_result(),
+                               locs());
+  ASSERT(locs()->out().reg() == V0);
 }
 
 
@@ -1739,14 +1860,19 @@
 
 LocationSummary*
 AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const {
-  UNIMPLEMENTED();
-  return NULL;
+  return MakeCallSummary();
 }
 
 
 void AllocateObjectWithBoundsCheckInstr::EmitNativeCode(
     FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
+  compiler->GenerateCallRuntime(token_pos(),
+                                deopt_id(),
+                                kAllocateObjectWithBoundsCheckRuntimeEntry,
+                                locs());
+  __ Drop(3);
+  ASSERT(locs()->out().reg() == V0);
+  __ Pop(V0);  // Pop new instance.
 }
 
 
@@ -1793,7 +1919,8 @@
   Label type_arguments_instantiated;
   const intptr_t len = type_arguments().Length();
   if (type_arguments().IsRawInstantiatedRaw(len)) {
-    __ beq(instantiator_reg, NULLREG, &type_arguments_instantiated);
+    __ BranchEqual(instantiator_reg, reinterpret_cast<int32_t>(Object::null()),
+                   &type_arguments_instantiated);
   }
   // Instantiate non-null type arguments.
   // A runtime call to instantiate the type arguments is required.
@@ -1846,7 +1973,8 @@
   // the type arguments.
   Label type_arguments_instantiated;
   ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
-  __ beq(instantiator_reg, NULLREG, &type_arguments_instantiated);
+  __ BranchEqual(instantiator_reg, reinterpret_cast<int32_t>(Object::null()),
+                 &type_arguments_instantiated);
   // Instantiate non-null type arguments.
   // In the non-factory case, we rely on the allocation stub to
   // instantiate the type arguments.
@@ -1886,7 +2014,8 @@
   // the type arguments and do not pass the instantiator.
   ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
   Label instantiator_not_null;
-  __ bne(instantiator_reg, NULLREG, &instantiator_not_null);
+  __ BranchNotEqual(instantiator_reg, reinterpret_cast<int32_t>(Object::null()),
+                    &instantiator_not_null);
   // Null was used in VisitExtractConstructorTypeArguments as the
   // instantiated type arguments, no proper instantiator needed.
   __ LoadImmediate(instantiator_reg,
@@ -2067,7 +2196,9 @@
     const intptr_t kCountLimit = 0x1F;
     const intptr_t value = Smi::Cast(constant).Value();
     if (value == 0) {
-      // No code needed.
+      if (result != left) {
+        __ mov(result, left);
+      }
     } else if ((value < 0) || (value >= kCountLimit)) {
       // This condition may not be known earlier in some cases because
       // of constant propagation, inlining, etc.
@@ -2101,6 +2232,7 @@
       const intptr_t left_int = Smi::Cast(obj).Value();
       if (left_int == 0) {
         __ bltz(right, deopt);
+        __ mov(result, ZR);
         return;
       }
       const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
@@ -2163,24 +2295,33 @@
 
 LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
   const intptr_t kNumInputs = 2;
+  const intptr_t kNumTemps = op_kind() == Token::kADD ? 1 : 0;
+  LocationSummary* summary =
+      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
   if (op_kind() == Token::kTRUNCDIV) {
-    UNIMPLEMENTED();
-    return NULL;
-  } else {
-    const intptr_t kNumTemps = op_kind() == Token::kADD ? 1 : 0;
-    LocationSummary* summary =
-        new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
-    summary->set_in(0, Location::RequiresRegister());
-    summary->set_in(1, Location::RegisterOrSmiConstant(right()));
-    if (op_kind() == Token::kADD) {
-      // Need an extra temp for the overflow detection code.
-      summary->set_temp(0, Location::RequiresRegister());
+    if (RightIsPowerOfTwoConstant()) {
+      summary->set_in(0, Location::RequiresRegister());
+      ConstantInstr* right_constant = right()->definition()->AsConstant();
+      summary->set_in(1, Location::Constant(right_constant->value()));
+      summary->set_out(Location::RequiresRegister());
+    } else {
+      // Both inputs must be writable because they will be untagged.
+      summary->set_in(0, Location::WritableRegister());
+      summary->set_in(1, Location::WritableRegister());
+      summary->set_out(Location::RequiresRegister());
     }
-    // We make use of 3-operand instructions by not requiring result register
-    // to be identical to first input register as on Intel.
-    summary->set_out(Location::RequiresRegister());
     return summary;
   }
+  summary->set_in(0, Location::RequiresRegister());
+  summary->set_in(1, Location::RegisterOrSmiConstant(right()));
+  if (op_kind() == Token::kADD) {
+    // Need an extra temp for the overflow detection code.
+    summary->set_temp(0, Location::RequiresRegister());
+  }
+  // We make use of 3-operand instructions by not requiring result register
+  // to be identical to first input register as on Intel.
+  summary->set_out(Location::RequiresRegister());
+  return summary;
 }
 
 
@@ -2251,7 +2392,33 @@
         break;
       }
       case Token::kTRUNCDIV: {
-        UNIMPLEMENTED();
+        const intptr_t value = Smi::Cast(constant).Value();
+        if (value == 1) {
+          if (result != left) {
+            __ mov(result, left);
+          }
+          break;
+        } else if (value == -1) {
+          // Check the corner case of dividing the 'MIN_SMI' with -1, in which
+          // case we cannot negate the result.
+          __ BranchEqual(left, 0x80000000, deopt);
+          __ subu(result, ZR, left);
+          break;
+        }
+        ASSERT((value != 0) && Utils::IsPowerOfTwo(Utils::Abs(value)));
+        const intptr_t shift_count =
+            Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize;
+        ASSERT(kSmiTagSize == 1);
+        __ sra(TMP, left, 31);
+        ASSERT(shift_count > 1);  // 1, -1 case handled above.
+        __ sll(TMP, TMP, 32 - shift_count);
+        __ addu(left, left, TMP);
+        ASSERT(shift_count > 0);
+        __ sra(result, left, shift_count);
+        if (value < 0) {
+          __ subu(result, ZR, result);
+        }
+        __ SmiTag(result);
         break;
       }
       case Token::kBIT_AND: {
@@ -2293,7 +2460,9 @@
 
         if (value == 0) {
           // TODO(vegorov): should be handled outside.
-          __ break_(0);
+          if (result != left) {
+            __ mov(result, left);
+          }
           break;
         } else if (value < 0) {
           // TODO(vegorov): should be handled outside.
@@ -2366,7 +2535,16 @@
       break;
     }
     case Token::kTRUNCDIV: {
-      UNIMPLEMENTED();
+      // Handle divide by zero in runtime.
+      __ beq(right, ZR, deopt);
+      __ SmiUntag(left);
+      __ SmiUntag(right);
+      __ div(left, right);
+      __ mflo(result);
+      // Check the corner case of dividing the 'MIN_SMI' with -1, in which
+      // case we cannot tag the result.
+      __ BranchEqual(V0, 0x40000000, deopt);
+      __ SmiTag(result);
       break;
     }
     case Token::kSHR: {
@@ -2399,35 +2577,142 @@
 
 
 LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
-  UNIMPLEMENTED();
-  return NULL;
+  intptr_t left_cid = left()->Type()->ToCid();
+  intptr_t right_cid = right()->Type()->ToCid();
+  ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
+  const intptr_t kNumInputs = 2;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary =
+    new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+  summary->set_in(0, Location::RequiresRegister());
+  summary->set_in(1, Location::RequiresRegister());
+  return summary;
 }
 
 
 void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
+  Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryDoubleOp);
+  intptr_t left_cid = left()->Type()->ToCid();
+  intptr_t right_cid = right()->Type()->ToCid();
+  Register left = locs()->in(0).reg();
+  Register right = locs()->in(1).reg();
+  if (left_cid == kSmiCid) {
+    __ andi(CMPRES, right, Immediate(kSmiTagMask));
+  } else if (right_cid == kSmiCid) {
+    __ andi(CMPRES, left, Immediate(kSmiTagMask));
+  } else {
+    __ or_(TMP, left, right);
+    __ andi(CMPRES, TMP, Immediate(kSmiTagMask));
+  }
+  __ beq(CMPRES, ZR, deopt);
 }
 
 
 LocationSummary* BoxDoubleInstr::MakeLocationSummary() const {
-  UNIMPLEMENTED();
-  return NULL;
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary =
+      new LocationSummary(kNumInputs,
+                          kNumTemps,
+                          LocationSummary::kCallOnSlowPath);
+  summary->set_in(0, Location::RequiresFpuRegister());
+  summary->set_out(Location::RequiresRegister());
+  return summary;
 }
 
 
+class BoxDoubleSlowPath : public SlowPathCode {
+ public:
+  explicit BoxDoubleSlowPath(BoxDoubleInstr* instruction)
+      : instruction_(instruction) { }
+
+  virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+    __ Comment("BoxDoubleSlowPath");
+    __ Bind(entry_label());
+    const Class& double_class = compiler->double_class();
+    const Code& stub =
+        Code::Handle(StubCode::GetAllocationStubForClass(double_class));
+    const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+
+    LocationSummary* locs = instruction_->locs();
+    locs->live_registers()->Remove(locs->out());
+
+    compiler->SaveLiveRegisters(locs);
+    compiler->GenerateCall(Scanner::kDummyTokenIndex,  // No token position.
+                           &label,
+                           PcDescriptors::kOther,
+                           locs);
+    if (locs->out().reg() != V0) {
+      __ mov(locs->out().reg(), V0);
+    }
+    compiler->RestoreLiveRegisters(locs);
+
+    __ b(exit_label());
+  }
+
+ private:
+  BoxDoubleInstr* instruction_;
+};
+
+
 void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
+  BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
+  compiler->AddSlowPathCode(slow_path);
+
+  Register out_reg = locs()->out().reg();
+  DRegister value = locs()->in(0).fpu_reg();
+
+  __ TryAllocate(compiler->double_class(),
+                 slow_path->entry_label(),
+                 out_reg);
+  __ Bind(slow_path->exit_label());
+  __ StoreDToOffset(value, out_reg, Double::value_offset() - kHeapObjectTag);
 }
 
 
 LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
-  UNIMPLEMENTED();
-  return NULL;
+  const intptr_t kNumInputs = 1;
+  const intptr_t value_cid = value()->Type()->ToCid();
+  const bool needs_writable_input = (value_cid == kSmiCid);
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary =
+      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+  summary->set_in(0, needs_writable_input
+                     ? Location::WritableRegister()
+                     : Location::RequiresRegister());
+  summary->set_out(Location::RequiresFpuRegister());
+  return summary;
 }
 
 
 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
+  const intptr_t value_cid = value()->Type()->ToCid();
+  const Register value = locs()->in(0).reg();
+  const DRegister result = locs()->out().fpu_reg();
+
+  if (value_cid == kDoubleCid) {
+    __ LoadDFromOffset(result, value, Double::value_offset() - kHeapObjectTag);
+  } else if (value_cid == kSmiCid) {
+    __ SmiUntag(value);  // Untag input before conversion.
+    __ mtc1(value, STMP1);
+    __ cvtdw(result, STMP1);
+  } else {
+    Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp);
+    Label is_smi, done;
+
+    __ andi(CMPRES, value, Immediate(kSmiTagMask));
+    __ beq(CMPRES, ZR, &is_smi);
+    __ LoadClassId(TMP, value);
+    __ BranchNotEqual(TMP, kDoubleCid, deopt);
+    __ LoadDFromOffset(result, value, Double::value_offset() - kHeapObjectTag);
+    __ b(&done);
+    __ Bind(&is_smi);
+    // TODO(regis): Why do we preserve value here but not above?
+    __ sra(TMP, value, 1);
+    __ mtc1(TMP, STMP1);
+    __ cvtdw(result, STMP1);
+    __ Bind(&done);
+  }
 }
 
 
@@ -2476,13 +2761,28 @@
 
 
 LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const {
-  UNIMPLEMENTED();
-  return NULL;
+  const intptr_t kNumInputs = 2;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary =
+      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+  summary->set_in(0, Location::RequiresFpuRegister());
+  summary->set_in(1, Location::RequiresFpuRegister());
+  summary->set_out(Location::RequiresFpuRegister());
+  return summary;
 }
 
 
 void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
+  DRegister left = locs()->in(0).fpu_reg();
+  DRegister right = locs()->in(1).fpu_reg();
+  DRegister result = locs()->out().fpu_reg();
+  switch (op_kind()) {
+    case Token::kADD: __ addd(result, left, right); break;
+    case Token::kSUB: __ subd(result, left, right); break;
+    case Token::kMUL: __ muld(result, left, right); break;
+    case Token::kDIV: __ divd(result, left, right); break;
+    default: UNREACHABLE();
+  }
 }
 
 
@@ -2707,24 +3007,56 @@
 
 
 LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const {
-  UNIMPLEMENTED();
-  return NULL;
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary =
+      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+  summary->set_in(0, Location::RequiresRegister());
+  // We make use of 3-operand instructions by not requiring result register
+  // to be identical to first input register as on Intel.
+  summary->set_out(Location::RequiresRegister());
+  return summary;
 }
 
 
 void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
+  Register value = locs()->in(0).reg();
+  Register result = locs()->out().reg();
+  switch (op_kind()) {
+    case Token::kNEGATE: {
+      Label* deopt = compiler->AddDeoptStub(deopt_id(),
+                                            kDeoptUnaryOp);
+      __ SubuDetectOverflow(result, ZR, value, CMPRES);
+      __ bltz(CMPRES, deopt);
+      break;
+    }
+    case Token::kBIT_NOT:
+      __ nor(result, value, ZR);
+      __ addiu(result, result, Immediate(-1));  // Remove inverted smi-tag.
+      break;
+    default:
+      UNREACHABLE();
+  }
 }
 
 
 LocationSummary* SmiToDoubleInstr::MakeLocationSummary() const {
-  UNIMPLEMENTED();
-  return NULL;
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* result =
+      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+  result->set_in(0, Location::WritableRegister());
+  result->set_out(Location::RequiresFpuRegister());
+  return result;
 }
 
 
 void SmiToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
+  Register value = locs()->in(0).reg();
+  FpuRegister result = locs()->out().fpu_reg();
+  __ SmiUntag(value);
+  __ mtc1(value, STMP1);
+  __ cvtdw(result, STMP1);
 }
 
 
@@ -2762,13 +3094,34 @@
 
 
 LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary() const {
-  UNIMPLEMENTED();
-  return NULL;
+  ASSERT((InputCount() == 1) || (InputCount() == 2));
+  const intptr_t kNumTemps = 0;
+  LocationSummary* result =
+      new LocationSummary(InputCount(), kNumTemps, LocationSummary::kCall);
+  result->set_in(0, Location::FpuRegisterLocation(D6));
+  if (InputCount() == 2) {
+    result->set_in(1, Location::FpuRegisterLocation(D7));
+  }
+  result->set_out(Location::FpuRegisterLocation(D0));
+  return result;
 }
 
 
 void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
+  // For pow-function return NAN if exponent is NAN.
+  Label do_call, skip_call;
+  if (recognized_kind() == MethodRecognizer::kDoublePow) {
+    DRegister exp = locs()->in(1).fpu_reg();
+    __ cund(exp, exp);
+    __ bc1f(&do_call);
+    // Exponent is NaN, return NaN.
+    __ movd(locs()->out().fpu_reg(), exp);
+    __ b(&skip_call);
+  }
+  __ Bind(&do_call);
+  // double values are passed and returned in vfp registers.
+  __ CallRuntime(TargetFunction());
+  __ Bind(&skip_call);
 }
 
 
@@ -2844,7 +3197,8 @@
   if (null_check()) {
     Label* deopt = compiler->AddDeoptStub(deopt_id(),
                                           kDeoptCheckClass);
-    __ beq(locs()->in(0).reg(), NULLREG, deopt);
+    __ BranchEqual(locs()->in(0).reg(),
+        reinterpret_cast<int32_t>(Object::null()), deopt);
     return;
   }
 
@@ -3131,6 +3485,7 @@
 // Special code for numbers (compare values instead of references.)
 void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   __ TraceSimMsg("StrictCompareInstr");
+  __ Comment("StrictCompareInstr");
   ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
   Location left = locs()->in(0);
   Location right = locs()->in(1);
@@ -3281,6 +3636,7 @@
 
 void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   __ TraceSimMsg("AllocateObjectInstr");
+  __ Comment("AllocateObjectInstr");
   const Class& cls = Class::ZoneHandle(constructor().Owner());
   const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls));
   const ExternalLabel label(cls.ToCString(), stub.EntryPoint());
@@ -3298,6 +3654,7 @@
 
 
 void CreateClosureInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  __ Comment("CreateClosureInstr");
   const Function& closure_function = function();
   ASSERT(!closure_function.IsImplicitStaticClosureFunction());
   const Code& stub = Code::Handle(
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 357c907..a55f175 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -24,6 +24,7 @@
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, propagate_ic_data);
 DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
+DECLARE_FLAG(bool, use_osr);
 
 // Generic summary for call instructions that have all arguments pushed
 // on the stack and return the result in a fixed register RAX.
@@ -2105,6 +2106,13 @@
                                   instruction_->deopt_id(),
                                   kStackOverflowRuntimeEntry,
                                   instruction_->locs());
+
+    if (FLAG_use_osr && !compiler->is_optimizing() && instruction_->in_loop()) {
+      // In unoptimized code, record loop stack checks as possible OSR entries.
+      compiler->AddCurrentDescriptor(PcDescriptors::kOsrEntry,
+                                     instruction_->deopt_id(),
+                                     0);  // No token position.
+    }
     compiler->pending_deoptimization_env_ = NULL;
     compiler->RestoreLiveRegisters(instruction_->locs());
     __ jmp(exit_label());
@@ -2124,6 +2132,14 @@
   __ movq(temp, Immediate(Isolate::Current()->stack_limit_address()));
   __ cmpq(RSP, Address(temp, 0));
   __ j(BELOW_EQUAL, slow_path->entry_label());
+  if (FLAG_use_osr && !compiler->is_optimizing() && in_loop()) {
+    // In unoptimized code check the usage counter to trigger OSR at loop
+    // stack checks.
+    __ LoadObject(temp, compiler->parsed_function().function());
+    __ cmpq(FieldAddress(temp, Function::usage_counter_offset()),
+            Immediate(2 * FLAG_optimization_counter_threshold));
+    __ j(GREATER_EQUAL, slow_path->entry_label());
+  }
   __ Bind(slow_path->exit_label());
 }
 
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 9ba29ff..4f8588b 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -109,19 +109,20 @@
                               FieldAddress(T0, Array::length_offset()),
                               T2);
 
+  __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null()));
   // Initialize all array elements to raw_null.
   // T0: new object start as a tagged pointer.
   // T1: new object end address.
   // T2: iterator which initially points to the start of the variable
   // data area to be initialized.
-  // NULLREG: null
+  // T7: null
   __ AddImmediate(T2, T0, sizeof(RawArray) - kHeapObjectTag);
 
   Label done;
   Label init_loop;
   __ Bind(&init_loop);
   __ BranchUnsignedGreaterEqual(T2, T1, &done);
-  __ sw(NULLREG, Address(T2, 0));
+  __ sw(T7, Address(T2, 0));
   __ b(&init_loop);
   __ delay_slot()->addiu(T2, T2, Immediate(kWordSize));
   __ Bind(&done);
@@ -201,13 +202,14 @@
     __ lw(T2, Address(SP, 0 * kWordSize));  // Value.
 
     // Null value is valid for any type.
-    __ beq(T2, NULLREG, &checked_ok);
+    __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null()));
+    __ beq(T2, T7, &checked_ok);
     __ delay_slot()->lw(T1, Address(SP, 2 * kWordSize));  // Array.
 
     __ lw(T1, FieldAddress(T1, type_args_field_offset));
 
     // T1: Type arguments of array.
-    __ beq(T1, NULLREG, &checked_ok);
+    __ beq(T1, T7, &checked_ok);
 
     // Check if it's dynamic.
     // For now handle only TypeArguments and bail out if InstantiatedTypeArgs.
@@ -462,8 +464,9 @@
   __ StoreIntoObject(T2,
                      FieldAddress(T1, Array::data_offset()),
                      T0);
+  __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null()));
   __ Ret();
-  __ delay_slot()->mov(V0, NULLREG);
+  __ delay_slot()->mov(V0, T7);
   __ Bind(&fall_through);
   return false;
 }
@@ -836,7 +839,6 @@
 
 bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) {
   Label fall_through;
-  __ Untested("Intrinsifier::Integer_bitXorFromInteger");
 
   TestBothArgumentsSmis(assembler, &fall_through);  // Checks two smis.
   __ Ret();
@@ -1138,24 +1140,15 @@
 // returns false. Any non-double arg1 causes control flow to fall through to the
 // slow case (compiled method body).
 static bool CompareDoubles(Assembler* assembler, Condition true_condition) {
-  Label is_smi, no_conversion, no_NaN, fall_through;
+  Label is_smi, double_op, no_NaN, fall_through;
+  __ Comment("CompareDoubles Intrinsic");
 
   TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
   // Both arguments are double, right operand is in T0.
-  __ lwc1(F2, FieldAddress(T0, Double::value_offset()));
-  __ b(&no_conversion);
-  __ delay_slot()->lwc1(F3,
-      FieldAddress(T0, Double::value_offset() + kWordSize));
-
-  __ Bind(&is_smi);
-  __ SmiUntag(T0);
-  __ mtc1(T0, F4);
-  __ cvtdw(D1, F4);
-
-  __ Bind(&no_conversion);
+  __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag);
+  __ Bind(&double_op);
   __ lw(T0, Address(SP, 1 * kWordSize));  // Left argument.
-  __ lwc1(F0, FieldAddress(T0, Double::value_offset()));
-  __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize));
+  __ LoadDFromOffset(D0, T0, Double::value_offset() - kHeapObjectTag);
   // Now, left is in D0, right is in D1.
 
   __ cund(D0, D1);  // Check for NaN.
@@ -1165,11 +1158,11 @@
   __ Bind(&no_NaN);
 
   switch (true_condition) {
-    case EQ: __ ceqd(D1, D0); break;
-    case LT: __ coltd(D1, D0); break;
-    case LE: __ coled(D1, D0); break;
-    case GT: __ coltd(D0, D1); break;
-    case GE: __ coled(D0, D1); break;
+    case EQ: __ ceqd(D0, D1); break;
+    case LT: __ coltd(D0, D1); break;
+    case LE: __ coled(D0, D1); break;
+    case GT: __ coltd(D1, D0); break;
+    case GE: __ coled(D1, D0); break;
     default: {
       // Only passing the above conditions to this function.
       UNREACHABLE();
@@ -1184,6 +1177,14 @@
   __ Bind(&is_true);
   __ LoadObject(V0, Bool::True());
   __ Ret();
+
+
+  __ Bind(&is_smi);
+  __ SmiUntag(T0);
+  __ mtc1(T0, STMP1);
+  __ cvtdw(D1, STMP1);
+  __ b(&double_op);
+
   __ Bind(&fall_through);
   return false;
 }
@@ -1268,7 +1269,6 @@
 // Left is double right is integer (Bigint, Mint or Smi)
 bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) {
   Label fall_through;
-  __ Untested("Intrinsifier::Double_mulFromInteger");
   // Only Smi-s allowed.
   __ lw(T0, Address(SP, 0 * kWordSize));
   __ andi(CMPRES, T0, Immediate(kSmiTagMask));
@@ -1320,7 +1320,7 @@
 
 bool Intrinsifier::Double_getIsNaN(Assembler* assembler) {
   Label is_true;
-  __ Untested("Intrinsifier::Double_getIsNaN");
+
   __ lw(T0, Address(SP, 0 * kWordSize));
   __ lwc1(F0, FieldAddress(T0, Double::value_offset()));
   __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize));
@@ -1337,7 +1337,6 @@
 
 bool Intrinsifier::Double_getIsNegative(Assembler* assembler) {
   Label is_false, is_true, is_zero;
-  __ Untested("Intrinsifier::Double_getIsNegative");
   __ lw(T0, Address(SP, 0 * kWordSize));
   __ lwc1(F0, FieldAddress(T0, Double::value_offset()));
   __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize));
@@ -1390,11 +1389,9 @@
 
 bool Intrinsifier::Math_sqrt(Assembler* assembler) {
   Label fall_through, is_smi, double_op;
-  __ Untested("Intrinsifier::Math_sqrt");
   TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
   // Argument is double and is in T0.
-  __ lwc1(F0, FieldAddress(T0, Double::value_offset()));
-  __ lwc1(F1, FieldAddress(T0, Double::value_offset() + kWordSize));
+  __ LoadDFromOffset(D1, T0, Double::value_offset() - kHeapObjectTag);
   __ Bind(&double_op);
   __ sqrtd(D0, D1);
   const Class& double_class = Class::Handle(
@@ -1447,8 +1444,6 @@
   ASSERT(Utils::IsUint(32, a_int_value));
   int32_t a_int32_value = static_cast<int32_t>(a_int_value);
 
-  __ Untested("Random_nextState");
-
   __ lw(T0, Address(SP, 0 * kWordSize));  // Receiver.
   __ lw(T1, FieldAddress(T0, state_field.Offset()));  // Field '_state'.
 
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
new file mode 100644
index 0000000..c79d3ce
--- /dev/null
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -0,0 +1,869 @@
+// 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 "include/dart_mirrors_api.h"
+
+#include "platform/assert.h"
+#include "vm/class_finalizer.h"
+#include "vm/dart.h"
+#include "vm/dart_api_impl.h"
+#include "vm/dart_api_state.h"
+#include "vm/dart_entry.h"
+#include "vm/exceptions.h"
+#include "vm/growable_array.h"
+#include "vm/object.h"
+#include "vm/resolver.h"
+#include "vm/stack_frame.h"
+#include "vm/symbols.h"
+
+namespace dart {
+
+// When we want to return a handle to a type to the user, we handle
+// class-types differently than some other types.
+static Dart_Handle TypeToHandle(Isolate* isolate,
+                                const char* function_name,
+                                const AbstractType& type) {
+  if (type.IsMalformed()) {
+    const Error& error = Error::Handle(type.malformed_error());
+    return Api::NewError("%s: malformed type encountered: %s.",
+        function_name, error.ToErrorCString());
+  } else if (type.HasResolvedTypeClass()) {
+    const Class& cls = Class::Handle(isolate, type.type_class());
+#if defined(DEBUG)
+    const Library& lib = Library::Handle(cls.library());
+    if (lib.IsNull()) {
+      ASSERT(cls.IsDynamicClass() || cls.IsVoidClass());
+    }
+#endif
+    return Api::NewHandle(isolate, cls.raw());
+  } else if (type.IsTypeParameter()) {
+    return Api::NewHandle(isolate, type.raw());
+  } else {
+    return Api::NewError("%s: unexpected type '%s' encountered.",
+                         function_name, type.ToCString());
+  }
+}
+
+
+// --- Classes and Interfaces Reflection ---
+
+DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle clazz) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
+  if (cls.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, clazz, Class);
+  }
+  return Api::NewHandle(isolate, cls.UserVisibleName());
+}
+
+
+DART_EXPORT Dart_Handle Dart_ClassGetLibrary(Dart_Handle clazz) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
+  if (cls.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, clazz, Class);
+  }
+
+#if defined(DEBUG)
+  const Library& lib = Library::Handle(cls.library());
+  if (lib.IsNull()) {
+    // ASSERT(cls.IsDynamicClass() || cls.IsVoidClass());
+    if (!cls.IsDynamicClass() && !cls.IsVoidClass()) {
+      fprintf(stderr, "NO LIBRARY: %s\n", cls.ToCString());
+    }
+  }
+#endif
+
+  return Api::NewHandle(isolate, cls.library());
+}
+
+
+DART_EXPORT Dart_Handle Dart_ClassGetInterfaceCount(Dart_Handle clazz,
+                                                    intptr_t* count) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
+  if (cls.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, clazz, Class);
+  }
+
+  const Array& interface_types = Array::Handle(isolate, cls.interfaces());
+  if (interface_types.IsNull()) {
+    *count = 0;
+  } else {
+    *count = interface_types.Length();
+  }
+  return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_ClassGetInterfaceAt(Dart_Handle clazz,
+                                                 intptr_t index) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
+  if (cls.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, clazz, Class);
+  }
+
+  // Finalize all classes.
+  Dart_Handle state = Api::CheckIsolateState(isolate);
+  if (::Dart_IsError(state)) {
+    return state;
+  }
+
+  const Array& interface_types = Array::Handle(isolate, cls.interfaces());
+  if (index < 0 || index >= interface_types.Length()) {
+    return Api::NewError("%s: argument 'index' out of bounds.", CURRENT_FUNC);
+  }
+  Type& interface_type = Type::Handle(isolate);
+  interface_type ^= interface_types.At(index);
+  if (interface_type.HasResolvedTypeClass()) {
+    return Api::NewHandle(isolate, interface_type.type_class());
+  }
+  const String& type_name =
+      String::Handle(isolate, interface_type.TypeClassName());
+  return Api::NewError("%s: internal error: found unresolved type class '%s'.",
+                       CURRENT_FUNC, type_name.ToCString());
+}
+
+
+DART_EXPORT bool Dart_ClassIsTypedef(Dart_Handle clazz) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
+  if (cls.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, clazz, Class);
+  }
+  // For now we represent typedefs as non-canonical signature classes.
+  // I anticipate this may change if we make typedefs more general.
+  return cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass();
+}
+
+
+DART_EXPORT Dart_Handle Dart_ClassGetTypedefReferent(Dart_Handle clazz) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
+  if (cls.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, clazz, Class);
+  }
+
+  if (!cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass()) {
+    const String& cls_name = String::Handle(cls.UserVisibleName());
+    return Api::NewError("%s: class '%s' is not a typedef class. "
+                         "See Dart_ClassIsTypedef.",
+                         CURRENT_FUNC, cls_name.ToCString());
+  }
+
+  const Function& func = Function::Handle(isolate, cls.signature_function());
+  return Api::NewHandle(isolate, func.signature_class());
+}
+
+
+DART_EXPORT bool Dart_ClassIsFunctionType(Dart_Handle clazz) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
+  if (cls.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, clazz, Class);
+  }
+  // A class represents a function type when it is a canonical
+  // signature class.
+  return cls.IsCanonicalSignatureClass();
+}
+
+
+DART_EXPORT Dart_Handle Dart_ClassGetFunctionTypeSignature(Dart_Handle clazz) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
+  if (cls.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, clazz, Class);
+  }
+  if (!cls.IsCanonicalSignatureClass()) {
+    const String& cls_name = String::Handle(cls.UserVisibleName());
+    return Api::NewError("%s: class '%s' is not a function-type class. "
+                         "See Dart_ClassIsFunctionType.",
+                         CURRENT_FUNC, cls_name.ToCString());
+  }
+  return Api::NewHandle(isolate, cls.signature_function());
+}
+
+
+// --- Function and Variable Reflection ---
+
+// Outside of the vm, we expose setter names with a trailing '='.
+static bool HasExternalSetterSuffix(const String& name) {
+  return name.CharAt(name.Length() - 1) == '=';
+}
+
+
+static RawString* RemoveExternalSetterSuffix(const String& name) {
+  ASSERT(HasExternalSetterSuffix(name));
+  return String::SubString(name, 0, name.Length() - 1);
+}
+
+
+DART_EXPORT Dart_Handle Dart_GetFunctionNames(Dart_Handle target) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
+  if (obj.IsError()) {
+    return target;
+  }
+
+  const GrowableObjectArray& names =
+      GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
+  Function& func = Function::Handle();
+  String& name = String::Handle();
+
+  if (obj.IsClass()) {
+    const Class& cls = Class::Cast(obj);
+    const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
+    if (!error.IsNull()) {
+      return Api::NewHandle(isolate, error.raw());
+    }
+    const Array& func_array = Array::Handle(cls.functions());
+
+    // Some special types like 'dynamic' have a null functions list.
+    if (!func_array.IsNull()) {
+      for (intptr_t i = 0; i < func_array.Length(); ++i) {
+        func ^= func_array.At(i);
+
+        // Skip implicit getters and setters.
+        if (func.kind() == RawFunction::kImplicitGetter ||
+            func.kind() == RawFunction::kImplicitSetter ||
+            func.kind() == RawFunction::kConstImplicitGetter ||
+            func.kind() == RawFunction::kMethodExtractor) {
+          continue;
+        }
+
+        name = func.UserVisibleName();
+        names.Add(name);
+      }
+    }
+  } else if (obj.IsLibrary()) {
+    const Library& lib = Library::Cast(obj);
+    DictionaryIterator it(lib);
+    Object& obj = Object::Handle();
+    while (it.HasNext()) {
+      obj = it.GetNext();
+      if (obj.IsFunction()) {
+        func ^= obj.raw();
+        name = func.UserVisibleName();
+        names.Add(name);
+      }
+    }
+  } else {
+    return Api::NewError(
+        "%s expects argument 'target' to be a class or library.",
+        CURRENT_FUNC);
+  }
+  return Api::NewHandle(isolate, Array::MakeArray(names));
+}
+
+
+DART_EXPORT Dart_Handle Dart_LookupFunction(Dart_Handle target,
+                                            Dart_Handle function_name) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
+  if (obj.IsError()) {
+    return target;
+  }
+  const String& func_name = Api::UnwrapStringHandle(isolate, function_name);
+  if (func_name.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function_name, String);
+  }
+
+  Function& func = Function::Handle(isolate);
+  String& tmp_name = String::Handle(isolate);
+  if (obj.IsClass()) {
+    const Class& cls = Class::Cast(obj);
+
+    // Case 1.  Lookup the unmodified function name.
+    func = cls.LookupFunctionAllowPrivate(func_name);
+
+    // Case 2.  Lookup the function without the external setter suffix
+    // '='.  Make sure to do this check after the regular lookup, so
+    // that we don't interfere with operator lookups (like ==).
+    if (func.IsNull() && HasExternalSetterSuffix(func_name)) {
+      tmp_name = RemoveExternalSetterSuffix(func_name);
+      tmp_name = Field::SetterName(tmp_name);
+      func = cls.LookupFunctionAllowPrivate(tmp_name);
+    }
+
+    // Case 3.  Lookup the funciton with the getter prefix prepended.
+    if (func.IsNull()) {
+      tmp_name = Field::GetterName(func_name);
+      func = cls.LookupFunctionAllowPrivate(tmp_name);
+    }
+
+    // Case 4.  Lookup the function with a . appended to find the
+    // unnamed constructor.
+    if (func.IsNull()) {
+      tmp_name = String::Concat(func_name, Symbols::Dot());
+      func = cls.LookupFunctionAllowPrivate(tmp_name);
+    }
+  } else if (obj.IsLibrary()) {
+    const Library& lib = Library::Cast(obj);
+
+    // Case 1.  Lookup the unmodified function name.
+    func = lib.LookupFunctionAllowPrivate(func_name);
+
+    // Case 2.  Lookup the function without the external setter suffix
+    // '='.  Make sure to do this check after the regular lookup, so
+    // that we don't interfere with operator lookups (like ==).
+    if (func.IsNull() && HasExternalSetterSuffix(func_name)) {
+      tmp_name = RemoveExternalSetterSuffix(func_name);
+      tmp_name = Field::SetterName(tmp_name);
+      func = lib.LookupFunctionAllowPrivate(tmp_name);
+    }
+
+    // Case 3.  Lookup the function with the getter prefix prepended.
+    if (func.IsNull()) {
+      tmp_name = Field::GetterName(func_name);
+      func = lib.LookupFunctionAllowPrivate(tmp_name);
+    }
+  } else {
+    return Api::NewError(
+        "%s expects argument 'target' to be a class or library.",
+        CURRENT_FUNC);
+  }
+
+#if defined(DEBUG)
+  if (!func.IsNull()) {
+    // We only provide access to a subset of function kinds.
+    RawFunction::Kind func_kind = func.kind();
+    ASSERT(func_kind == RawFunction::kRegularFunction ||
+           func_kind == RawFunction::kGetterFunction ||
+           func_kind == RawFunction::kSetterFunction ||
+           func_kind == RawFunction::kConstructor);
+  }
+#endif
+  return Api::NewHandle(isolate, func.raw());
+}
+
+
+DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  if (func.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function, Function);
+  }
+  return Api::NewHandle(isolate, func.UserVisibleName());
+}
+
+
+DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  if (func.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function, Function);
+  }
+  if (func.IsNonImplicitClosureFunction()) {
+    RawFunction* parent_function = func.parent_function();
+    return Api::NewHandle(isolate, parent_function);
+  }
+  const Class& owner = Class::Handle(func.Owner());
+  ASSERT(!owner.IsNull());
+  if (owner.IsTopLevel()) {
+    // Top-level functions are implemented as members of a hidden class. We hide
+    // that class here and instead answer the library.
+#if defined(DEBUG)
+    const Library& lib = Library::Handle(owner.library());
+    if (lib.IsNull()) {
+      ASSERT(owner.IsDynamicClass() || owner.IsVoidClass());
+    }
+#endif
+    return Api::NewHandle(isolate, owner.library());
+  } else {
+    return Api::NewHandle(isolate, owner.raw());
+  }
+}
+
+
+DART_EXPORT Dart_Handle Dart_FunctionIsAbstract(Dart_Handle function,
+                                                bool* is_abstract) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  if (is_abstract == NULL) {
+    RETURN_NULL_ERROR(is_abstract);
+  }
+  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  if (func.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function, Function);
+  }
+  *is_abstract = func.is_abstract();
+  return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
+                                              bool* is_static) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  if (is_static == NULL) {
+    RETURN_NULL_ERROR(is_static);
+  }
+  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  if (func.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function, Function);
+  }
+  *is_static = func.is_static();
+  return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_FunctionIsConstructor(Dart_Handle function,
+                                                   bool* is_constructor) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  if (is_constructor == NULL) {
+    RETURN_NULL_ERROR(is_constructor);
+  }
+  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  if (func.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function, Function);
+  }
+  *is_constructor = func.kind() == RawFunction::kConstructor;
+  return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_FunctionIsGetter(Dart_Handle function,
+                                              bool* is_getter) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  if (is_getter == NULL) {
+    RETURN_NULL_ERROR(is_getter);
+  }
+  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  if (func.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function, Function);
+  }
+  *is_getter = func.IsGetterFunction();
+  return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_FunctionIsSetter(Dart_Handle function,
+                                              bool* is_setter) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  if (is_setter == NULL) {
+    RETURN_NULL_ERROR(is_setter);
+  }
+  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  if (func.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function, Function);
+  }
+  *is_setter = (func.kind() == RawFunction::kSetterFunction);
+  return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_FunctionReturnType(Dart_Handle function) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  if (func.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function, Function);
+  }
+
+  if (func.kind() == RawFunction::kConstructor) {
+    // Special case the return type for constructors.  Inside the vm
+    // we mark them as returning dynamic, but for the purposes of
+    // reflection, they return the type of the class being
+    // constructed.
+    return Api::NewHandle(isolate, func.Owner());
+  } else {
+    const AbstractType& return_type =
+        AbstractType::Handle(isolate, func.result_type());
+    return TypeToHandle(isolate, "Dart_FunctionReturnType", return_type);
+  }
+}
+
+
+DART_EXPORT Dart_Handle Dart_FunctionParameterCounts(
+    Dart_Handle function,
+    int64_t* fixed_param_count,
+    int64_t* opt_param_count) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  if (fixed_param_count == NULL) {
+    RETURN_NULL_ERROR(fixed_param_count);
+  }
+  if (opt_param_count == NULL) {
+    RETURN_NULL_ERROR(opt_param_count);
+  }
+  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  if (func.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function, Function);
+  }
+
+  // We hide implicit parameters, such as a method's receiver. This is
+  // consistent with Invoke or New, which don't expect their callers to
+  // provide them in the argument lists they are handed.
+  *fixed_param_count = func.num_fixed_parameters() -
+                       func.NumImplicitParameters();
+  // TODO(regis): Separately report named and positional optional param counts.
+  *opt_param_count = func.NumOptionalParameters();
+
+  ASSERT(*fixed_param_count >= 0);
+  ASSERT(*opt_param_count >= 0);
+
+  return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_FunctionParameterType(Dart_Handle function,
+                                                   int parameter_index) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  if (func.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, function, Function);
+  }
+
+  const intptr_t num_implicit_params = func.NumImplicitParameters();
+  const intptr_t num_params = func.NumParameters() - num_implicit_params;
+  if (parameter_index < 0 || parameter_index >= num_params) {
+    return Api::NewError(
+        "%s: argument 'parameter_index' out of range. "
+        "Expected 0..%"Pd" but saw %d.",
+        CURRENT_FUNC, num_params, parameter_index);
+  }
+  const AbstractType& param_type =
+      AbstractType::Handle(isolate, func.ParameterTypeAt(
+          num_implicit_params + parameter_index));
+  return TypeToHandle(isolate, "Dart_FunctionParameterType", param_type);
+}
+
+
+DART_EXPORT Dart_Handle Dart_GetVariableNames(Dart_Handle target) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
+  if (obj.IsError()) {
+    return target;
+  }
+
+  const GrowableObjectArray& names =
+      GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
+  Field& field = Field::Handle(isolate);
+  String& name = String::Handle(isolate);
+
+  if (obj.IsClass()) {
+    const Class& cls = Class::Cast(obj);
+    const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
+    if (!error.IsNull()) {
+      return Api::NewHandle(isolate, error.raw());
+    }
+    const Array& field_array = Array::Handle(cls.fields());
+
+    // Some special types like 'dynamic' have a null fields list.
+    //
+    // TODO(turnidge): Fix 'dynamic' so that it does not have a null
+    // fields list.  This will have to wait until the empty array is
+    // allocated in the vm isolate.
+    if (!field_array.IsNull()) {
+      for (intptr_t i = 0; i < field_array.Length(); ++i) {
+        field ^= field_array.At(i);
+        name = field.UserVisibleName();
+        names.Add(name);
+      }
+    }
+  } else if (obj.IsLibrary()) {
+    const Library& lib = Library::Cast(obj);
+    DictionaryIterator it(lib);
+    Object& obj = Object::Handle(isolate);
+    while (it.HasNext()) {
+      obj = it.GetNext();
+      if (obj.IsField()) {
+        field ^= obj.raw();
+        name = field.UserVisibleName();
+        names.Add(name);
+      }
+    }
+  } else {
+    return Api::NewError(
+        "%s expects argument 'target' to be a class or library.",
+        CURRENT_FUNC);
+  }
+  return Api::NewHandle(isolate, Array::MakeArray(names));
+}
+
+
+DART_EXPORT Dart_Handle Dart_LookupVariable(Dart_Handle target,
+                                            Dart_Handle variable_name) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
+  if (obj.IsError()) {
+    return target;
+  }
+  const String& var_name = Api::UnwrapStringHandle(isolate, variable_name);
+  if (var_name.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, variable_name, String);
+  }
+  if (obj.IsClass()) {
+    const Class& cls = Class::Cast(obj);
+    return Api::NewHandle(isolate, cls.LookupField(var_name));
+  }
+  if (obj.IsLibrary()) {
+    const Library& lib = Library::Cast(obj);
+    return Api::NewHandle(isolate, lib.LookupFieldAllowPrivate(var_name));
+  }
+  return Api::NewError(
+      "%s expects argument 'target' to be a class or library.",
+      CURRENT_FUNC);
+}
+
+
+DART_EXPORT Dart_Handle Dart_VariableName(Dart_Handle variable) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Field& var = Api::UnwrapFieldHandle(isolate, variable);
+  if (var.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, variable, Field);
+  }
+  return Api::NewHandle(isolate, var.UserVisibleName());
+}
+
+
+DART_EXPORT Dart_Handle Dart_VariableIsStatic(Dart_Handle variable,
+                                              bool* is_static) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  if (is_static == NULL) {
+    RETURN_NULL_ERROR(is_static);
+  }
+  const Field& var = Api::UnwrapFieldHandle(isolate, variable);
+  if (var.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, variable, Field);
+  }
+  *is_static = var.is_static();
+  return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_VariableIsFinal(Dart_Handle variable,
+                                             bool* is_final) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  if (is_final == NULL) {
+    RETURN_NULL_ERROR(is_final);
+  }
+  const Field& var = Api::UnwrapFieldHandle(isolate, variable);
+  if (var.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, variable, Field);
+  }
+  *is_final = var.is_final();
+  return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_VariableType(Dart_Handle variable) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Field& var = Api::UnwrapFieldHandle(isolate, variable);
+  if (var.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, variable, Field);
+  }
+
+  const AbstractType& type = AbstractType::Handle(isolate, var.type());
+  return TypeToHandle(isolate, "Dart_VariableType", type);
+}
+
+
+DART_EXPORT Dart_Handle Dart_GetTypeVariableNames(Dart_Handle clazz) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
+  if (cls.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, clazz, Class);
+  }
+
+  const intptr_t num_type_params = cls.NumTypeParameters();
+  const TypeArguments& type_params =
+      TypeArguments::Handle(cls.type_parameters());
+
+  const GrowableObjectArray& names =
+      GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
+  TypeParameter& type_param = TypeParameter::Handle(isolate);
+  String& name = String::Handle(isolate);
+  for (intptr_t i = 0; i < num_type_params; i++) {
+    type_param ^= type_params.TypeAt(i);
+    name = type_param.name();
+    names.Add(name);
+  }
+  return Api::NewHandle(isolate, Array::MakeArray(names));
+}
+
+
+DART_EXPORT Dart_Handle Dart_LookupTypeVariable(
+    Dart_Handle clazz,
+    Dart_Handle type_variable_name) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Class& cls = Api::UnwrapClassHandle(isolate, clazz);
+  if (cls.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, clazz, Class);
+  }
+  const String& var_name = Api::UnwrapStringHandle(isolate, type_variable_name);
+  if (var_name.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, type_variable_name, String);
+  }
+
+  const intptr_t num_type_params = cls.NumTypeParameters();
+  const TypeArguments& type_params =
+      TypeArguments::Handle(cls.type_parameters());
+
+  TypeParameter& type_param = TypeParameter::Handle(isolate);
+  String& name = String::Handle(isolate);
+  for (intptr_t i = 0; i < num_type_params; i++) {
+    type_param ^= type_params.TypeAt(i);
+    name = type_param.name();
+    if (name.Equals(var_name)) {
+      return Api::NewHandle(isolate, type_param.raw());
+    }
+  }
+  const String& cls_name = String::Handle(cls.UserVisibleName());
+  return Api::NewError(
+      "%s: Could not find type variable named '%s' for class %s.\n",
+      CURRENT_FUNC, var_name.ToCString(), cls_name.ToCString());
+}
+
+
+DART_EXPORT Dart_Handle Dart_TypeVariableName(Dart_Handle type_variable) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const TypeParameter& type_var =
+      Api::UnwrapTypeParameterHandle(isolate, type_variable);
+  if (type_var.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, type_variable, TypeParameter);
+  }
+  return Api::NewHandle(isolate, type_var.name());
+}
+
+
+DART_EXPORT Dart_Handle Dart_TypeVariableOwner(Dart_Handle type_variable) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const TypeParameter& type_var =
+      Api::UnwrapTypeParameterHandle(isolate, type_variable);
+  if (type_var.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, type_variable, TypeParameter);
+  }
+  const Class& owner = Class::Handle(type_var.parameterized_class());
+  ASSERT(!owner.IsNull() && owner.IsClass());
+  return Api::NewHandle(isolate, owner.raw());
+}
+
+
+DART_EXPORT Dart_Handle Dart_TypeVariableUpperBound(Dart_Handle type_variable) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const TypeParameter& type_var =
+      Api::UnwrapTypeParameterHandle(isolate, type_variable);
+  if (type_var.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, type_variable, TypeParameter);
+  }
+  const AbstractType& bound = AbstractType::Handle(type_var.bound());
+  return TypeToHandle(isolate, "Dart_TypeVariableUpperBound", bound);
+}
+
+
+// --- Libraries Reflection ---
+
+DART_EXPORT Dart_Handle Dart_LibraryName(Dart_Handle library) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  if (lib.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, library, Library);
+  }
+  const String& name = String::Handle(isolate, lib.name());
+  ASSERT(!name.IsNull());
+  return Api::NewHandle(isolate, name.raw());
+}
+
+
+DART_EXPORT Dart_Handle Dart_LibraryGetClassNames(Dart_Handle library) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  if (lib.IsNull()) {
+    RETURN_TYPE_ERROR(isolate, library, Library);
+  }
+
+  const GrowableObjectArray& names =
+      GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
+  ClassDictionaryIterator it(lib);
+  Class& cls = Class::Handle();
+  String& name = String::Handle();
+  while (it.HasNext()) {
+    cls = it.GetNextClass();
+    if (cls.IsSignatureClass()) {
+      if (!cls.IsCanonicalSignatureClass()) {
+        // This is a typedef.  Add it to the list of class names.
+        name = cls.UserVisibleName();
+        names.Add(name);
+      } else {
+        // Skip canonical signature classes.  These are not named.
+      }
+    } else {
+      name = cls.UserVisibleName();
+      names.Add(name);
+    }
+  }
+  return Api::NewHandle(isolate, Array::MakeArray(names));
+}
+
+
+// --- Closures Reflection ---
+
+DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure) {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  const Instance& closure_obj = Api::UnwrapInstanceHandle(isolate, closure);
+  if (closure_obj.IsNull() || !closure_obj.IsClosure()) {
+    RETURN_TYPE_ERROR(isolate, closure, Instance);
+  }
+
+  ASSERT(ClassFinalizer::AllClassesFinalized());
+
+  RawFunction* rf = Closure::function(closure_obj);
+  return Api::NewHandle(isolate, rf);
+}
+
+
+// --- Metadata Reflection ----
+
+DART_EXPORT Dart_Handle Dart_GetMetadata(Dart_Handle object) {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  DARTSCOPE(isolate);
+  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+  Class& cls = Class::Handle(isolate);
+  if (obj.IsClass()) {
+    cls ^= obj.raw();
+  } else if (obj.IsFunction()) {
+    cls = Function::Cast(obj).origin();
+  } else if (obj.IsField()) {
+    cls = Field::Cast(obj).origin();
+  } else {
+    return Api::NewHandle(isolate, Object::empty_array().raw());
+  }
+  const Library& lib = Library::Handle(cls.library());
+  return Api::NewHandle(isolate, lib.GetMetadata(obj));
+}
+
+}  // namespace dart
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
new file mode 100644
index 0000000..a142540
--- /dev/null
+++ b/runtime/vm/native_api_impl.cc
@@ -0,0 +1,136 @@
+// 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 "include/dart_native_api.h"
+
+#include "platform/assert.h"
+#include "vm/dart_api_impl.h"
+#include "vm/dart_api_message.h"
+#include "vm/dart_api_state.h"
+#include "vm/message.h"
+#include "vm/native_message_handler.h"
+#include "vm/port.h"
+
+namespace dart {
+
+// --- Message sending/receiving from native code ---
+
+static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
+  void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
+  return reinterpret_cast<uint8_t*>(new_ptr);
+}
+
+
+DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message) {
+  uint8_t* buffer = NULL;
+  ApiMessageWriter writer(&buffer, allocator);
+  bool success = writer.WriteCMessage(message);
+
+  if (!success) return success;
+
+  // Post the message at the given port.
+  return PortMap::PostMessage(new Message(
+      port_id, Message::kIllegalPort, buffer, writer.BytesWritten(),
+      Message::kNormalPriority));
+}
+
+
+DART_EXPORT Dart_Port Dart_NewNativePort(const char* name,
+                                         Dart_NativeMessageHandler handler,
+                                         bool handle_concurrently) {
+  if (name == NULL) {
+    name = "<UnnamedNativePort>";
+  }
+  if (handler == NULL) {
+    OS::PrintErr("%s expects argument 'handler' to be non-null.\n",
+                 CURRENT_FUNC);
+    return ILLEGAL_PORT;
+  }
+  // Start the native port without a current isolate.
+  IsolateSaver saver(Isolate::Current());
+  Isolate::SetCurrent(NULL);
+
+  NativeMessageHandler* nmh = new NativeMessageHandler(name, handler);
+  Dart_Port port_id = PortMap::CreatePort(nmh);
+  nmh->Run(Dart::thread_pool(), NULL, NULL, 0);
+  return port_id;
+}
+
+
+DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id) {
+  // Close the native port without a current isolate.
+  IsolateSaver saver(Isolate::Current());
+  Isolate::SetCurrent(NULL);
+
+  // TODO(turnidge): Check that the port is native before trying to close.
+  return PortMap::ClosePort(native_port_id);
+}
+
+
+// --- Profiling support ---
+
+// TODO(7565): Dartium should use the new VM flag "generate_pprof_symbols" for
+// pprof profiling. Then these symbols should be removed.
+
+DART_EXPORT void Dart_InitPprofSupport() { }
+
+DART_EXPORT void Dart_GetPprofSymbolInfo(void** buffer, int* buffer_size) {
+  *buffer = NULL;
+  *buffer_size = 0;
+}
+
+
+// --- Heap Profiler ---
+
+DART_EXPORT Dart_Handle Dart_HeapProfile(Dart_FileWriteCallback callback,
+                                         void* stream) {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  if (callback == NULL) {
+    RETURN_NULL_ERROR(callback);
+  }
+  isolate->heap()->Profile(callback, stream);
+  return Api::Success();
+}
+
+
+// --- Verification tools ---
+
+static void CompileAll(Isolate* isolate, Dart_Handle* result) {
+  ASSERT(isolate != NULL);
+  const Error& error = Error::Handle(isolate, Library::CompileAll());
+  if (error.IsNull()) {
+    *result = Api::Success();
+  } else {
+    *result = Api::NewHandle(isolate, error.raw());
+  }
+}
+
+
+DART_EXPORT Dart_Handle Dart_CompileAll() {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  Dart_Handle result = Api::CheckIsolateState(isolate);
+  if (::Dart_IsError(result)) {
+    return result;
+  }
+  CHECK_CALLBACK_STATE(isolate);
+  CompileAll(isolate, &result);
+  return result;
+}
+
+
+DART_EXPORT Dart_Handle Dart_CheckFunctionFingerprints() {
+  Isolate* isolate = Isolate::Current();
+  DARTSCOPE(isolate);
+  Dart_Handle result = Api::CheckIsolateState(isolate);
+  if (::Dart_IsError(result)) {
+    return result;
+  }
+  CHECK_CALLBACK_STATE(isolate);
+  Library::CheckFunctionFingerprints();
+  return result;
+}
+
+}  // namespace dart
diff --git a/runtime/vm/native_message_handler.h b/runtime/vm/native_message_handler.h
index d3f29a8..777cb7f 100644
--- a/runtime/vm/native_message_handler.h
+++ b/runtime/vm/native_message_handler.h
@@ -6,6 +6,7 @@
 #define VM_NATIVE_MESSAGE_HANDLER_H_
 
 #include "include/dart_api.h"
+#include "include/dart_native_api.h"
 #include "vm/message_handler.h"
 
 namespace dart {
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 12cfe2d..c0e5a65 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -22,6 +22,7 @@
 #include "vm/datastream.h"
 #include "vm/debugger.h"
 #include "vm/deopt_instructions.h"
+#include "vm/disassembler.h"
 #include "vm/double_conversion.h"
 #include "vm/exceptions.h"
 #include "vm/flow_graph_builder.h"
@@ -7292,6 +7293,7 @@
     case PcDescriptors::kClosureCall:   return "closure-call ";
     case PcDescriptors::kReturn:        return "return       ";
     case PcDescriptors::kRuntimeCall:   return "runtime-call ";
+    case PcDescriptors::kOsrEntry:      return "osr-entry    ";
     case PcDescriptors::kOther:         return "other        ";
   }
   UNREACHABLE();
@@ -7999,6 +8001,13 @@
 }
 
 
+void Code::Disassemble() const {
+  const Instructions& instr = Instructions::Handle(instructions());
+  uword start = instr.EntryPoint();
+  Disassembler::Disassemble(start, start + instr.size(), comments());
+}
+
+
 const Code::Comments& Code::comments() const  {
   Comments* comments = new Code::Comments(Array::Handle(raw_ptr()->comments_));
   return *comments;
@@ -8151,6 +8160,18 @@
 }
 
 
+intptr_t Code::GetDeoptIdForOsr(uword pc) const {
+  const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
+  for (intptr_t i = 0; i < descriptors.Length(); ++i) {
+    if ((descriptors.PC(i) == pc) &&
+        (descriptors.DescriptorKind(i) == PcDescriptors::kOsrEntry)) {
+      return descriptors.DeoptId(i);
+    }
+  }
+  return Isolate::kNoDeoptId;
+}
+
+
 const char* Code::ToCString() const {
   const char* kFormat = "Code entry:%p";
   intptr_t len = OS::SNPrint(NULL, 0, kFormat, EntryPoint()) + 1;
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 90e55f8..1f847b3 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2542,6 +2542,7 @@
     kClosureCall,      // Closure call.
     kRuntimeCall,      // Runtime call.
     kReturn,           // Return from function.
+    kOsrEntry,         // OSR entry point in unoptimized code.
     kOther
   };
 
@@ -2877,6 +2878,8 @@
   // Aborts if there is no static call at 'pc'.
   void SetStaticCallTargetCodeAt(uword pc, const Code& code) const;
 
+  void Disassemble() const;
+
   class Comments : public ZoneAllocated {
    public:
     static Comments& New(intptr_t count);
@@ -2964,6 +2967,7 @@
   uword GetLazyDeoptPc() const;
 
   uword GetPcForDeoptId(intptr_t deopt_id, PcDescriptors::Kind kind) const;
+  intptr_t GetDeoptIdForOsr(uword pc) const;
 
   // Returns true if there is an object in the code between 'start_offset'
   // (inclusive) and 'end_offset' (exclusive).
diff --git a/runtime/vm/runtime_entry_mips.cc b/runtime/vm/runtime_entry_mips.cc
index 622f24f..f9d2b2f 100644
--- a/runtime/vm/runtime_entry_mips.cc
+++ b/runtime/vm/runtime_entry_mips.cc
@@ -28,11 +28,17 @@
   uword entry = GetEntryPoint();
 #if defined(USING_SIMULATOR)
   // Redirection to leaf runtime calls supports a maximum of 4 arguments passed
-  // in registers.
-  ASSERT(!is_leaf() || (argument_count() <= 4));
+  // in registers (maximum 2 double arguments for leaf float runtime calls).
+  ASSERT(argument_count() >= 0);
+  ASSERT(!is_leaf() ||
+         (!is_float() && (argument_count() <= 4)) ||
+         (argument_count() <= 2));
   Simulator::CallKind call_kind =
-      is_leaf() ? Simulator::kLeafRuntimeCall : Simulator::kRuntimeCall;
-  entry = Simulator::RedirectExternalReference(entry, call_kind);
+      is_leaf() ? (is_float() ? Simulator::kLeafFloatRuntimeCall
+                              : Simulator::kLeafRuntimeCall)
+                : Simulator::kRuntimeCall;
+  entry =
+      Simulator::RedirectExternalReference(entry, call_kind, argument_count());
 #endif
   if (is_leaf()) {
     ExternalLabel label(name(), entry);
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index 3687bc9..0a12de3 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -92,6 +92,7 @@
 
   bool GetValue(char* desc, uint32_t* value);
   bool GetFValue(char* desc, double* value);
+  bool GetDValue(char* desc, double* value);
 
   // Set or delete a breakpoint. Returns true if successful.
   bool SetBreakpoint(Instr* breakpc);
@@ -226,6 +227,26 @@
 }
 
 
+bool SimulatorDebugger::GetDValue(char* desc, double* value) {
+  FRegister freg = LookupFRegisterByName(desc);
+  if (freg != kNoFRegister) {
+    *value = sim_->get_fregister_double(freg);
+    return true;
+  }
+  if (desc[0] == '*') {
+    uint32_t addr;
+    if (GetValue(desc + 1, &addr)) {
+      if (Simulator::IsIllegalAddress(addr)) {
+        return false;
+      }
+      *value = *(reinterpret_cast<double*>(addr));
+      return true;
+    }
+  }
+  return false;
+}
+
+
 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) {
   // Check if a breakpoint can be set. If not return without any side-effects.
   if (sim_->break_pc_ != NULL) {
@@ -361,6 +382,20 @@
         } else {
           OS::Print("printfloat <dreg or *addr>\n");
         }
+      } else if ((strcmp(cmd, "pd") == 0) ||
+                 (strcmp(cmd, "printdouble") == 0)) {
+        if (args == 2) {
+          double dvalue;
+          if (GetDValue(arg1, &dvalue)) {
+            uint64_t long_value = bit_cast<uint64_t, double>(dvalue);
+            OS::Print("%s: %llu 0x%llx %.8g\n",
+                arg1, long_value, long_value, dvalue);
+          } else {
+            OS::Print("%s unrecognized\n", arg1);
+          }
+        } else {
+          OS::Print("printfloat <dreg or *addr>\n");
+        }
       } else if ((strcmp(cmd, "po") == 0) ||
                  (strcmp(cmd, "printobject") == 0)) {
         if (args == 2) {
@@ -589,13 +624,16 @@
 
   Simulator::CallKind call_kind() const { return call_kind_; }
 
+  int argument_count() const { return argument_count_; }
+
   static Redirection* Get(uword external_function,
-                          Simulator::CallKind call_kind) {
+                          Simulator::CallKind call_kind,
+                          int argument_count) {
     Redirection* current;
     for (current = list_; current != NULL; current = current->next_) {
       if (current->external_function_ == external_function) return current;
     }
-    return new Redirection(external_function, call_kind);
+    return new Redirection(external_function, call_kind, argument_count);
   }
 
   static Redirection* FromBreakInstruction(Instr* break_instruction) {
@@ -609,9 +647,12 @@
   static const int32_t kRedirectInstruction =
     Instr::kBreakPointInstruction | (Instr::kRedirectCode << kBreakCodeShift);
 
-  Redirection(uword external_function, Simulator::CallKind call_kind)
+  Redirection(uword external_function,
+              Simulator::CallKind call_kind,
+              int argument_count)
       : external_function_(external_function),
         call_kind_(call_kind),
+        argument_count_(argument_count),
         break_instruction_(kRedirectInstruction),
         next_(list_) {
     list_ = this;
@@ -619,6 +660,7 @@
 
   uword external_function_;
   Simulator::CallKind call_kind_;
+  int argument_count_;
   uint32_t break_instruction_;
   Redirection* next_;
   static Redirection* list_;
@@ -628,8 +670,11 @@
 Redirection* Redirection::list_ = NULL;
 
 
-uword Simulator::RedirectExternalReference(uword function, CallKind call_kind) {
-  Redirection* redirection = Redirection::Get(function, call_kind);
+uword Simulator::RedirectExternalReference(uword function,
+                                           CallKind call_kind,
+                                           int argument_count) {
+  Redirection* redirection =
+      Redirection::Get(function, call_kind, argument_count);
   return redirection->address_of_break_instruction();
 }
 
@@ -890,6 +935,9 @@
 typedef int32_t (*SimulatorLeafRuntimeCall)(
     int32_t r0, int32_t r1, int32_t r2, int32_t r3);
 
+// Calls to leaf float Dart runtime functions are based on this interface.
+typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1);
+
 // Calls to native Dart functions are based on this interface.
 typedef void (*SimulatorNativeCall)(NativeArguments* arguments);
 
@@ -925,7 +973,8 @@
         OS::Print("Call to host function at 0x%"Pd"\n", external);
       }
 
-      if (redirection->call_kind() != kLeafRuntimeCall) {
+        if ((redirection->call_kind() == kRuntimeCall) ||
+            (redirection->call_kind() == kNativeCall)) {
         // The top_exit_frame_info of the current isolate points to the top of
         // the simulator stack.
         ASSERT((StackTop() - Isolate::Current()->top_exit_frame_info()) <
@@ -953,6 +1002,17 @@
             reinterpret_cast<SimulatorLeafRuntimeCall>(external);
         a0 = target(a0, a1, a2, a3);
         set_register(V0, a0);  // Set returned result from function.
+      } else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
+        ASSERT((0 <= redirection->argument_count()) &&
+               (redirection->argument_count() <= 2));
+        // double values are passed and returned in floating point registers.
+        SimulatorLeafFloatRuntimeCall target =
+            reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external);
+        double d0 = 0.0;
+        double d6 = get_fregister_double(F12);
+        double d7 = get_fregister_double(F14);
+        d0 = target(d6, d7);
+        set_fregister_double(F0, d0);
       } else {
         ASSERT(redirection->call_kind() == kNativeCall);
         NativeArguments* arguments;
@@ -986,7 +1046,7 @@
 
       // Zap floating point registers.
       int32_t zap_dvalue = icount_;
-      for (int i = F0; i <= F31; i++) {
+      for (int i = F4; i <= F18; i++) {
         set_fregister(static_cast<FRegister>(i), zap_dvalue);
       }
 
@@ -1109,6 +1169,20 @@
       set_register(instr->RdField(), get_lo_register());
       break;
     }
+    case MOVCI: {
+      ASSERT(instr->SaField() == 0);
+      ASSERT(instr->Bit(17) == 0);
+      int32_t rs_val = get_register(instr->RsField());
+      uint32_t cc, fcsr_cc, test, status;
+      cc = instr->Bits(18, 3);
+      fcsr_cc = get_fcsr_condition_bit(cc);
+      test = instr->Bit(16);
+      status = test_fcsr_bit(fcsr_cc);
+      if (test == status) {
+        set_register(instr->RdField(), rs_val);
+      }
+      break;
+    }
     case MOVN: {
       ASSERT(instr->SaField() == 0);
       // Format(instr, "movn 'rd, 'rs, 'rt");
@@ -1520,6 +1594,12 @@
             set_fregister_double(instr->FdField(), fs_dbl);
             break;
           }
+          case FMT_S: {
+            float fs_flt = get_fregister_float(instr->FsField());
+            double fs_dbl = static_cast<double>(fs_flt);
+            set_fregister_double(instr->FdField(), fs_dbl);
+            break;
+          }
           case FMT_L: {
             int64_t fs_int = get_fregister_long(instr->FsField());
             double fs_dbl = static_cast<double>(fs_int);
diff --git a/runtime/vm/simulator_mips.h b/runtime/vm/simulator_mips.h
index eca271d..9b685b2 100644
--- a/runtime/vm/simulator_mips.h
+++ b/runtime/vm/simulator_mips.h
@@ -106,9 +106,12 @@
   enum CallKind {
     kRuntimeCall,
     kLeafRuntimeCall,
+    kLeafFloatRuntimeCall,
     kNativeCall
   };
-  static uword RedirectExternalReference(uword function, CallKind call_kind);
+  static uword RedirectExternalReference(uword function,
+                                         CallKind call_kind,
+                                         int argument_count);
 
   void Longjmp(uword pc,
                uword sp,
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index 2b206fa..e32f242 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -75,7 +75,6 @@
   // Returns token_pos of the pc(), or -1 if none exists.
   intptr_t GetTokenPos() const;
 
-
  protected:
   StackFrame() : fp_(0), sp_(0), pc_(0) { }
 
@@ -296,4 +295,3 @@
 }  // namespace dart
 
 #endif  // VM_STACK_FRAME_H_
-
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 0cf7c9b..7f884622f 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -1435,22 +1435,10 @@
     __ popl(func_reg);     // Restore.
     __ LeaveFrame();
   }
-  Label is_hot;
-  if (FlowGraphCompiler::CanOptimize()) {
-    ASSERT(FLAG_optimization_counter_threshold > 1);
-    __ cmpl(FieldAddress(func_reg, Function::usage_counter_offset()),
-        Immediate(FLAG_optimization_counter_threshold));
-    __ j(GREATER_EQUAL, &is_hot, Assembler::kNearJump);
-    // As long as VM has no OSR do not optimize in the middle of the function
-    // but only at exit so that we have collected all type feedback before
-    // optimizing.
-  }
   __ incl(FieldAddress(func_reg, Function::usage_counter_offset()));
-  __ Bind(&is_hot);
 }
 
 
-
 // Loads function into 'temp_reg'.
 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler,
                                              Register temp_reg) {
@@ -1458,20 +1446,7 @@
   Register func_reg = temp_reg;
   ASSERT(ic_reg != func_reg);
   __ movl(func_reg, FieldAddress(ic_reg, ICData::function_offset()));
-  Label is_hot;
-  if (FlowGraphCompiler::CanOptimize()) {
-    ASSERT(FLAG_optimization_counter_threshold > 1);
-    // The usage_counter is always less than FLAG_optimization_counter_threshold
-    // except when the function gets optimized.
-    __ cmpl(FieldAddress(func_reg, Function::usage_counter_offset()),
-        Immediate(FLAG_optimization_counter_threshold));
-    __ j(EQUAL, &is_hot, Assembler::kNearJump);
-    // As long as VM has no OSR do not optimize in the middle of the function
-    // but only at exit so that we have collected all type feedback before
-    // optimizing.
-  }
   __ incl(FieldAddress(func_reg, Function::usage_counter_offset()));
-  __ Bind(&is_hot);
 }
 
 
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index e5cf95c..4bfd8a1 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -95,11 +95,11 @@
   // Load Context pointer from Isolate structure into A2.
   __ lw(A2, Address(CTX, Isolate::top_context_offset()));
 
-  // Reload NULLREG.
-  __ LoadImmediate(NULLREG, reinterpret_cast<intptr_t>(Object::null()));
+  // Load null.
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
 
   // Reset Context pointer in Isolate structure.
-  __ sw(NULLREG, Address(CTX, Isolate::top_context_offset()));
+  __ sw(TMP, Address(CTX, Isolate::top_context_offset()));
 
   // Cache Context pointer into CTX while executing Dart code.
   __ mov(CTX, A2);
@@ -202,11 +202,11 @@
   // Load Context pointer from Isolate structure into A2.
   __ lw(A2, Address(CTX, Isolate::top_context_offset()));
 
-  // Reload NULLREG.
-  __ LoadImmediate(NULLREG, reinterpret_cast<intptr_t>(Object::null()));
+  // Load null.
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
 
   // Reset Context pointer in Isolate structure.
-  __ sw(NULLREG, Address(CTX, Isolate::top_context_offset()));
+  __ sw(TMP, Address(CTX, Isolate::top_context_offset()));
 
   // Cache Context pointer into CTX while executing Dart code.
   __ mov(CTX, A2);
@@ -228,7 +228,8 @@
 
   __ addiu(SP, SP, Immediate(-2 * kWordSize));
   __ sw(S4, Address(SP, 1 * kWordSize));
-  __ sw(NULLREG, Address(SP, 0 * kWordSize));
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(TMP, Address(SP, 0 * kWordSize));
 
   __ CallRuntime(kPatchStaticCallRuntimeEntry);
   __ TraceSimMsg("CallStaticFunctionStub return");
@@ -257,7 +258,8 @@
   // Setup space on stack for return value and preserve arguments descriptor.
   __ addiu(SP, SP, Immediate(-2 * kWordSize));
   __ sw(S4, Address(SP, 1 * kWordSize));
-  __ sw(NULLREG, Address(SP, 0 * kWordSize));
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(TMP, Address(SP, 0 * kWordSize));
   __ CallRuntime(kFixCallersTargetRuntimeEntry);
   // Get Code object result and restore arguments descriptor array.
   __ lw(T0, Address(SP, 0 * kWordSize));
@@ -279,7 +281,7 @@
 static void PushArgumentsArray(Assembler* assembler) {
   __ TraceSimMsg("PushArgumentsArray");
   // Allocate array to store arguments of caller.
-  __ mov(A0, NULLREG);
+  __ LoadImmediate(A0, reinterpret_cast<intptr_t>(Object::null()));
   // A0: Null element type for raw Array.
   // A1: Smi-tagged argument count, may be zero.
   __ BranchLink(&StubCode::AllocateArrayLabel());
@@ -329,7 +331,8 @@
   // Push TMP1 data object.
   // Push arguments descriptor array.
   __ addiu(SP, SP, Immediate(-4 * kWordSize));
-  __ sw(NULLREG, Address(SP, 3 * kWordSize));
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(TMP, Address(SP, 3 * kWordSize));
   __ sw(T1, Address(SP, 2 * kWordSize));
   __ sw(S5, Address(SP, 1 * kWordSize));
   __ sw(S4, Address(SP, 0 * kWordSize));
@@ -498,8 +501,44 @@
 
 
 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
-  __ Unimplemented("MegamorphicMiss stub");
-  return;
+  __ EnterStubFrame();
+
+  // Load the receiver.
+  __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
+  __ sll(T2, T2, 1);  // T2 is a Smi.
+  __ addu(TMP, FP, T2);
+  __ lw(T6, Address(TMP, kParamEndSlotFromFp * kWordSize));
+
+  // Preserve IC data and arguments descriptor.
+  __ addiu(SP, SP, Immediate(-6 * kWordSize));
+  __ sw(S5, Address(SP, 5 * kWordSize));
+  __ sw(S4, Address(SP, 4 * kWordSize));
+
+  // Push space for the return value.
+  // Push the receiver.
+  // Push IC data object.
+  // Push arguments descriptor array.
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(TMP, Address(SP, 3 * kWordSize));
+  __ sw(T6, Address(SP, 2 * kWordSize));
+  __ sw(S5, Address(SP, 1 * kWordSize));
+  __ sw(S4, Address(SP, 0 * kWordSize));
+
+  __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry);
+
+  __ lw(T0, Address(SP, 3 * kWordSize));  // Get result.
+  __ lw(S4, Address(SP, 4 * kWordSize));  // Restore argument descriptor.
+  __ lw(S5, Address(SP, 5 * kWordSize));  // Restore IC data.
+  __ addiu(SP, SP, Immediate(6 * kWordSize));
+
+  __ LeaveStubFrame();
+
+  Label nonnull;
+  __ BranchNotEqual(T0, reinterpret_cast<int32_t>(Object::null()), &nonnull);
+  __ Branch(&StubCode::InstanceFunctionLookupLabel());
+  __ Bind(&nonnull);
+  __ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag);
+  __ jr(T0);
 }
 
 
@@ -604,12 +643,13 @@
     // T3: iterator which initially points to the start of the variable
     // data area to be initialized.
 
+    __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
     Label loop, loop_exit;
     __ BranchUnsignedGreaterEqual(T3, T2, &loop_exit);
     __ Bind(&loop);
     __ addiu(T3, T3, Immediate(kWordSize));
     __ bne(T3, T2, &loop);
-    __ delay_slot()->sw(NULLREG, Address(T3, -kWordSize));
+    __ delay_slot()->sw(T7, Address(T3, -kWordSize));
     __ Bind(&loop_exit);
 
     // Done allocating and initializing the array.
@@ -627,17 +667,17 @@
   // Setup space on stack for return value.
   // Push array length as Smi and element type.
   __ addiu(SP, SP, Immediate(-3 * kWordSize));
-  __ sw(NULLREG, Address(SP, 2 * kWordSize));
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(TMP, Address(SP, 2 * kWordSize));
   __ sw(A1, Address(SP, 1 * kWordSize));
-  __ sw(T3, Address(SP, 0 * kWordSize));
+  __ sw(A0, Address(SP, 0 * kWordSize));
   __ CallRuntime(kAllocateArrayRuntimeEntry);
   __ TraceSimMsg("AllocateArrayStub return");
   // Pop arguments; result is popped in IP.
-  __ lw(TMP1, Address(SP, 2 * kWordSize));
+  __ lw(V0, Address(SP, 2 * kWordSize));
   __ lw(A1, Address(SP, 1 * kWordSize));
-  __ lw(T3, Address(SP, 0 * kWordSize));
+  __ lw(A0, Address(SP, 0 * kWordSize));
   __ addiu(SP, SP, Immediate(3 * kWordSize));
-  __ mov(V0, TMP1);
 
   __ LeaveStubFrameAndReturn();
 }
@@ -666,8 +706,10 @@
   // Verify that T1 is a closure by checking its class.
   Label not_closure;
 
+  __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
+
   // See if it is not a closure, but null object.
-  __ beq(T1, NULLREG, &not_closure);
+  __ beq(T1, T7, &not_closure);
 
   __ andi(CMPRES, T1, Immediate(kSmiTagMask));
   __ beq(CMPRES, ZR, &not_closure);  // Not a closure, but a smi.
@@ -678,7 +720,7 @@
   __ lw(T0, FieldAddress(T0, Class::signature_function_offset()));
 
   // See if actual class is not a closure class.
-  __ beq(T0, NULLREG, &not_closure);
+  __ beq(T0, T7, &not_closure);
 
   // T0 is just the signature function. Load the actual closure function.
   __ lw(T2, FieldAddress(T1, Closure::function_offset()));
@@ -689,7 +731,7 @@
   Label function_compiled;
   // Load closure function code in T0.
   __ lw(T0, FieldAddress(T2, Function::code_offset()));
-  __ bne(T0, NULLREG, &function_compiled);
+  __ bne(T0, T7, &function_compiled);
 
   // Create a stub frame as we are pushing some objects on the stack before
   // calling into the runtime.
@@ -731,9 +773,9 @@
   __ EnterStubFrame();
 
   // Setup space on stack for result from error reporting.
-  __ addiu(SP, SP, Immediate(2 * kWordSize));
+  __ addiu(SP, SP, Immediate(-2 * kWordSize));
   // Arguments descriptor and raw null.
-  __ sw(NULLREG, Address(SP, 1 * kWordSize));
+  __ sw(T7, Address(SP, 1 * kWordSize));
   __ sw(S4, Address(SP, 0 * kWordSize));
 
   // Load smi-tagged arguments array length, including the non-closure.
@@ -825,9 +867,6 @@
   // Compute address of 'arguments array' data area into A2.
   __ lw(A2, Address(A2, VMHandles::kOffsetOfRawPtrInHandle));
 
-  // Load the null Object into NULLREG for easy comparisons.
-  __ LoadImmediate(NULLREG, reinterpret_cast<intptr_t>(Object::null()));
-
   // Set up arguments for the Dart call.
   Label push_arguments;
   Label done_push_arguments;
@@ -960,20 +999,22 @@
     // T2: isolate, not an object.
     __ sw(T2, FieldAddress(V0, Context::isolate_offset()));
 
+    __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
+
     // Initialize the context variables.
     // V0: new object.
     // T1: number of context variables.
     Label loop, loop_exit;
     __ blez(T1, &loop_exit);
     // Setup the parent field.
-    __ delay_slot()->sw(NULLREG, FieldAddress(V0, Context::parent_offset()));
+    __ delay_slot()->sw(T7, FieldAddress(V0, Context::parent_offset()));
     __ AddImmediate(T3, V0, Context::variable_offset(0) - kHeapObjectTag);
     __ sll(T1, T1, 2);
     __ Bind(&loop);
     __ addiu(T1, T1, Immediate(-kWordSize));
     __ addu(TMP1, T3, T1);
     __ bgtz(T1, &loop);
-    __ delay_slot()->sw(NULLREG, Address(TMP1));
+    __ delay_slot()->sw(T7, Address(TMP1));
     __ Bind(&loop_exit);
 
     // Done allocating and initializing the context.
@@ -988,7 +1029,8 @@
   // Setup space on stack for return value.
   __ SmiTag(T1);
   __ addiu(SP, SP, Immediate(-2 * kWordSize));
-  __ sw(NULLREG, Address(SP, 1 * kWordSize));
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(TMP, Address(SP, 1 * kWordSize));  // Store null.
   __ sw(T1, Address(SP, 0 * kWordSize));
   __ CallRuntime(kAllocateContextRuntimeEntry);  // Allocate context.
   __ lw(V0, Address(SP, 1 * kWordSize));  // Get the new context.
@@ -1172,6 +1214,8 @@
     __ LoadImmediate(T0, tags);
     __ sw(T0, Address(T2, Instance::tags_offset()));
 
+    __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
+
     // Initialize the remaining words of the object.
     // T2: new object start.
     // T3: next object start.
@@ -1183,7 +1227,7 @@
       for (intptr_t current_offset = sizeof(RawObject);
            current_offset < instance_size;
            current_offset += kWordSize) {
-        __ sw(NULLREG, Address(T2, current_offset));
+        __ sw(T7, Address(T2, current_offset));
       }
     } else {
       __ addiu(T4, T2, Immediate(sizeof(RawObject)));
@@ -1197,7 +1241,7 @@
       __ Bind(&loop);
       __ addiu(T4, T4, Immediate(kWordSize));
       __ bne(T4, T3, &loop);
-      __ delay_slot()->sw(NULLREG, Address(T4, -kWordSize));
+      __ delay_slot()->sw(T7, Address(T4, -kWordSize));
       __ Bind(&loop_exit);
     }
     if (is_cls_parameterized) {
@@ -1223,7 +1267,8 @@
 
   __ addiu(SP, SP, Immediate(-4 * kWordSize));
   // Space on stack for return value.
-  __ sw(NULLREG, Address(SP, 3 * kWordSize));
+  __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(T7, Address(SP, 3 * kWordSize));
   __ sw(TMP1, Address(SP, 2 * kWordSize));  // Class of object to be allocated.
 
   if (is_cls_parameterized) {
@@ -1233,7 +1278,7 @@
   } else {
     // Push null type arguments and kNoInstantiator.
     __ LoadImmediate(T1, Smi::RawValue(StubCode::kNoInstantiator));
-    __ sw(NULLREG, Address(SP, 1 * kWordSize));
+    __ sw(T7, Address(SP, 1 * kWordSize));
     __ sw(T1, Address(SP, 0 * kWordSize));
   }
   __ CallRuntime(kAllocateObjectRuntimeEntry);  // Allocate object.
@@ -1264,8 +1309,8 @@
 
   __ TraceSimMsg("AllocationStubForClosure");
   __ EnterStubFrame(true);  // Uses pool pointer to refer to function.
-  const intptr_t kTypeArgumentsFPOffset = 4 * kWordSize;
-  const intptr_t kReceiverFPOffset = 5 * kWordSize;
+  const intptr_t kTypeArgumentsFPOffset = 3 * kWordSize;
+  const intptr_t kReceiverFPOffset = 4 * kWordSize;
   const intptr_t closure_size = Closure::InstanceSize();
   const intptr_t context_size = Context::InstanceSize(1);  // Captured receiver.
   if (FLAG_inline_alloc &&
@@ -1337,7 +1382,8 @@
       __ sw(T0, Address(T4, Context::isolate_offset()));
 
       // Set the parent to null.
-      __ sw(NULLREG, Address(T4, Context::parent_offset()));
+      __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+      __ sw(TMP, Address(T4, Context::parent_offset()));
 
       // Initialize the context variable to the receiver.
       __ lw(T0, Address(FP, kReceiverFPOffset));
@@ -1370,24 +1416,24 @@
     num_slots = is_implicit_instance_closure ? 4 : 3;
   }
   __ addiu(SP, SP, Immediate(-num_slots * kWordSize));
-  __ LoadObject(TMP1, func);
   // Setup space on stack for return value.
-  __ sw(NULLREG, Address(SP, (num_slots - 1) * kWordSize));
+  __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(T7, Address(SP, (num_slots - 1) * kWordSize));
+  __ LoadObject(TMP1, func);
   __ sw(TMP1, Address(SP, (num_slots - 2) * kWordSize));
   if (is_implicit_static_closure) {
     __ CallRuntime(kAllocateImplicitStaticClosureRuntimeEntry);
     __ TraceSimMsg("AllocationStubForClosure return");
   } else {
+    __ mov(T2, T7);
     if (is_implicit_instance_closure) {
       __ lw(T1, Address(FP, kReceiverFPOffset));
       __ sw(T1, Address(SP, (num_slots - 3) * kWordSize));  // Receiver.
-      __ sw(NULLREG, Address(SP, (num_slots - 4) * kWordSize));  // Push null.
     }
     if (has_type_arguments) {
-      __ lw(V0, Address(FP, kTypeArgumentsFPOffset));
-      // Push type arguments of closure.
-      __ sw(V0, Address(SP, (num_slots - 3) * kWordSize));
+      __ lw(T2, Address(FP, kTypeArgumentsFPOffset));
     }
+    __ sw(T2, Address(SP, 0 * kWordSize));
 
     if (is_implicit_instance_closure) {
       __ CallRuntime(kAllocateImplicitInstanceClosureRuntimeEntry);
@@ -1407,8 +1453,37 @@
 }
 
 
+// The target function was not found, so invoke method
+// "dynamic noSuchMethod(Invocation invocation)".
+//  S5: inline cache data object.
+//  S4: arguments descriptor array.
 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
-  __ Unimplemented("CallNoSuchMethodFunction stub");
+  __ EnterStubFrame();
+
+  // Load the receiver.
+  __ lw(A1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
+  __ sll(TMP, A1, 1);  // A1 is a Smi.
+  __ addu(TMP, FP, TMP);
+  __ lw(T6, Address(TMP, kParamEndSlotFromFp * kWordSize));
+
+  // Push space for the return value.
+  // Push the receiver.
+  // Push IC data object.
+  // Push arguments descriptor array.
+  __ addiu(SP, SP, Immediate(-4 * kWordSize));
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(TMP, Address(SP, 3 * kWordSize));
+  __ sw(T6, Address(SP, 2 * kWordSize));
+  __ sw(S5, Address(SP, 1 * kWordSize));
+  __ sw(S4, Address(SP, 0 * kWordSize));
+
+  // A1: Smi-tagged arguments array length.
+  PushArgumentsArray(assembler);
+
+  __ CallRuntime(kInvokeNoSuchMethodFunctionRuntimeEntry);
+
+  __ lw(V0, Address(SP, 4 * kWordSize));  // Get result into V0.
+  __ LeaveStubFrameAndReturn();
 }
 
 
@@ -1585,7 +1660,8 @@
   __ addiu(SP, SP, Immediate(-num_slots * kWordSize));
   __ sw(S5, Address(SP, (num_slots - 1) * kWordSize));
   __ sw(S4, Address(SP, (num_slots - 2) * kWordSize));
-  __ sw(NULLREG, Address(SP, (num_slots - 3) * kWordSize));
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(TMP, Address(SP, (num_slots - 3) * kWordSize));
   // Push call arguments.
   for (intptr_t i = 0; i < num_args; i++) {
     __ lw(TMP1, Address(T1, -i * kWordSize));
@@ -1615,7 +1691,8 @@
   __ addiu(SP, SP, Immediate(num_slots * kWordSize));
   __ LeaveStubFrame();
   Label call_target_function;
-  __ bne(T3, NULLREG, &call_target_function);
+  __ BranchNotEqual(T3, reinterpret_cast<int32_t>(Object::null()),
+                    &call_target_function);
 
   // NoSuchMethod or closure.
   // Mark IC call that it may be a closure call that does not collect
@@ -1737,7 +1814,8 @@
   // Preserve arguments descriptor and make room for result.
   __ addiu(SP, SP, Immediate(-2 * kWordSize));
   __ sw(S4, Address(SP, 1 * kWordSize));
-  __ sw(NULLREG, Address(SP, 0 * kWordSize));
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(TMP, Address(SP, 0 * kWordSize));
   __ CallRuntime(kBreakpointStaticHandlerRuntimeEntry);
   // Pop code object result and restore arguments descriptor.
   __ lw(T0, Address(SP, 0 * kWordSize));
@@ -1837,14 +1915,17 @@
   __ lw(T2, FieldAddress(A2, SubtypeTestCache::cache_offset()));
   __ AddImmediate(T2, Array::data_offset() - kHeapObjectTag);
 
+  __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
+
   Label loop, found, not_found, next_iteration;
   // T0: instance class id.
   // T1: instance type arguments.
   // T2: Entry start.
+  // T7: null.
   __ SmiTag(T0);
   __ Bind(&loop);
   __ lw(T3, Address(T2, kWordSize * SubtypeTestCache::kInstanceClassId));
-  __ beq(T3, NULLREG, &not_found);
+  __ beq(T3, T7, &not_found);
 
   if (n == 1) {
     __ beq(T3, T0, &found);
@@ -1868,7 +1949,7 @@
   // Fall through to not found.
   __ Bind(&not_found);
   __ Ret();
-  __ delay_slot()->mov(V0, NULLREG);
+  __ delay_slot()->mov(V0, T7);
 
   __ Bind(&found);
   __ Ret();
@@ -1947,6 +2028,7 @@
 // TODO(srdjan): Move to VM stubs once Boolean objects become VM objects.
 void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) {
   __ TraceSimMsg("EqualityWithNullArgStub");
+  __ Comment("EqualityWithNullArgStub");
   __ EnterStubFrame();
   static const intptr_t kNumArgsTested = 2;
 #if defined(DEBUG)
@@ -2048,7 +2130,8 @@
   __ addiu(SP, SP, Immediate(-3 * kWordSize));
   __ sw(S4, Address(SP, 2 * kWordSize));
   // Setup space on stack for return value.
-  __ sw(NULLREG, Address(SP, 1 * kWordSize));
+  __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
+  __ sw(TMP, Address(SP, 1 * kWordSize));
   __ sw(T0, Address(SP, 0 * kWordSize));
   __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry);
   __ TraceSimMsg("OptimizeFunctionStub return");
@@ -2079,21 +2162,23 @@
 // cannot contain a value that fits in Mint or Smi.
 void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) {
   __ TraceSimMsg("IdenticalWithNumberCheckStub");
-  const Register ret = CMPRES;
+  __ Comment("IdenticalWithNumberCheckStub");
   const Register temp1 = T2;
   const Register temp2 = T3;
   const Register left = T1;
   const Register right = T0;
   // Preserve left, right.
-  __ addiu(SP, SP, Immediate(-2 * kWordSize));
-  __ sw(T1, Address(SP, 1 * kWordSize));
-  __ sw(T0, Address(SP, 0 * kWordSize));
+  __ addiu(SP, SP, Immediate(-4 * kWordSize));
+  __ sw(temp1, Address(SP, 3 * kWordSize));
+  __ sw(temp2, Address(SP, 2 * kWordSize));
+  __ sw(left, Address(SP, 1 * kWordSize));
+  __ sw(right, Address(SP, 0 * kWordSize));
   // TOS + 3: left argument.
   // TOS + 2: right argument.
   // TOS + 1: saved left
   // TOS + 0: saved right
-  __ lw(left, Address(SP, 3 * kWordSize));
-  __ lw(right, Address(SP, 2 * kWordSize));
+  __ lw(left, Address(SP, 5 * kWordSize));
+  __ lw(right, Address(SP, 4 * kWordSize));
   Label reference_compare, done, check_mint, check_bigint;
   // If any of the arguments is Smi do reference compare.
   __ andi(temp1, left, Immediate(kSmiTagMask));
@@ -2106,48 +2191,50 @@
   __ LoadClassId(temp2, left);
   __ bne(temp1, temp2, &check_mint);
   __ LoadClassId(temp2, right);
-  __ subu(ret, temp1, temp2);
-  __ bne(ret, ZR, &done);
+  __ subu(CMPRES, temp1, temp2);
+  __ bne(CMPRES, ZR, &done);
 
   // Double values bitwise compare.
   __ lw(temp1, FieldAddress(left, Double::value_offset() + 0 * kWordSize));
-  __ lw(temp1, FieldAddress(right, Double::value_offset() + 0 * kWordSize));
-  __ subu(ret, temp1, temp2);
-  __ bne(ret, ZR, &done);
+  __ lw(temp2, FieldAddress(right, Double::value_offset() + 0 * kWordSize));
+  __ subu(CMPRES, temp1, temp2);
+  __ bne(CMPRES, ZR, &done);
   __ lw(temp1, FieldAddress(left, Double::value_offset() + 1 * kWordSize));
   __ lw(temp2, FieldAddress(right, Double::value_offset() + 1 * kWordSize));
   __ b(&done);
-  __ delay_slot()->subu(ret, temp1, temp2);
+  __ delay_slot()->subu(CMPRES, temp1, temp2);
 
   __ Bind(&check_mint);
   __ LoadImmediate(temp1, kMintCid);
   __ LoadClassId(temp2, left);
   __ bne(temp1, temp2, &check_bigint);
   __ LoadClassId(temp2, right);
-  __ subu(ret, temp1, temp2);
-  __ bne(ret, ZR, &done);
+  __ subu(CMPRES, temp1, temp2);
+  __ bne(CMPRES, ZR, &done);
 
   __ lw(temp1, FieldAddress(left, Mint::value_offset() + 0 * kWordSize));
   __ lw(temp2, FieldAddress(right, Mint::value_offset() + 0 * kWordSize));
-  __ subu(ret, temp1, temp2);
-  __ bne(ret, ZR, &done);
+  __ subu(CMPRES, temp1, temp2);
+  __ bne(CMPRES, ZR, &done);
   __ lw(temp1, FieldAddress(left, Mint::value_offset() + 1 * kWordSize));
   __ lw(temp2, FieldAddress(right, Mint::value_offset() + 1 * kWordSize));
   __ b(&done);
-  __ delay_slot()->subu(ret, temp1, temp2);
+  __ delay_slot()->subu(CMPRES, temp1, temp2);
 
   __ Bind(&check_bigint);
   __ LoadImmediate(temp1, kBigintCid);
   __ LoadClassId(temp2, left);
   __ bne(temp1, temp2, &reference_compare);
   __ LoadClassId(temp2, right);
-  __ subu(ret, temp1, temp2);
-  __ bne(ret, ZR, &done);
+  __ subu(CMPRES, temp1, temp2);
+  __ bne(CMPRES, ZR, &done);
 
-  __ EnterStubFrame(0);
+  __ EnterStubFrame();
   __ ReserveAlignedFrameSpace(2 * kWordSize);
-  __ sw(T1, Address(SP, 1 * kWordSize));
-  __ sw(T0, Address(SP, 0 * kWordSize));
+  __ sw(left, Address(SP, 1 * kWordSize));
+  __ sw(right, Address(SP, 0 * kWordSize));
+  __ mov(A0, left);
+  __ mov(A1, right);
   __ CallRuntime(kBigintCompareRuntimeEntry);
   __ TraceSimMsg("IdenticalWithNumberCheckStub return");
   // Result in V0, 0 means equal.
@@ -2156,14 +2243,16 @@
   __ delay_slot()->mov(CMPRES, V0);
 
   __ Bind(&reference_compare);
-  __ subu(ret, left, right);
+  __ subu(CMPRES, left, right);
   __ Bind(&done);
   // A branch or test after this comparison will check CMPRES == TMP1.
   __ mov(TMP1, ZR);
-  __ lw(T0, Address(SP, 0 * kWordSize));
-  __ lw(T1, Address(SP, 1 * kWordSize));
+  __ lw(right, Address(SP, 0 * kWordSize));
+  __ lw(left, Address(SP, 1 * kWordSize));
+  __ lw(temp2, Address(SP, 2 * kWordSize));
+  __ lw(temp1, Address(SP, 3 * kWordSize));
   __ Ret();
-  __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize));
+  __ delay_slot()->addiu(SP, SP, Immediate(4 * kWordSize));
 }
 
 }  // namespace dart
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 0b49f59..8d78a52 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -1418,18 +1418,7 @@
     __ popq(func_reg);     // Restore.
     __ LeaveFrame();
   }
-  Label is_hot;
-  if (FlowGraphCompiler::CanOptimize()) {
-    ASSERT(FLAG_optimization_counter_threshold > 1);
-    __ cmpq(FieldAddress(func_reg, Function::usage_counter_offset()),
-        Immediate(FLAG_optimization_counter_threshold));
-    __ j(GREATER_EQUAL, &is_hot, Assembler::kNearJump);
-    // As long as VM has no OSR do not optimize in the middle of the function
-    // but only at exit so that we have collected all type feedback before
-    // optimizing.
-  }
   __ incq(FieldAddress(func_reg, Function::usage_counter_offset()));
-  __ Bind(&is_hot);
 }
 
 
@@ -1440,22 +1429,10 @@
   Register func_reg = temp_reg;
   ASSERT(ic_reg != func_reg);
   __ movq(func_reg, FieldAddress(ic_reg, ICData::function_offset()));
-  Label is_hot;
-  if (FlowGraphCompiler::CanOptimize()) {
-    ASSERT(FLAG_optimization_counter_threshold > 1);
-    // The usage_counter is always less than FLAG_optimization_counter_threshold
-    // except when the function gets optimized.
-    __ cmpq(FieldAddress(func_reg, Function::usage_counter_offset()),
-        Immediate(FLAG_optimization_counter_threshold));
-    __ j(EQUAL, &is_hot, Assembler::kNearJump);
-    // As long as VM has no OSR do not optimize in the middle of the function
-    // but only at exit so that we have collected all type feedback before
-    // optimizing.
-  }
   __ incq(FieldAddress(func_reg, Function::usage_counter_offset()));
-  __ Bind(&is_hot);
 }
 
+
 // Generate inline cache check for 'num_args'.
 //  RBX: Inline cache data object.
 //  R10: Arguments descriptor array.
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index c850caa..75844c2 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -409,6 +409,7 @@
   EnqueueTask enqueuer;
   CompilerTask fileReadingTask;
   DeferredLoadTask deferredLoadTask;
+  ContainerTracer containerTracer;
   String buildId;
 
   static const SourceString MAIN = const SourceString('main');
@@ -453,6 +454,9 @@
 
   bool hasCrashed = false;
 
+  /// Set by the backend if real reflection is detected in use of dart:mirrors.
+  bool disableTypeInferenceForMirrors = false;
+
   Compiler({this.tracer: const Tracer(),
             this.enableTypeAssertions: false,
             this.enableUserAssertions: false,
@@ -510,6 +514,7 @@
       closureToClassMapper = new closureMapping.ClosureTask(this, closureNamer),
       checker = new TypeCheckerTask(this),
       typesTask = new ti.TypesTask(this),
+      containerTracer = new ContainerTracer(this),
       constantHandler = new ConstantHandler(this, backend.constantSystem),
       deferredLoadTask = new DeferredLoadTask(this),
       enqueuer = new EnqueueTask(this)];
@@ -530,7 +535,9 @@
 
   bool get compileAll => false;
 
-  bool get disableTypeInference => disableTypeInferenceFlag || mirrorsEnabled;
+  bool get disableTypeInference {
+    return disableTypeInferenceFlag || disableTypeInferenceForMirrors;
+  }
 
   int getNextFreeClassId() => nextFreeClassId++;
 
diff --git a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
index c006c95..517573f 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
@@ -35,6 +35,7 @@
 import 'resolution/resolution.dart';
 import 'js/js.dart' as js;
 import 'deferred_load.dart' show DeferredLoadTask;
+import 'types/container_tracer.dart' show ContainerTracer;
 
 export 'resolution/resolution.dart' show TreeElements, TreeElementMapping;
 export 'scanner/scannerlib.dart' show SourceString,
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index f3dae36..1352cea 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -639,8 +639,8 @@
       if (uri == 'dart:isolate') {
         enableIsolateSupport(library);
       } else if (uri == 'dart:async') {
-        ClassElement cls = element.getEnclosingClass();
-        if (cls != null && cls.name == const SourceString('Timer')) {
+        if (element.name == const SourceString('_createTimer') ||
+            element.name == const SourceString('_createPeriodicTimer')) {
           // The [:Timer:] class uses the event queue of the isolate
           // library, so we make sure that event queue is generated.
           enableIsolateSupport(library);
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 87e7294..5afa2a0 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -1133,6 +1133,7 @@
   void registerStaticUse(Element element, Enqueuer enqueuer) {
     if (element == disableTreeShakingMarker) {
       enqueuer.enqueueEverything();
+      compiler.disableTypeInferenceForMirrors = true;
     } else if (element == preserveNamesMarker) {
     }
   }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 61e465b..75d6443 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -3341,11 +3341,15 @@
       if (Elements.isFixedListConstructorCall(
               originalElement, send, compiler)) {
         isListConstructor = true;
-        return backend.fixedArrayType;
+        HType inferred =
+            new HType.inferredForNode(currentElement, node, compiler);
+        return inferred.isUnknown() ? backend.fixedArrayType : inferred;
       } else if (Elements.isGrowableListConstructorCall(
                     originalElement, send, compiler)) {
         isListConstructor = true;
-        return backend.extendableArrayType;
+        HType inferred =
+            new HType.inferredForNode(currentElement, node, compiler);
+        return inferred.isUnknown() ? backend.extendableArrayType : inferred;
       } else if (element.isGenerativeConstructor()) {
         ClassElement cls = element.getEnclosingClass();
         return new HType.nonNullExact(cls.thisType, compiler);
@@ -4103,7 +4107,10 @@
       visit(link.head);
       inputs.add(pop());
     }
-    push(buildLiteralList(inputs));
+    HInstruction instruction = buildLiteralList(inputs);
+    HType type = new HType.inferredForNode(currentElement, node, compiler);
+    if (!type.isUnknown()) instruction.instructionType = type;
+    push(instruction);
   }
 
   visitConditional(Conditional node) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
index fdfd0db..9c5f1a9 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
@@ -154,18 +154,18 @@
 
   HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
                                    Compiler compiler) {
-    if (instruction.inputs[1].isIndexable(compiler)) {
-      if (!instruction.inputs[2].isInteger() && compiler.enableTypeAssertions) {
-        // We want the right checked mode error.
-        return null;
-      }
-      HInstruction index = new HIndex(
-          instruction.inputs[1], instruction.inputs[2], instruction.selector);
-      index.instructionType =
-          new HType.inferredTypeForSelector(instruction.selector, compiler);
-      return index;
+    if (!instruction.inputs[1].isIndexable(compiler)) return null;
+    if (!instruction.inputs[2].isInteger() && compiler.enableTypeAssertions) {
+      // We want the right checked mode error.
+      return null;
     }
-    return null;
+    HInstruction index = new HIndex(
+        instruction.inputs[1], instruction.inputs[2], instruction.selector);
+    HType receiverType = instruction.getDartReceiver(compiler).instructionType;
+    Selector refined = receiverType.refine(instruction.selector, compiler);
+    HType type = new HType.inferredTypeForSelector(refined, compiler);
+    index.instructionType = type;
+    return index;
   }
 
   bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
index f408df4..44c01e8 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
@@ -179,12 +179,18 @@
   String temporaryId(HInstruction instruction) {
     String prefix;
     HType type = instruction.instructionType;
-    if (type.isMutableArray(compiler)) {
+    if (type.isExtendableArray(compiler)) {
+      prefix = 'e';
+    } else if (type.isFixedArray(compiler)) {
+      prefix = 'f';
+    } else if (type.isMutableArray(compiler)) {
       prefix = 'm';
     } else if (type.isReadableArray(compiler)) {
       prefix = 'a';
-    } else if (type.isExtendableArray(compiler)) {
-      prefix = 'e';
+    } else if (type.isString(compiler)) {
+      prefix = 's';
+    } else if (type.isIndexable(compiler)) {
+      prefix = 'r';
     } else if (type == HType.BOOLEAN) {
       prefix = 'b';
     } else if (type == HType.INTEGER) {
@@ -193,14 +199,10 @@
       prefix = 'd';
     } else if (type == HType.NUMBER) {
       prefix = 'n';
-    } else if (type.isString(compiler)) {
-      prefix = 's';
     } else if (type == HType.UNKNOWN) {
       prefix = 'v';
     } else if (type == HType.CONFLICTING) {
       prefix = 'c';
-    } else if (type.isIndexable(compiler)) {
-      prefix = 'r';
     } else if (type == HType.NULL) {
       prefix = 'u';
     } else {
diff --git a/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart b/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
new file mode 100644
index 0000000..04c9923
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
@@ -0,0 +1,666 @@
+// 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 container_tracer;
+
+import '../dart2jslib.dart' hide Selector, TypedSelector;
+import '../elements/elements.dart';
+import '../tree/tree.dart';
+import '../universe/universe.dart';
+import '../util/util.dart' show Link;
+import 'simple_types_inferrer.dart' show SimpleTypesInferrer, InferrerVisitor;
+import 'types.dart';
+
+/**
+ * A set of selector names that [List] implements, that we know do not
+ * change the element type of the list, or let the list escape to code
+ * that might change the element type.
+ */
+Set<String> okSelectorsSet = new Set<String>.from(
+  const <String>[
+    // From Object.
+    '==',
+    'hashCode',
+    'toString',
+    'noSuchMethod',
+    'runtimeType',
+
+    // From Iterable.
+    'iterator',
+    'map',
+    'where',
+    'expand',
+    'contains',
+    'forEach',
+    'reduce',
+    'fold',
+    'every',
+    'join',
+    'any',
+    'toList',
+    'toSet',
+    'length',
+    'isEmpty',
+    'isNotEmpty',
+    'take',
+    'takeWhile',
+    'skip',
+    'skipWhile',
+    'first',
+    'last',
+    'single',
+    'firstWhere',
+    'lastWhere',
+    'singleWhere',
+    'elementAt',
+
+    // From List.
+    '[]',
+    'length',
+    'reversed',
+    'sort',
+    'indexOf',
+    'lastIndexOf',
+    'clear',
+    'remove',
+    'removeAt',
+    'removeLast',
+    'removeWhere',
+    'retainWhere',
+    'sublist',
+    'getRange',
+    'removeRange',
+    'asMap',
+
+    // From JSArray.
+    'checkMutable',
+    'checkGrowable',
+  ]);
+
+bool _VERBOSE = false;
+
+/**
+ * Global analysis phase that traces container instantiations in order to
+ * find their element type.
+ */
+class ContainerTracer extends CompilerTask {
+  ContainerTracer(Compiler compiler) : super(compiler);
+
+  String get name => 'List tracer';
+
+  bool analyze() {
+    measure(() {
+      SimpleTypesInferrer inferrer = compiler.typesTask.typesInferrer;
+      var internal = inferrer.internal;
+      // Walk over all created [ContainerTypeMask].
+      internal.concreteTypes.values.forEach((ContainerTypeMask mask) {
+        mask.elementType = new TracerForConcreteContainer(
+            mask, this, compiler, inferrer).run();
+      });
+    });
+  }
+}
+
+/**
+ * A tracer for a specific container.
+ */
+class TracerForConcreteContainer {
+  final Compiler compiler;
+  final ContainerTracer tracer;
+  final SimpleTypesInferrer inferrer;
+
+  final Node analyzedNode;
+  final Element startElement;
+
+  final List<Element> workList = <Element>[];
+
+  /**
+   * A set of elements where this list might escape.
+   */
+  final Set<Element> escapingElements = new Set<Element>();
+
+  /**
+   * A set of selectors that both use and update the list, for example
+   * [: list[0]++; :] or [: list[0] |= 42; :]. 
+   */
+  final Set<Selector> constraints = new Set<Selector>();
+
+  /**
+   * A cache of setters that were already seen. Caching these
+   * selectors avoid the filtering done in [addSettersToAnalysis].
+   */
+  final Set<Selector> seenSetterSelectors = new Set<Selector>();
+
+  static const int MAX_ANALYSIS_COUNT = 11;
+
+  TypeMask potentialType;
+  bool continueAnalyzing = true;
+
+  TracerForConcreteContainer(ContainerTypeMask mask,
+                             this.tracer,
+                             this.compiler,
+                             this.inferrer)
+      : analyzedNode = mask.allocationNode,
+        startElement = mask.allocationElement;
+
+  TypeMask run() {
+    int analysisCount = 0;
+    workList.add(startElement);
+    while (!workList.isEmpty) {
+      if (workList.length + analysisCount > MAX_ANALYSIS_COUNT) {
+        bailout('Too many users');
+        break;
+      }
+      Element currentElement = workList.removeLast().implementation;
+      new ContainerTracerVisitor(currentElement, this).run();
+      if (!continueAnalyzing) break;
+      analysisCount++;
+    }
+
+    if (!continueAnalyzing) return inferrer.dynamicType;
+
+    // [potentialType] can be null if we did not find any instruction
+    // that adds elements to the list.
+    if (potentialType == null) return new TypeMask.empty();
+
+    potentialType = potentialType.nullable();
+    // Walk over the found constraints and update the type according
+    // to the selectors of these constraints.
+    for (Selector constraint in constraints) {
+      assert(constraint.isOperator());
+      constraint = new TypedSelector(potentialType, constraint);
+      potentialType = potentialType.union(
+          inferrer.getTypeOfSelector(constraint), compiler);
+    }
+    if (_VERBOSE) {
+      print('$potentialType for $analyzedNode');
+    }
+    return potentialType;
+  }
+
+
+  void unionPotentialTypeWith(TypeMask newType) {
+    assert(newType != null);
+    potentialType = potentialType == null
+        ? newType
+        : newType.union(potentialType, compiler);
+    if (potentialType == inferrer.dynamicType) {
+      bailout('Moved to dynamic');
+    }
+  }
+
+  void addEscapingElement(element) {
+    element = element.implementation;
+    if (escapingElements.contains(element)) return;
+    escapingElements.add(element);
+    if (element.isField() || element.isGetter() || element.isFunction()) {
+      for (Element e in inferrer.getCallersOf(element)) {
+        addElementToAnalysis(e);
+      }
+    } else if (element.isParameter()) {
+      addElementToAnalysis(element.enclosingElement);
+    } else if (element.isFieldParameter()) {
+      addEscapingElement(element.fieldElement);
+    }
+  }
+
+  void addSettersToAnalysis(Selector selector) {
+    assert(selector.isSetter());
+    if (seenSetterSelectors.contains(selector)) return;
+    seenSetterSelectors.add(selector);
+    for (var e in compiler.world.allFunctions.filter(selector)) {
+      e = e.implementation;
+      if (e.isField()) {
+        addEscapingElement(e);
+      } else {
+        FunctionSignature signature = e.computeSignature(compiler);
+        signature.forEachRequiredParameter((Element e) {
+          addEscapingElement(e);
+        });
+      }
+    }
+  }
+
+  void addElementToAnalysis(Element element) {
+    workList.add(element);
+  }
+
+  TypeMask bailout(String reason) {
+    if (_VERBOSE) {
+      print('Bailout on $analyzedNode $startElement because of $reason');
+    }
+    continueAnalyzing = false;
+    return inferrer.dynamicType;
+  }
+
+  bool couldBeTheList(resolved) {
+    if (resolved is Selector) {
+      return escapingElements.any((e) {
+        return e.isInstanceMember()
+            && (e.isField() || e.isFunction())
+            && resolved.applies(e, compiler);
+      });
+    } else if (resolved is Node) {
+      return analyzedNode == resolved;
+    } else {
+      assert(resolved is Element);
+      return escapingElements.contains(resolved); 
+    }
+  }
+
+  void recordConstraint(Selector selector) {
+    constraints.add(selector);
+  }
+}
+
+class ContainerTracerVisitor extends InferrerVisitor {
+  final Element analyzedElement;
+  final TracerForConcreteContainer tracer;
+  ContainerTracerVisitor(element, tracer)
+      : super(element, tracer.inferrer, tracer.compiler),
+        this.analyzedElement = element,
+        this.tracer = tracer;
+
+  bool escaping = false;
+  bool visitingClosure = false;
+  bool visitingInitializers = false;
+
+  void run() {
+    compiler.withCurrentElement(analyzedElement, () {
+      visit(analyzedElement.parseNode(compiler));
+    });
+  }
+
+  /**
+   * Executes [f] and returns whether it triggered the list to escape.
+   */
+  bool visitAndCatchEscaping(Function f) {
+    bool oldEscaping = escaping;
+    escaping = false;
+    f();
+    bool foundEscaping = escaping;
+    escaping = oldEscaping;
+    return foundEscaping;
+  }
+
+  /**
+   * Visits the [arguments] of [callee], and records the parameters
+   * that could hold the container as escaping.
+   *
+   * Returns whether the container escaped.
+   */
+  bool visitArguments(Link<Node> arguments, /* Element or Selector */ callee) {
+    List<int> indices = [];
+    int index = 0;
+    for (Node node in arguments) {
+      if (visitAndCatchEscaping(() { visit(node); })) {
+        indices.add(index);
+      }
+      index++;
+    }
+    if (!indices.isEmpty) {
+      Iterable<Element> callees;
+      if (callee is Element) {
+        callees = [callee];
+      } else {
+        assert(callee is Selector);
+        callees = compiler.world.allFunctions.filter(callee);
+      }
+      for (var e in callees) {
+        e = e.implementation;
+        if (e.isField()) {
+          tracer.bailout('Passed to a closure');
+          break;
+        }
+        FunctionSignature signature = e.computeSignature(compiler);
+        index = 0;
+        int parameterIndex = 0;
+        signature.forEachRequiredParameter((Element parameter) {
+          if (index < indices.length && indices[index] == parameterIndex) {
+            tracer.addEscapingElement(parameter);
+            index++;
+          }
+          parameterIndex++;
+        });
+        if (index != indices.length) {
+          tracer.bailout('Used in a named parameter or closure');
+        }
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  TypeMask visitFunctionExpression(FunctionExpression node) {
+    bool oldVisitingClosure = visitingClosure;
+    FunctionElement function = elements[node];
+    FunctionSignature signature = function.computeSignature(compiler);
+    signature.forEachParameter((element) {
+      locals.update(element, inferrer.getTypeOfElement(element));
+    });
+    visitingClosure = function != analyzedElement;
+    bool oldVisitingInitializers = visitingInitializers;
+    visitingInitializers = true;
+    visit(node.initializers);
+    visitingInitializers = oldVisitingInitializers;
+    visit(node.body);
+    visitingClosure = oldVisitingClosure;
+
+    return inferrer.functionType;
+  }
+
+  TypeMask visitLiteralList(LiteralList node) {
+    if (node.isConst()) return inferrer.constListType;
+    if (tracer.couldBeTheList(node)) {
+      escaping = true;
+      for (Node element in node.elements.nodes) {
+        tracer.unionPotentialTypeWith(visit(element));
+      }
+    } else {
+      node.visitChildren(this);
+    }
+    return inferrer.growableListType;
+  }
+
+  // TODO(ngeoffray): Try to move the following two methods in
+  // [InferrerVisitor].
+  TypeMask visitCascadeReceiver(CascadeReceiver node) {
+    return visit(node.expression);
+  }
+
+  TypeMask visitCascade(Cascade node) {
+    Send send = node.expression;
+    TypeMask result;
+    bool isReceiver = visitAndCatchEscaping(() {
+      result = visit(send.receiver);
+    });
+    if (send.asSendSet() != null) {
+      handleSendSet(send, isReceiver);
+    } else {
+      handleDynamicSend(send, isReceiver);
+    }
+    if (isReceiver) {
+      escaping = true;
+    }
+    return result;
+  }
+
+  TypeMask visitSendSet(SendSet node) {
+    bool isReceiver = visitAndCatchEscaping(() {
+      visit(node.receiver);
+    });
+    return handleSendSet(node, isReceiver);
+  }
+
+  TypeMask handleSendSet(SendSet node, bool isReceiver) {
+    TypeMask rhsType;
+    TypeMask indexType;
+
+    Selector getterSelector =
+        elements.getGetterSelectorInComplexSendSet(node);
+    Selector operatorSelector =
+        elements.getOperatorSelectorInComplexSendSet(node);
+    Selector setterSelector = elements.getSelector(node);
+
+    String op = node.assignmentOperator.source.stringValue;
+    bool isIncrementOrDecrement = op == '++' || op == '--';
+    bool isIndexEscaping = false;
+    bool isValueEscaping = false;
+    if (isIncrementOrDecrement) {
+      rhsType = inferrer.intType;
+      if (node.isIndex) {
+        isIndexEscaping = visitAndCatchEscaping(() {
+          indexType = visit(node.arguments.head);
+        });
+      }
+    } else if (node.isIndex) {
+      isIndexEscaping = visitAndCatchEscaping(() {
+        indexType = visit(node.arguments.head);
+      });
+      isValueEscaping = visitAndCatchEscaping(() {
+        rhsType = visit(node.arguments.tail.head);
+      });
+    } else {
+      isValueEscaping = visitAndCatchEscaping(() {
+        rhsType = visit(node.arguments.head);
+      });
+    }
+
+    Element element = elements[node];
+
+    if (node.isIndex) {
+      if (isReceiver) {
+        if (op == '=') {
+          tracer.unionPotentialTypeWith(rhsType);
+        } else {
+          tracer.recordConstraint(operatorSelector);
+        }
+      } else if (isIndexEscaping || isValueEscaping) {
+        // If the index or value is escaping, iterate over all
+        // potential targets, and mark their parameter as escaping.
+        for (var e in compiler.world.allFunctions.filter(setterSelector)) {
+          e = e.implementation;
+          FunctionSignature signature = e.computeSignature(compiler);
+          int index = 0;
+          signature.forEachRequiredParameter((Element parameter) {
+            if (index == 0 && isIndexEscaping) {
+              tracer.addEscapingElement(parameter);
+            }
+            if (index == 1 && isValueEscaping) {
+              tracer.addEscapingElement(parameter);
+            }
+            index++;
+          });
+        }
+      }
+    } else if (isReceiver) {
+      if (setterSelector.name == const SourceString('length')) {
+        // Changing the length.
+        tracer.unionPotentialTypeWith(inferrer.nullType);
+      }
+    } else if (isValueEscaping) {
+      if (element != null
+          && element.isField()
+          && setterSelector == null
+          && !visitingInitializers) {
+        // Initializer at declaration of a field.
+        assert(analyzedElement.isField());
+        tracer.addEscapingElement(analyzedElement);
+      } else if (element != null
+                  && (!element.isInstanceMember() || visitingInitializers)) {
+        // A local, a static element, or a field in an initializer.
+        tracer.addEscapingElement(element);
+      } else {
+        tracer.addSettersToAnalysis(setterSelector);
+      }
+    }
+
+    if (Elements.isLocal(element)) {
+      locals.update(element, rhsType);
+    }
+
+    if (node.isPostfix) {
+      // We don't check if [getterSelector] could be the container because
+      // a list++ will always throw.
+      return inferrer.getTypeOfSelector(getterSelector);
+    } else if (op != '=') {
+      // We don't check if [getterSelector] could be the container because
+      // a list += 42 will always throw.
+      return inferrer.getTypeOfSelector(operatorSelector);
+    } else {
+      if (isValueEscaping) {
+        escaping = true;
+      }
+      return rhsType;
+    }
+  }
+
+  TypeMask visitSuperSend(Send node) {
+    Element element = elements[node];
+    if (!node.isPropertyAccess) {
+      visitArguments(node.arguments, element);
+    }
+
+    if (tracer.couldBeTheList(element)) {
+      escaping = true;
+    }
+
+    if (element.isField()) {
+      return inferrer.getTypeOfElement(element);
+    } else if (element.isFunction()) {
+      return inferrer.getReturnTypeOfElement(element);
+    } else {
+      return inferrer.dynamicType;
+    }
+  }
+
+  TypeMask visitStaticSend(Send node) {
+    Element element = elements[node];
+    bool isEscaping = visitArguments(node.arguments, element);
+
+    if (element.isForeign(compiler)) {
+      if (isEscaping) return tracer.bailout('Used in a JS');
+    }
+
+    if (tracer.couldBeTheList(element)) {
+      escaping = true;
+    }
+
+    if (Elements.isGrowableListConstructorCall(element, node, compiler)) {
+      if (tracer.couldBeTheList(node)) {
+        escaping = true;
+      }
+      return inferrer.growableListType;
+    } else if (Elements.isFixedListConstructorCall(element, node, compiler)) {
+      if (tracer.couldBeTheList(node)) {
+        escaping = true;
+      }
+      return inferrer.fixedListType;
+    } else if (element.isFunction() || element.isConstructor()) {
+      return inferrer.getReturnTypeOfElement(element);
+    } else {
+      // Closure call or unresolved.
+      return inferrer.dynamicType;
+    }
+  }
+
+  TypeMask visitGetterSend(Send node) {
+    Element element = elements[node];
+    Selector selector = elements.getSelector(node);
+    if (Elements.isStaticOrTopLevelField(element)) {
+      if (tracer.couldBeTheList(element)) {
+        escaping = true;
+      }
+      return inferrer.getTypeOfElement(element);
+    } else if (Elements.isInstanceSend(node, elements)) {
+      return visitDynamicSend(node);
+    } else if (Elements.isStaticOrTopLevelFunction(element)) {
+      return inferrer.functionType;
+    } else if (Elements.isErroneousElement(element)) {
+      return inferrer.dynamicType;
+    } else if (Elements.isLocal(element)) {
+      if (tracer.couldBeTheList(element)) {
+        escaping = true;
+      }
+      return locals.use(element);
+    } else {
+      node.visitChildren(this);
+      return inferrer.dynamicType;
+    }
+  }
+
+  TypeMask visitClosureSend(Send node) {
+    assert(node.receiver == null);
+    visit(node.selector);
+    bool isEscaping =
+        visitArguments(node.arguments, elements.getSelector(node));
+
+    if (isEscaping) return tracer.bailout('Passed to a closure');
+    return inferrer.dynamicType;
+  }
+
+  TypeMask visitDynamicSend(Send node) {
+    bool isReceiver = visitAndCatchEscaping(() {
+      visit(node.receiver);
+    });
+    return handleDynamicSend(node, isReceiver);
+  }
+
+  TypeMask handleDynamicSend(Send node, bool isReceiver) {
+    Selector selector = elements.getSelector(node);
+    String selectorName = selector.name.slowToString();
+    if (isReceiver && !okSelectorsSet.contains(selectorName)) {
+      if (selector.isCall()
+          && (selectorName == 'add' || selectorName == 'insert')) {
+        TypeMask argumentType;
+        if (node.arguments.isEmpty
+            || (selectorName == 'insert' && node.arguments.tail.isEmpty)) {
+          return tracer.bailout('Invalid "add" or "insert" call on a list');
+        }
+        bool isEscaping = visitAndCatchEscaping(() {
+          argumentType = visit(node.arguments.head);
+          if (selectorName == 'insert') {
+            argumentType = visit(node.arguments.tail.head);
+          }
+        });
+        if (isEscaping) {
+          return tracer.bailout('List containing itself');
+        }
+        tracer.unionPotentialTypeWith(argumentType);
+      } else {
+        return tracer.bailout('Send with the node as receiver $node');
+      }
+    } else if (!node.isPropertyAccess) {
+      visitArguments(node.arguments, selector);
+    }
+    if (tracer.couldBeTheList(selector)) {
+      escaping = true;
+    }
+    return inferrer.getTypeOfSelector(selector);
+  }
+
+  TypeMask visitReturn(Return node) {
+    if (node.expression == null) {
+      return inferrer.nullType;
+    }
+    
+    TypeMask type;
+    bool isEscaping = visitAndCatchEscaping(() {
+      type = visit(node.expression);
+    });
+
+    if (isEscaping) {
+      if (visitingClosure) {
+        tracer.bailout('Return from closure');
+      } else {
+        tracer.addEscapingElement(analyzedElement);
+      }
+    }
+    return type;
+  }
+  
+  TypeMask visitForIn(ForIn node) {
+    visit(node.expression);
+    Selector iteratorSelector = elements.getIteratorSelector(node);
+    Selector currentSelector = elements.getCurrentSelector(node);
+
+    TypeMask iteratorType = inferrer.getTypeOfSelector(iteratorSelector);
+    TypeMask currentType = inferrer.getTypeOfSelector(currentSelector);
+
+    // We nullify the type in case there is no element in the
+    // iterable.
+    currentType = currentType.nullable();
+
+    Node identifier = node.declaredIdentifier;
+    Element element = elements[identifier];
+    if (Elements.isLocal(element)) {
+      locals.update(element, currentType);
+    }
+
+    return handleLoop(node, () {
+      visit(node.body);
+    });
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart
new file mode 100644
index 0000000..3684755
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart
@@ -0,0 +1,138 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of types;
+
+/// A holder for an element type. We define a special class for it so
+/// that nullable ContainerTypeMask and non-nullable ContainerTypeMask
+/// share the same [ElementTypeHolder].
+class ElementTypeHolder {
+  // This field will be set after global analysis.
+  TypeMask elementType;
+}
+
+/// A [ContainerTypeMask] is a [TypeMask] for a specific allocation
+/// site of a container (currently only List) that will get specialized
+/// once the [ListTracer] phase finds an element type for it.
+class ContainerTypeMask implements TypeMask {
+
+  // The flat version of a [ContainerTypeMask] is the container type
+  // (for example List).
+  final FlatTypeMask asFlat;
+
+  // The [Node] where this type mask was created.
+  final Node allocationNode;
+
+  // The [Element] where this type mask was created.
+  final Element allocationElement;
+
+  // A holder for the element type. Shared between all
+  // [ContainerTypeMask] for the same node.
+  final ElementTypeHolder holder;
+
+  TypeMask get elementType => holder.elementType;
+  void set elementType(TypeMask mask) {
+    holder.elementType = mask;
+  }
+
+  ContainerTypeMask(this.asFlat,
+                    this.allocationNode,
+                    this.allocationElement,
+                    [holder])
+      : this.holder = (holder == null) ? new ElementTypeHolder() : holder;
+
+  TypeMask nullable() {
+    return isNullable
+        ? this
+        : new ContainerTypeMask(asFlat.nullable(),
+                                allocationNode,
+                                allocationElement,
+                                holder);
+  }
+
+  TypeMask nonNullable() {
+    return isNullable
+        ? new ContainerTypeMask(asFlat.nonNullable(),
+                                allocationNode,
+                                allocationElement,
+                                holder)
+        : this;
+  }
+
+  TypeMask simplify(Compiler compiler) => this;
+
+  bool get isEmpty => false;
+  bool get isNullable => asFlat.isNullable;
+  bool get isExact => true;
+  bool get isUnion => false;
+  bool get isContainer => true;
+
+  bool containsOnlyInt(Compiler compiler) => false;
+  bool containsOnlyDouble(Compiler compiler) => false;
+  bool containsOnlyNum(Compiler compiler) => false;
+  bool containsOnlyNull(Compiler compiler) => false;
+  bool containsOnlyBool(Compiler compiler) => false;
+  bool containsOnlyString(Compiler compiler) => false;
+  bool containsOnly(ClassElement element) {
+    return asFlat.containsOnly(element);
+  }
+
+  bool satisfies(ClassElement cls, Compiler compiler) {
+    return asFlat.satisfies(cls, compiler);
+  }
+
+  bool contains(DartType type, Compiler compiler) {
+    return asFlat.contains(type, compiler);
+  }
+
+  bool containsAll(Compiler compiler) => false;
+
+  ClassElement singleClass(Compiler compiler) {
+    return asFlat.singleClass(compiler);
+  }
+
+  Iterable<ClassElement> containedClasses(Compiler compiler) {
+    return asFlat.containedClasses(compiler);
+  }
+
+  TypeMask union(other, Compiler compiler) {
+    if (other.isContainer
+        && other.allocationNode == this.allocationNode) {
+      return other.isNullable ? other : this;
+    } else if (other.isEmpty) {
+      return other.isNullable ? this.nullable() : this;
+    }
+    return asFlat.union(other, compiler);
+  }
+
+  TypeMask intersection(TypeMask other, Compiler compiler) {
+    TypeMask flatIntersection = asFlat.intersection(other, compiler);
+    if (flatIntersection.isEmpty) return flatIntersection;
+    return flatIntersection.isNullable
+        ? nullable()
+        : nonNullable();
+  }
+
+  bool willHit(Selector selector, Compiler compiler) {
+    return asFlat.willHit(selector, compiler);
+  }
+
+  bool canHit(Element element, Selector selector, Compiler compiler) {
+    return asFlat.canHit(element, selector, compiler);
+  }
+
+  Element locateSingleElement(Selector selector, Compiler compiler) {
+    return asFlat.locateSingleElement(selector, compiler);
+  }
+
+  bool operator==(other) {
+    if (other is! ContainerTypeMask) return false;
+    return allocationNode == other.allocationNode
+        && isNullable == other.isNullable;
+  }
+
+  String toString() {
+    return 'Container mask: $elementType';
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
index a318d0e..c96f28d 100644
--- a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
@@ -63,6 +63,7 @@
   bool get isExact => (flags >> 1) == EXACT;
   bool get isNullable => (flags & 1) != 0;
   bool get isUnion => false;
+  bool get isContainer => false;
 
   // TODO(kasperl): Get rid of these. They should not be a visible
   // part of the implementation because they make it hard to add
diff --git a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
index 68aa7ce..75e35e1 100644
--- a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
@@ -10,7 +10,7 @@
                     {bool isNullable: true}) {
   if (annotation.isDynamic) return type;
   if (annotation.isMalformed) return type;
-  if (annotation.isVoid) return compiler.typesTask.typesInferrer.nullType;
+  if (annotation.isVoid) return compiler.typesTask.nullType;
   if (annotation.element == compiler.objectClass) return type;
   TypeMask otherType;
   if (annotation.kind == TypeKind.TYPEDEF
@@ -34,8 +34,7 @@
  TypeMask computeLUB(TypeMask firstType,
                      TypeMask secondType,
                      Compiler compiler) {
-  TypesInferrer inferrer = compiler.typesTask.typesInferrer;
-  TypeMask dynamicType = inferrer.dynamicType;
+  TypeMask dynamicType = compiler.typesTask.dynamicType;
   if (firstType == null) {
     return secondType;
   } else if (secondType == dynamicType) {
@@ -54,7 +53,8 @@
  * Placeholder for inferred types of local variables.
  */
 class LocalsHandler {
-  final InternalSimpleTypesInferrer inferrer;
+  final Compiler compiler;
+  final TypesInferrer inferrer;
   final Map<Element, TypeMask> locals;
   final Map<Element, Element> capturedAndBoxed;
   final Map<Element, TypeMask> fieldsInitializedInConstructor;
@@ -67,7 +67,7 @@
     return seenReturn || seenBreakOrContinue;
   }
 
-  LocalsHandler(this.inferrer)
+  LocalsHandler(this.inferrer, this.compiler)
       : locals = new Map<Element, TypeMask>(),
         capturedAndBoxed = new Map<Element, Element>(),
         fieldsInitializedInConstructor = new Map<Element, TypeMask>(),
@@ -81,6 +81,7 @@
             other.fieldsInitializedInConstructor),
         inTryBlock = other.inTryBlock || inTryBlock,
         inferrer = other.inferrer,
+        compiler = other.compiler,
         isThisExposed = other.isThisExposed;
 
   TypeMask use(Element local) {
@@ -92,7 +93,6 @@
 
   void update(Element local, TypeMask type) {
     assert(type != null);
-    Compiler compiler = inferrer.compiler;
     if (compiler.trustTypeAnnotations || compiler.enableTypeAssertions) {
       type = narrowType(type, local.computeType(compiler), compiler);
     }
@@ -139,7 +139,7 @@
       } else if (!isCaptured && other.aborts && discardIfAborts) {
         // Don't do anything.
       } else {
-        TypeMask type = computeLUB(oldType, otherType, inferrer.compiler);
+        TypeMask type = computeLUB(oldType, otherType, compiler);
         if (type != oldType) changed = true;
         locals[local] = type;
       }
@@ -175,7 +175,7 @@
         toRemove.add(element);
       } else {
         fieldsInitializedInConstructor[element] =
-            computeLUB(type, otherType, inferrer.compiler);
+            computeLUB(type, otherType, compiler);
       }
     });
     // Remove fields that were not initialized in [other].
@@ -197,7 +197,9 @@
 
 abstract class InferrerVisitor extends ResolvedVisitor<TypeMask> {
   final Element analyzedElement;
-  final InternalSimpleTypesInferrer inferrer;
+  // Subclasses know more about this field. Typing it dynamic to avoid
+  // warnings.
+  final /* TypesInferrer */ inferrer;
   final Compiler compiler;
   final Map<TargetElement, List<LocalsHandler>> breaksFor =
       new Map<TargetElement, List<LocalsHandler>>();
@@ -217,10 +219,14 @@
   InferrerVisitor(Element analyzedElement,
                   this.inferrer,
                   Compiler compiler,
-                  this.locals)
+                  [LocalsHandler handler])
     : this.compiler = compiler,
       this.analyzedElement = analyzedElement,
-      super(compiler.enqueuer.resolution.getCachedElements(analyzedElement));
+      super(compiler.enqueuer.resolution.getCachedElements(analyzedElement)) {
+    locals = (handler == null)
+        ? new LocalsHandler(inferrer, compiler)
+        : handler;
+  }
 
   TypeMask visitSendSet(SendSet node);
 
@@ -252,6 +258,7 @@
   }
 
   TypeMask visitFunctionExpression(FunctionExpression node) {
+    node.visitChildren(this);
     return inferrer.functionType;
   }
 
@@ -320,11 +327,11 @@
     if (_thisType != null) return _thisType;
     ClassElement cls = outermostElement.getEnclosingClass();
     if (compiler.world.isUsedAsMixin(cls)) {
-      return _thisType = new TypeMask.nonNullSubtype(inferrer.rawTypeOf(cls));
+      return _thisType = new TypeMask.nonNullSubtype(cls.rawType);
     } else if (compiler.world.hasAnySubclass(cls)) {
-      return _thisType = new TypeMask.nonNullSubclass(inferrer.rawTypeOf(cls));
+      return _thisType = new TypeMask.nonNullSubclass(cls.rawType);
     } else {
-      return _thisType = new TypeMask.nonNullExact(inferrer.rawTypeOf(cls));
+      return _thisType = new TypeMask.nonNullExact(cls.rawType);
     }
   }
 
@@ -332,7 +339,7 @@
   TypeMask get superType {
     if (_superType != null) return _superType;
     return _superType = new TypeMask.nonNullExact(
-        inferrer.rawTypeOf(outermostElement.getEnclosingClass().superclass));
+        outermostElement.getEnclosingClass().superclass.rawType);
   }
 
   TypeMask visitIdentifier(Identifier node) {
@@ -362,7 +369,7 @@
       Element element = elements[node.receiver];
       TypeMask existing = locals.use(element);
       TypeMask newType = narrowType(
-          existing, type, inferrer.compiler, isNullable: false);
+          existing, type, compiler, isNullable: false);
       locals.update(element, newType);
     }
   }
@@ -408,7 +415,7 @@
     } else if (const SourceString("as") == op.source) {
       TypeMask receiverType = visit(node.receiver);
       DartType type = elements.getType(node.arguments.head);
-      return narrowType(receiverType, type, inferrer.compiler);
+      return narrowType(receiverType, type, compiler);
     } else if (node.isParameterCheck) {
       node.visitChildren(this);
       return inferrer.boolType;
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
index 4a9b948..634a542 100644
--- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -13,7 +13,8 @@
 import '../native_handler.dart' as native;
 import '../tree/tree.dart';
 import '../util/util.dart' show Link;
-import 'types.dart' show TypesInferrer, FlatTypeMask, TypeMask;
+import 'types.dart'
+    show TypesInferrer, FlatTypeMask, TypeMask, ContainerTypeMask;
 
 // BUG(8802): There's a bug in the analyzer that makes the re-export
 // of Selector from dart2jslib.dart fail. For now, we work around that
@@ -111,21 +112,21 @@
       compiler = compiler,
       internal = new InternalSimpleTypesInferrer(compiler, OPTIMISTIC);
 
-  TypeMask get dynamicType => internal.dynamicType;
-  TypeMask get nullType => internal.nullType;
-  TypeMask get intType => internal.intType;
-  TypeMask get doubleType => internal.doubleType;
-  TypeMask get numType => internal.numType;
-  TypeMask get boolType => internal.boolType;
-  TypeMask get functionType => internal.functionType;
-  TypeMask get listType => internal.listType;
-  TypeMask get constListType => internal.constListType;
-  TypeMask get fixedListType => internal.fixedListType;
-  TypeMask get growableListType => internal.growableListType;
-  TypeMask get mapType => internal.mapType;
-  TypeMask get constMapType => internal.constMapType;
-  TypeMask get stringType => internal.stringType;
-  TypeMask get typeType => internal.typeType;
+  TypeMask get dynamicType => compiler.typesTask.dynamicType;
+  TypeMask get nullType => compiler.typesTask.nullType;
+  TypeMask get intType => compiler.typesTask.intType;
+  TypeMask get doubleType => compiler.typesTask.doubleType;
+  TypeMask get numType => compiler.typesTask.numType;
+  TypeMask get boolType => compiler.typesTask.boolType;
+  TypeMask get functionType => compiler.typesTask.functionType;
+  TypeMask get listType => compiler.typesTask.listType;
+  TypeMask get constListType => compiler.typesTask.constListType;
+  TypeMask get fixedListType => compiler.typesTask.fixedListType;
+  TypeMask get growableListType => compiler.typesTask.growableListType;
+  TypeMask get mapType => compiler.typesTask.mapType;
+  TypeMask get constMapType => compiler.typesTask.constMapType;
+  TypeMask get stringType => compiler.typesTask.stringType;
+  TypeMask get typeType => compiler.typesTask.typeType;
 
   TypeMask getReturnTypeOfElement(Element element) {
     if (compiler.disableTypeInference) return dynamicType;
@@ -144,6 +145,14 @@
     return internal.getTypeOfSelector(selector);
   }
 
+  Iterable<Element> getCallersOf(Element element) {
+    if (compiler.disableTypeInference) throw "Don't use me";
+    Iterable<Element> result = internal.callersOf[element];
+    return result == null
+        ? internal.callersOf[element] = const <Element>[]
+        : result;
+  }
+
   bool analyzeMain(Element element) {
     if (compiler.disableTypeInference) return true;
     bool result = internal.analyzeMain(element);
@@ -154,14 +163,24 @@
     internal = new InternalSimpleTypesInferrer(compiler, PESSIMISTIC);
     return internal.analyzeMain(element);
   }
+
+  void clear() {
+    internal.clear();
+  }
 }
 
 class InternalSimpleTypesInferrer extends TypesInferrer {
   /**
+   * Maps a node to its type. Currently used for computing element
+   * types of lists.
+   */
+  final Map<Node, TypeMask> concreteTypes = new Map<Node, TypeMask>();
+
+  /**
    * Maps an element to its callers.
    */
-  final Map<Element, Set<Element>> callersOf =
-      new Map<Element, Set<Element>>();
+  final Map<Element, Iterable<Element>> callersOf =
+      new Map<Element, Iterable<Element>>();
 
   /**
    * Maps an element to its return type.
@@ -241,23 +260,22 @@
 
   int optimismState;
 
-  TypeMask dynamicType;
   bool isDynamicType(TypeMask type) => identical(type, dynamicType);
-
-  TypeMask nullType;
-  TypeMask intType;
-  TypeMask doubleType;
-  TypeMask numType;
-  TypeMask boolType;
-  TypeMask functionType;
-  TypeMask listType;
-  TypeMask constListType;
-  TypeMask fixedListType;
-  TypeMask growableListType;
-  TypeMask mapType;
-  TypeMask constMapType;
-  TypeMask stringType;
-  TypeMask typeType;
+  TypeMask get dynamicType => compiler.typesTask.dynamicType;
+  TypeMask get nullType => compiler.typesTask.nullType;
+  TypeMask get intType => compiler.typesTask.intType;
+  TypeMask get doubleType => compiler.typesTask.doubleType;
+  TypeMask get numType => compiler.typesTask.numType;
+  TypeMask get boolType => compiler.typesTask.boolType;
+  TypeMask get functionType => compiler.typesTask.functionType;
+  TypeMask get listType => compiler.typesTask.listType;
+  TypeMask get constListType => compiler.typesTask.constListType;
+  TypeMask get fixedListType => compiler.typesTask.fixedListType;
+  TypeMask get growableListType => compiler.typesTask.growableListType;
+  TypeMask get mapType => compiler.typesTask.mapType;
+  TypeMask get constMapType => compiler.typesTask.constMapType;
+  TypeMask get stringType => compiler.typesTask.stringType;
+  TypeMask get typeType => compiler.typesTask.typeType;
 
   /**
    * These are methods that are expected to return only bool.  We optimistically
@@ -308,7 +326,6 @@
    * found as reachable. Returns whether it succeeded.
    */
   bool analyzeMain(Element element) {
-    initializeTypes();
     buildWorkQueue();
     int analyzed = 0;
     compiler.progress.reset();
@@ -345,7 +362,6 @@
       }
     } while (!workSet.isEmpty);
     dump();
-    clear();
     return true;
   }
 
@@ -377,17 +393,7 @@
    * defined in the context of [owner].
    */
   TypeMask getTypeOfNode(Element owner, Node node) {
-    var elements = compiler.enqueuer.resolution.resolvedElements[owner];
-    // TODO(ngeoffray): Not sure why the resolver would put a null
-    // mapping.
-    if (elements == null) return null;
-    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 getNonNullType(typeOfSelector(selector));
+    return getNonNullType(concreteTypes[node]);
   }
 
   void checkAnalyzedAll() {
@@ -496,42 +502,6 @@
     return cls.rawType;
   }
 
-  void initializeTypes() {
-    nullType = new TypeMask.empty();
-
-    Backend backend = compiler.backend;
-    intType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.intImplementation));
-    doubleType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.doubleImplementation));
-    numType = new TypeMask.nonNullSubclass(
-        rawTypeOf(backend.numImplementation));
-    stringType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.stringImplementation));
-    boolType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.boolImplementation));
-
-    listType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.listImplementation));
-    constListType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.constListImplementation));
-    fixedListType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.fixedListImplementation));
-    growableListType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.growableListImplementation));
-
-    mapType = new TypeMask.nonNullSubtype(
-        rawTypeOf(backend.mapImplementation));
-    constMapType = new TypeMask.nonNullSubtype(
-        rawTypeOf(backend.constMapImplementation));
-    functionType = new TypeMask.nonNullSubtype(
-        rawTypeOf(backend.functionImplementation));
-    typeType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.typeImplementation));
-
-    dynamicType = new TypeMask.subclass(rawTypeOf(compiler.objectClass));
-  }
-
   dump() {
     int interestingTypes = 0;
     returnTypeOf.forEach((Element element, TypeMask type) {
@@ -815,6 +785,12 @@
         assert(element.isGetter());
         return returnTypeOfElement(element);
       }
+    } else if (selector.isIndex()
+               && selector.mask != null
+               && selector.mask.isContainer) {
+      ContainerTypeMask mask = selector.mask;
+      TypeMask elementType = mask.elementType;
+      return elementType == null ? dynamicType : elementType;
     } else {
       return returnTypeOfElement(element);
     }
@@ -1288,7 +1264,6 @@
     Element outermostElement =
         element.getOutermostEnclosingMemberOrTopLevel().implementation;
     assert(outermostElement != null);
-    handler = handler != null ? handler : new LocalsHandler(inferrer);
     return new SimpleTypeInferrerVisitor.internal(
         element, outermostElement, inferrer, compiler, handler);
   }
@@ -1451,6 +1426,14 @@
     return inferrer.functionType;
   }
 
+  TypeMask visitLiteralList(LiteralList node) {
+    node.visitChildren(this);
+    if (node.isConst()) return inferrer.constListType;
+    return inferrer.concreteTypes.putIfAbsent(
+      node, () => new ContainerTypeMask(
+          inferrer.growableListType, node, outermostElement));
+  }
+
   bool isThisOrSuper(Node node) => node.isThis() || node.isSuper();
 
   void checkIfExposesThis(Selector selector) {
@@ -1707,9 +1690,13 @@
 
     handleStaticSend(node, selector, element, arguments);
     if (Elements.isGrowableListConstructorCall(element, node, compiler)) {
-      return inferrer.growableListType;
+      return inferrer.concreteTypes.putIfAbsent(
+          node, () => new ContainerTypeMask(
+              inferrer.growableListType, node, outermostElement));
     } else if (Elements.isFixedListConstructorCall(element, node, compiler)) {
-      return inferrer.fixedListType;
+      return inferrer.concreteTypes.putIfAbsent(
+          node, () => new ContainerTypeMask(
+              inferrer.fixedListType, node, outermostElement));
     } else if (element.isFunction() || element.isConstructor()) {
       return inferrer.returnTypeOfElement(element);
     } else {
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
index c00b4bd..e53cc0a 100644
--- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
@@ -48,6 +48,7 @@
   bool get isNullable;
   bool get isExact;
   bool get isUnion;
+  bool get isContainer;
 
   bool containsOnlyInt(Compiler compiler);
   bool containsOnlyDouble(Compiler compiler);
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index 60f3641..d260746 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -17,6 +17,7 @@
 import '../dart_types.dart';
 
 part 'concrete_types_inferrer.dart';
+part 'container_type_mask.dart';
 part 'flat_type_mask.dart';
 part 'type_mask.dart';
 part 'union_type_mask.dart';
@@ -30,22 +31,6 @@
   TypeMask getTypeOfElement(Element element);
   TypeMask getTypeOfNode(Element owner, Node node);
   TypeMask getTypeOfSelector(Selector selector);
-
-  TypeMask get dynamicType;
-  TypeMask get nullType;
-  TypeMask get intType;
-  TypeMask get doubleType;
-  TypeMask get numType;
-  TypeMask get boolType;
-  TypeMask get functionType;
-  TypeMask get listType;
-  TypeMask get constListType;
-  TypeMask get fixedListType;
-  TypeMask get growableListType;
-  TypeMask get mapType;
-  TypeMask get constMapType;
-  TypeMask get stringType;
-  TypeMask get typeType;
 }
 
 /**
@@ -65,6 +50,22 @@
     }
   }
 
+  TypeMask dynamicType;
+  TypeMask nullType;
+  TypeMask intType;
+  TypeMask doubleType;
+  TypeMask numType;
+  TypeMask boolType;
+  TypeMask functionType;
+  TypeMask listType;
+  TypeMask constListType;
+  TypeMask fixedListType;
+  TypeMask growableListType;
+  TypeMask mapType;
+  TypeMask constMapType;
+  TypeMask stringType;
+  TypeMask typeType;
+
   /// Replaces native types by their backend implementation.
   Element normalize(Element cls) {
     if (cls == compiler.boolClass) {
@@ -130,8 +131,12 @@
   TypeMask _best(var type1, var type2) {
     if (type1 == null) return type2;
     if (type2 == null) return type1;
+    if (type1.isContainer) type1 = type1.asFlat;
+    if (type2.isContainer) type2 = type2.asFlat;
     if (type1.isExact) {
       if (type2.isExact) {
+        // TODO(polux): Update the code to not have this situation.
+        if (type1.base != type2.base) return type1;
         assert(same(type1.base, type2.base));
         return type1.isNullable ? type2 : type1;
       } else {
@@ -174,11 +179,56 @@
     }
   }
 
+  // TODO(ngeoffray): Get rid of this method. Unit tests don't always
+  // ensure these classes are resolved.
+  rawTypeOf(ClassElement cls) {
+    cls.ensureResolved(compiler);
+    assert(cls.rawType != null);
+    return cls.rawType;
+  }
+
+  void initializeTypes() {
+    nullType = new TypeMask.empty();
+
+    Backend backend = compiler.backend;
+    intType = new TypeMask.nonNullExact(
+        rawTypeOf(backend.intImplementation));
+    doubleType = new TypeMask.nonNullExact(
+        rawTypeOf(backend.doubleImplementation));
+    numType = new TypeMask.nonNullSubclass(
+        rawTypeOf(backend.numImplementation));
+    stringType = new TypeMask.nonNullExact(
+        rawTypeOf(backend.stringImplementation));
+    boolType = new TypeMask.nonNullExact(
+        rawTypeOf(backend.boolImplementation));
+
+    listType = new TypeMask.nonNullExact(
+        rawTypeOf(backend.listImplementation));
+    constListType = new TypeMask.nonNullExact(
+        rawTypeOf(backend.constListImplementation));
+    fixedListType = new TypeMask.nonNullExact(
+        rawTypeOf(backend.fixedListImplementation));
+    growableListType = new TypeMask.nonNullExact(
+        rawTypeOf(backend.growableListImplementation));
+
+    mapType = new TypeMask.nonNullSubtype(
+        rawTypeOf(backend.mapImplementation));
+    constMapType = new TypeMask.nonNullSubtype(
+        rawTypeOf(backend.constMapImplementation));
+    functionType = new TypeMask.nonNullSubtype(
+        rawTypeOf(backend.functionImplementation));
+    typeType = new TypeMask.nonNullExact(
+        rawTypeOf(backend.typeImplementation));
+
+    dynamicType = new TypeMask.subclass(rawTypeOf(compiler.objectClass));
+  }
+
   /**
    * Called when resolution is complete.
    */
   void onResolutionComplete(Element mainElement) {
     measure(() {
+      initializeTypes();
       typesInferrer.analyzeMain(mainElement);
       if (concreteTypesInferrer != null) {
         bool success = concreteTypesInferrer.analyzeMain(mainElement);
@@ -190,6 +240,8 @@
         }
       }
     });
+    compiler.containerTracer.analyze();
+    typesInferrer.clear();
   }
 
   /**
diff --git a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
index 0eb33f6..357486b 100644
--- a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
@@ -30,7 +30,13 @@
       } else if (mask.isEmpty && !mask.isNullable) {
         continue;
       } else {
-        FlatTypeMask flatMask = mask;
+        FlatTypeMask flatMask;
+        if (mask.isContainer) {
+          ContainerTypeMask container = mask;
+          flatMask = container.asFlat;
+        } else {
+          flatMask = mask;
+        }
         assert(flatMask.base == null
                || flatMask.base.element != compiler.dynamicClass);
         int inListIndex = -1;
@@ -140,6 +146,7 @@
   }
 
   TypeMask union(var other, Compiler compiler) {
+    if (other.isContainer) other = other.asFlat;
     if (!other.isUnion && disjointMasks.contains(other)) return this;
 
     List<FlatTypeMask> newList =
@@ -154,6 +161,7 @@
   }
 
   TypeMask intersection(var other, Compiler compiler) {
+    if (other.isContainer) other = other.asFlat;
     if (!other.isUnion && disjointMasks.contains(other)) return other;
 
     List<TypeMask> intersections = <TypeMask>[];
@@ -189,6 +197,7 @@
   bool get isNullable => disjointMasks.any((e) => e.isNullable);
   bool get isExact => false;
   bool get isUnion => true;
+  bool get isContainer => false;
 
   bool containsOnlyInt(Compiler compiler) => false;
   bool containsOnlyDouble(Compiler compiler) => false;
diff --git a/sdk/lib/_internal/lib/async_patch.dart b/sdk/lib/_internal/lib/async_patch.dart
index 9d8b237e..78ce9cd 100644
--- a/sdk/lib/_internal/lib/async_patch.dart
+++ b/sdk/lib/_internal/lib/async_patch.dart
@@ -7,24 +7,23 @@
 import 'dart:_isolate_helper' show IsolateNatives, TimerImpl;
 import 'dart:_foreign_helper' show JS, DART_CLOSURE_TO_JS;
 
-patch class Timer {
-  patch factory Timer(Duration duration, void callback()) {
-    int milliseconds = duration.inMilliseconds;
-    if (milliseconds < 0) milliseconds = 0;
-    return new TimerImpl(milliseconds, callback);
-  }
+patch Timer _createTimer(Duration duration, void callback()) {
+  int milliseconds = duration.inMilliseconds;
+  if (milliseconds < 0) milliseconds = 0;
+  return new TimerImpl(milliseconds, callback);
+}
 
-  patch factory Timer.periodic(Duration duration, void callback(Timer timer)) {
-    int milliseconds = duration.inMilliseconds;
-    if (milliseconds < 0) milliseconds = 0;
-    return new TimerImpl.periodic(milliseconds, callback);
-  }
+patch Timer _createPeriodicTimer(Duration duration,
+                                 void callback(Timer timer)) {
+  int milliseconds = duration.inMilliseconds;
+  if (milliseconds < 0) milliseconds = 0;
+  return new TimerImpl.periodic(milliseconds, callback);
 }
 
 patch class _AsyncRun {
   patch static void _enqueueImmediate(void callback()) {
     // TODO(9002): don't use the Timer to enqueue the immediate callback.
-    Timer.run(callback);
+    _createTimer(Duration.ZERO, callback);
   }
 }
 
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index 18d6e6d..59b8355 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -93,23 +93,49 @@
   }
 }
 
-class JsTypeMirror implements TypeMirror {
-  final Symbol simpleName;
-  JsTypeMirror(this.simpleName);
+abstract class JsMirror {
+  const JsMirror();
+
+  abstract String get _prettyName;
+
+  String toString() => _prettyName;
 }
 
-class JsLibraryMirror extends JsObjectMirror implements LibraryMirror {
+abstract class JsDeclarationMirror extends JsMirror
+    implements DeclarationMirror {
   final Symbol simpleName;
+
+  const JsDeclarationMirror(this.simpleName);
+
+  bool get isPrivate => n(simpleName).startsWith('_');
+
+  bool get isTopLevel => owner != null && owner is LibraryMirror;
+
+  String toString() => "$_prettyName on '${n(simpleName)}'";
+}
+
+class JsTypeMirror extends JsDeclarationMirror implements TypeMirror {
+  JsTypeMirror(Symbol simpleName)
+      : super(simpleName);
+
+  String get _prettyName => 'TypeMirror';
+}
+
+class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror
+    implements LibraryMirror {
   final Uri uri;
   final List<String> _classes;
   final List<String> _functions;
   final List _metadata;
 
-  JsLibraryMirror(this.simpleName,
+  JsLibraryMirror(Symbol simpleName,
                  this.uri,
                  this._classes,
                  this._functions,
-                 this._metadata);
+                 this._metadata)
+      : super(simpleName);
+
+  String get _prettyName => 'LibraryMirror';
 
   Symbol get qualifiedName => simpleName;
 
@@ -321,11 +347,11 @@
     return JSInvocationMirror.invokeFromMirror(invocation, reflectee);
   }
 
-  String toString() => 'InstanceMirror($reflectee)';
+  String toString() => 'InstanceMirror on ${Error.safeToString(reflectee)}';
 }
 
-class JsClassMirror extends JsObjectMirror implements ClassMirror {
-  final Symbol simpleName;
+class JsClassMirror extends JsTypeMirror with JsObjectMirror
+    implements ClassMirror {
   final _jsConstructor;
   final String _fields;
   final List _fieldsMetadata;
@@ -336,10 +362,13 @@
   // Set as side-effect of accessing JsLibraryMirror.classes.
   JsLibraryMirror _owner;
 
-  JsClassMirror(this.simpleName,
+  JsClassMirror(Symbol simpleName,
                 this._jsConstructor,
                 this._fields,
-                this._fieldsMetadata);
+                this._fieldsMetadata)
+      : super(simpleName);
+
+  String get _prettyName => 'ClassMirror';
 
   Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
 
@@ -516,13 +545,10 @@
     }
     return _superclass == this ? null : _superclass;
   }
-
-  String toString() => 'ClassMirror(${n(simpleName)})';
 }
 
-class JsVariableMirror implements VariableMirror {
+class JsVariableMirror extends JsDeclarationMirror implements VariableMirror {
   // TODO(ahe): The values in these fields are virtually untested.
-  final Symbol simpleName;
   final String _jsName;
   final bool isFinal;
   final bool isStatic;
@@ -530,11 +556,12 @@
   DeclarationMirror _owner;
   List _metadata;
 
-  JsVariableMirror(this.simpleName,
+  JsVariableMirror(Symbol simpleName,
                    this._jsName,
                    this.isFinal,
                    this.isStatic,
-                   this._metadataFunction);
+                   this._metadataFunction)
+      : super(simpleName);
 
   factory JsVariableMirror.from(String descriptor, metadataFunction) {
     int length = descriptor.length;
@@ -556,6 +583,8 @@
         s(accessorName), jsName, isFinal, false, metadataFunction);
   }
 
+  String get _prettyName => 'VariableMirror';
+
   TypeMirror get type => JsMirrorSystem._dynamicType;
 
   DeclarationMirror get owner => _owner;
@@ -570,12 +599,6 @@
     return _metadata.map(reflect).toList();
   }
 
-  bool get isPrivate => n(simpleName).startsWith('_');
-
-  bool get isTopLevel => owner != null && owner is LibraryMirror;
-
-  String toString() => 'VariableMirror(${n(qualifiedName)})';
-
   static int fieldCode(int code) {
     if (code >= 60 && code <= 64) return code - 59;
     if (code >= 123 && code <= 126) return code - 117;
@@ -585,7 +608,8 @@
 }
 
 class JsClosureMirror extends JsInstanceMirror implements ClosureMirror {
-  JsClosureMirror(reflectee) : super(reflectee);
+  JsClosureMirror(reflectee)
+      : super(reflectee);
 
   MethodMirror get function {
     disableTreeShaking();
@@ -628,10 +652,11 @@
     return new Future<InstanceMirror>(
         () => apply(positionalArguments, namedArguments));
   }
+
+  String toString() => "ClosureMirror on '${Error.safeToString(reflectee)}'";
 }
 
-class JsMethodMirror implements MethodMirror {
-  final Symbol simpleName;
+class JsMethodMirror extends JsDeclarationMirror implements MethodMirror {
   final _jsFunction;
   final int _parameterCount;
   final bool isGetter;
@@ -640,12 +665,13 @@
   DeclarationMirror _owner;
   List _metadata;
 
-  JsMethodMirror(this.simpleName,
+  JsMethodMirror(Symbol simpleName,
                  this._jsFunction,
                  this._parameterCount,
                  this.isGetter,
                  this.isSetter,
-                 this.isStatic);
+                 this.isStatic)
+      : super(simpleName);
 
   factory JsMethodMirror.fromUnmangledName(String name, jsFunction) {
     List<String> info = name.split(':');
@@ -670,6 +696,8 @@
         isGetter, isSetter, false);
   }
 
+  String get _prettyName => 'MethodMirror';
+
   List<ParameterMirror> get parameters {
     // TODO(ahe): Fill the list with parameter mirrors.
     return new List<ParameterMirror>(_parameterCount);
@@ -685,18 +713,6 @@
     }
     return _metadata.map(reflect).toList();
   }
-
-  // TODO(ahe): Share with VariableMirror.
-  bool get isPrivate => n(simpleName).startsWith('_');
-
-  // TODO(ahe): Share with VariableMirror.
-  bool get isTopLevel => owner != null && owner is LibraryMirror;
-
-  String toString() {
-    return
-        'MethodMirror(${n(simpleName)}'
-        '${isSetter ? ", setter" : (isGetter ? ", getter" : "")})';
-  }
 }
 
 Symbol computeQualifiedName(DeclarationMirror owner, Symbol simpleName) {
diff --git a/sdk/lib/_internal/lib/regexp_helper.dart b/sdk/lib/_internal/lib/regexp_helper.dart
index 0e923a3..c9d9636 100644
--- a/sdk/lib/_internal/lib/regexp_helper.dart
+++ b/sdk/lib/_internal/lib/regexp_helper.dart
@@ -7,37 +7,56 @@
 // Helper method used by internal libraries.
 regExpGetNative(JSSyntaxRegExp regexp) => regexp._nativeRegExp;
 
-class JSSyntaxRegExp implements RegExp {
-  final String _pattern;
-  final bool _isMultiLine;
-  final bool _isCaseSensitive;
-  var _nativeRegExp;
+/**
+ * Returns a native version of the RegExp with the global flag set.
+ *
+ * The RegExp's `lastIndex` property is zero when it is returned.
+ *
+ * The returned regexp is shared, and its `lastIndex` property may be
+ * modified by other uses, so the returned regexp must be used immediately
+ * when it's returned, with no user-provided code run in between.
+ */
+regExpGetGlobalNative(JSSyntaxRegExp regexp) {
+  var regexp = regexp._nativeGlobalVersion;
+  JS("void", "#.lastIndex = 0", regexp);
+  return regexp;
+}
 
-  JSSyntaxRegExp._internal(String pattern,
-                           bool multiLine,
-                           bool caseSensitive,
-                           bool global)
-      : _nativeRegExp = makeNative(pattern, multiLine, caseSensitive, global),
-        this._pattern = pattern,
-        this._isMultiLine = multiLine,
-        this._isCaseSensitive = caseSensitive;
+class JSSyntaxRegExp implements RegExp {
+  final _nativeRegExp;
+  var _nativeGlobalRegExp;
+  var _nativeAnchoredRegExp;
 
   JSSyntaxRegExp(String pattern,
-                 {bool multiLine: false,
-                  bool caseSensitive: true})
-      : this._internal(pattern, multiLine, caseSensitive, false);
+                 { bool multiLine: false,
+                   bool caseSensitive: true })
+      : this._nativeRegExp =
+            makeNative(pattern, multiLine, caseSensitive, false);
 
-  JSSyntaxRegExp._globalVersionOf(JSSyntaxRegExp other)
-      : this._internal(other.pattern,
-                       other.isMultiLine,
-                       other.isCaseSensitive,
-                       true);
+  get _nativeGlobalVersion {
+    if (_nativeGlobalRegExp != null) return _nativeGlobalRegExp;
+    return _nativeGlobalRegExp = makeNative(_pattern,
+                                            _isMultiLine,
+                                            _isCaseSensitive,
+                                            true);
+  }
 
-  JSSyntaxRegExp._anchoredVersionOf(JSSyntaxRegExp other)
-      : this._internal(other.pattern + "|()",
-                       other.isMultiLine,
-                       other.isCaseSensitive,
-                       true);
+  get _nativeAnchoredVersion {
+    if (_nativeAnchoredRegExp != null) return _nativeAnchoredRegExp;
+    // An "anchored version" of a regexp is created by adding "|()" to the
+    // source. This means that the regexp always matches at the first position
+    // that it tries, and you can see if the original regexp matched, or it
+    // was the added zero-width match that matched, by looking at the last
+    // capture. If it is a String, the match participated, otherwise it didn't.
+    return _nativeAnchoredRegExp = makeNative("$_pattern|()",
+                                              _isMultiLine,
+                                              _isCaseSensitive,
+                                              true);
+  }
+
+  String get _pattern  => JS("String", "#.source", _nativeRegExp);
+  bool get _isMultiLine => JS("bool", "#.multiline", _nativeRegExp);
+  bool get _isCaseSensitive => JS("bool", "!#.ignoreCase", _nativeRegExp);
 
   static makeNative(
       String pattern, bool multiLine, bool caseSensitive, bool global) {
@@ -68,10 +87,7 @@
     List<String> m =
         JS('=List|Null', r'#.exec(#)', _nativeRegExp, checkString(str));
     if (m == null) return null;
-    var matchStart = JS('int', r'#.index', m);
-    // m.lastIndex only works with flag 'g'.
-    var matchEnd = matchStart + m[0].length;
-    return new _MatchImplementation(pattern, str, matchStart, matchEnd, m);
+    return new _MatchImplementation(this, m);
   }
 
   bool hasMatch(String str) {
@@ -80,7 +96,8 @@
 
   String stringMatch(String str) {
     var match = firstMatch(str);
-    return match == null ? null : match.group(0);
+    if (match != null) return match.group(0);
+    return null;
   }
 
   Iterable<Match> allMatches(String str) {
@@ -88,24 +105,31 @@
     return new _AllMatchesIterable(this, str);
   }
 
+  Match _execGlobal(String string, int start) {
+    Object regexp = _nativeGlobalVersion;
+    JS("void", "#.lastIndex = #", regexp, start);
+    List match = JS("=List|Null", "#.exec(#)", regexp, string);
+    if (match == null) return null;
+    return new _MatchImplementation(this, match);
+  }
+
+  Match _execAnchored(String string, int start) {
+    Object regexp = _nativeAnchoredVersion;
+    JS("void", "#.lastIndex = #", regexp, start);
+    List match = JS("=List|Null", "#.exec(#)", regexp, string);
+    if (match == null) return null;
+    // If the last capture group participated, the original regexp did not
+    // match at the start position.
+    if (match[match.length - 1] != null) return null;
+    match.length -= 1;
+    return new _MatchImplementation(this, match);
+  }
+
   Match matchAsPrefix(String string, [int start = 0]) {
     if (start < 0 || start > string.length) {
       throw new RangeError.range(start, 0, string.length);
     }
-    // An "anchored version" of a regexp is created by adding "|()" to the
-    // source. This means that the regexp always matches at the first position
-    // that it tries, and you can see if the original regexp matched, or it
-    // was the added zero-width match that matched, by looking at the last
-    // capture. If it is a String, the match participated, otherwise it didn't.
-    JSSyntaxRegExp regexp = new JSSyntaxRegExp._anchoredVersionOf(this);
-    if (start > 0) {
-      JS("void", "#.lastIndex = #", regExpGetNative(regexp), start);
-    }
-    _MatchImplementation match = regexp.firstMatch(string);
-    if (match == null) return null;
-    if (match._groups[match._groups.length - 1] != null) return null;
-    match._groups.length -= 1;
-    return match;
+    return _execAnchored(string, start);
   }
 
   String get pattern => _pattern;
@@ -115,21 +139,22 @@
 
 class _MatchImplementation implements Match {
   final Pattern pattern;
-  final String str;
-  final int start;
-  final int end;
-  final List<String> _groups;
+  // Contains a JS RegExp match object.
+  // It is an Array of String values with extra "index" and "input" properties.
+  final List<String> _match;
 
-  const _MatchImplementation(
-      this.pattern,
-      this.str,
-      int this.start,
-      int this.end,
-      List<String> this._groups);
+  _MatchImplementation(this.pattern, this._match) {
+    assert(JS("var", "#.input", _match) is String);
+    assert(JS("var", "#.index", _match) is int);
+  }
 
-  String group(int index) => _groups[index];
+  String get str => JS("String", "#.input", _match);
+  int get start => JS("int", "#.index", _match);
+  int get end => start + _match[0].length;
+
+  String group(int index) => _match[index];
   String operator [](int index) => group(index);
-  int get groupCount => _groups.length - 1;
+  int get groupCount => _match.length - 1;
 
   List<String> groups(List<int> groups) {
     List<String> out = [];
@@ -142,54 +167,41 @@
 
 class _AllMatchesIterable extends IterableBase<Match> {
   final JSSyntaxRegExp _re;
-  final String _str;
+  final String _string;
 
-  const _AllMatchesIterable(this._re, this._str);
+  const _AllMatchesIterable(this._re, this._string);
 
-  Iterator<Match> get iterator => new _AllMatchesIterator(_re, _str);
+  Iterator<Match> get iterator => new _AllMatchesIterator(_re, _string);
 }
 
 class _AllMatchesIterator implements Iterator<Match> {
-  final RegExp _regExp;
-  final RegExp _globalRegExp;
-  String _str;
+  final JSSyntaxRegExp _regExp;
+  String _string;
   Match _current;
 
-  _AllMatchesIterator(JSSyntaxRegExp re, String this._str)
-    : _regExp = re,
-      _globalRegExp = new JSSyntaxRegExp._globalVersionOf(re);
+  _AllMatchesIterator(this._regExp, this._string);
 
   Match get current => _current;
 
   bool moveNext() {
-    if (_str == null) return false;
-    // firstMatch actually acts as nextMatch because of
-    // hidden global flag.
-    if (_current != null && _current.start == _current.end) {
-      // Advance implicit start-position if last match was empty.
-      JS("void", "#.lastIndex++", regExpGetNative(_globalRegExp));
+    if (_string == null) return false;
+    int index = 0;
+    if (_current != null) {
+      index = _current.end;
+      if (_current.start == index) {
+        index++;
+      }
     }
-    List<String> m =
-        JS('=List|Null', r'#.exec(#)', regExpGetNative(_globalRegExp), _str);
-    if (m == null) {
-      _current = null;
-      _str = null;  // Marks iteration as ended.
+    _current = _regExp._execGlobal(_string, index);
+    if (_current == null) {
+      _string = null;  // Marks iteration as ended.
       return false;
     }
-    var matchStart = JS('int', r'#.index', m);
-    var matchEnd = matchStart + m[0].length;
-    _current = new _MatchImplementation(_regExp, _str, matchStart, matchEnd, m);
     return true;
   }
 }
 
-Match firstMatchAfter(JSSyntaxRegExp re, String str, int start) {
-  JSSyntaxRegExp global = new JSSyntaxRegExp._globalVersionOf(re);
-  JS("void", "#.lastIndex = #", regExpGetNative(global), start);
-  List<String> m =
-      JS('=List|Null', r'#.exec(#)', regExpGetNative(global), checkString(str));
-  if (m == null) return null;
-  var matchStart = JS('int', r'#.index', m);
-  var matchEnd = matchStart + m[0].length;
-  return new _MatchImplementation(re, str, matchStart, matchEnd, m);
+/** Find the first match of [regExp] in [string] at or after [start]. */
+Match firstMatchAfter(JSSyntaxRegExp regExp, String string, int start) {
+  return regExp._execGlobal(string, start);
 }
diff --git a/sdk/lib/_internal/lib/string_helper.dart b/sdk/lib/_internal/lib/string_helper.dart
index f321fbb..1c430c8 100644
--- a/sdk/lib/_internal/lib/string_helper.dart
+++ b/sdk/lib/_internal/lib/string_helper.dart
@@ -94,14 +94,14 @@
         return result.toString();
       }
     } else {
-      var quoter = JS('', "new RegExp(#, 'g')", r'[-[\]{}()*+?.,\\^$|#\s]');
+      var quoter = JS('', "new RegExp(#, 'g')", r'[[\]{}()*+?.\\^$|]');
       var quoted = JS('String', r'#.replace(#, "\\$&")', from, quoter);
       var replacer = JS('', "new RegExp(#, 'g')", quoted);
       return stringReplaceJS(receiver, replacer, to);
     }
   } else if (from is JSSyntaxRegExp) {
-    var re = new JSSyntaxRegExp._globalVersionOf(from);
-    return stringReplaceJS(receiver, re._nativeRegExp, to);
+    var re = regExpGetGlobalNative(from);
+    return stringReplaceJS(receiver, re, to);
   } else {
     checkNull(from);
     // TODO(floitsch): implement generic String.replace (with patterns).
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index b028d80..acd808a 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.dart
@@ -16,3 +16,4 @@
 part 'stream_impl.dart';
 part 'stream_pipe.dart';
 part 'timer.dart';
+part 'zone.dart';
diff --git a/sdk/lib/async/async_sources.gypi b/sdk/lib/async/async_sources.gypi
index b39435a..dc0dbec 100644
--- a/sdk/lib/async/async_sources.gypi
+++ b/sdk/lib/async/async_sources.gypi
@@ -17,5 +17,6 @@
     'stream_impl.dart',
     'stream_pipe.dart',
     'timer.dart',
+    'zone.dart',
   ],
 }
diff --git a/sdk/lib/async/event_loop.dart b/sdk/lib/async/event_loop.dart
index 2802e40..bc0a638 100644
--- a/sdk/lib/async/event_loop.dart
+++ b/sdk/lib/async/event_loop.dart
@@ -18,13 +18,23 @@
       callback();
     } catch (e) {
       _AsyncRun._enqueueImmediate(_asyncRunCallback);
-      throw;
+      rethrow;
     }
   }
   // Any new callback must register a callback function now.
   _callbacksAreEnqueued = false;
 }
 
+void _scheduleAsyncCallback(callback) {
+  // Optimizing a group of Timer.run callbacks to be executed in the
+  // same Timer callback.
+  _asyncCallbacks.add(callback);
+  if (!_callbacksAreEnqueued) {
+    _AsyncRun._enqueueImmediate(_asyncRunCallback);
+    _callbacksAreEnqueued = true;
+  }
+}
+
 /**
  * Runs the given [callback] asynchronously.
  *
@@ -45,13 +55,7 @@
  *     }
  */
 void runAsync(void callback()) {
-  // Optimizing a group of Timer.run callbacks to be executed in the
-  // same Timer callback.
-  _asyncCallbacks.add(callback);
-  if (!_callbacksAreEnqueued) {
-    _AsyncRun._enqueueImmediate(_asyncRunCallback);
-    _callbacksAreEnqueued = true;
-  }
+  _Zone._current.runAsync(callback);
 }
 
 class _AsyncRun {
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index 47c51ec..be0b7a2 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -11,7 +11,10 @@
   final Future<T> future;
   bool _isComplete = false;
 
-  _Completer() : future = new _FutureImpl<T>();
+  _Completer() : future = new _FutureImpl<T>() {
+    _FutureImpl futureImpl = future;
+    futureImpl._zone.expectCallback();
+  }
 
   void _setFutureValue(T value);
   void _setFutureError(error);
@@ -19,6 +22,8 @@
   void complete([T value]) {
     if (_isComplete) throw new StateError("Future already completed");
     _isComplete = true;
+    _FutureImpl futureImpl = future;
+    futureImpl._zone.cancelCallbackExpectation();
     _setFutureValue(value);
   }
 
@@ -29,7 +34,13 @@
       // Force the stack trace onto the error, even if it already had one.
       _attachStackTrace(error, stackTrace);
     }
-    _setFutureError(error);
+    _FutureImpl futureImpl = future;
+    if (futureImpl._inSameErrorZone(_Zone.current)) {
+      futureImpl._zone.cancelCallbackExpectation();
+      _setFutureError(error);
+    } else {
+      _Zone.current.handleUncaughtError(error);
+    }
   }
 
   bool get isCompleted => _isComplete;
@@ -74,6 +85,8 @@
   }
   void _sendValue(T value);
   void _sendError(error);
+
+  bool _inSameErrorZone(_Zone otherZone);
 }
 
 /** Adapter for a [_FutureImpl] to be a future result listener. */
@@ -83,6 +96,61 @@
   _FutureListenerWrapper(this.future);
   _sendValue(T value) { future._setValue(value); }
   _sendError(error) { future._setError(error); }
+  bool _inSameErrorZone(_Zone otherZone) => future._inSameErrorZone(otherZone);
+}
+
+/**
+ * This listener is installed at error-zone boundaries. It signals an
+ * uncaught error in the zone of origin when an error is sent from one error
+ * zone to another.
+ *
+ * When a Future is listening to another Future and they have not been
+ * instantiated in the same error-zone then Futures put an instance of this
+ * class between them (see [_FutureImpl._addListener]).
+ *
+ * For example:
+ *
+ *     var completer = new Completer();
+ *     var future = completer.future.then((x) => x);
+ *     catchErrors(() {
+ *       var future2 = future.catchError(print);
+ *     });
+ *     completer.completeError(499);
+ *
+ * In this example `future` and `future2` are in different error-zones. The
+ * error (499) that originates outside `catchErrors` must not reach the
+ * `catchError` future (`future2`) inside `catchErrors`.
+ *
+ * When invoking `catchError` on `future` the Future installs an
+ * [_ErrorZoneBoundaryListener] between itself and the result, `future2`.
+ *
+ * Conceptually _ErrorZoneBoundaryListeners could be implemented as
+ * `catchError`s on the origin future as well.
+ */
+class _ErrorZoneBoundaryListener implements _FutureListener {
+  _FutureListener _nextListener;
+  final _FutureListener _listener;
+
+  _ErrorZoneBoundaryListener(this._listener);
+
+  bool _inSameErrorZone(_Zone otherZone) {
+    // Should never be called. We use [_inSameErrorZone] to know if we have
+    // to insert an instance of [_ErrorZoneBoundaryListener] (and in the
+    // controller). Once we have inserted one we should never need to use it
+    // anymore.
+    throw new UnsupportedError(
+        "A Zone boundary doesn't support the inSameErrorZone test.");
+  }
+
+  void _sendValue(value) {
+    _listener._sendValue(value);
+  }
+
+  void _sendError(error) {
+    // We are not allowed to send an error from one error-zone to another.
+    // This is the whole purpose of this class.
+    _Zone.current.handleUncaughtError(error);
+  }
 }
 
 class _FutureImpl<T> implements Future<T> {
@@ -118,6 +186,8 @@
   /** Whether the future is complete, and as what. */
   int _state = _INCOMPLETE;
 
+  final _Zone _zone = _Zone.current.fork();
+
   bool get _isChained => (_state & _CHAINED) != 0;
   bool get _hasChainedListener => _state == _CHAINED;
   bool get _isComplete => _state >= _VALUE;
@@ -215,6 +285,10 @@
 
   Stream<T> asStream() => new Stream.fromFuture(this);
 
+  bool _inSameErrorZone(_Zone otherZone) {
+    return _zone.inSameErrorZone(otherZone);
+  }
+
   void _setValue(T value) {
     if (_isComplete) throw new StateError("Future already completed");
     _FutureListener listeners = _isChained ? null : _removeListeners();
@@ -267,17 +341,16 @@
         _clearUnhandledError();
         // TODO(floitsch): Hook this into unhandled error handling.
         var error = _resultOrListeners;
-        print("Uncaught Error: ${error}");
-        var trace = getAttachedStackTrace(error);
-        if (trace != null) {
-          print("Stack Trace:\n$trace\n");
-        }
-        throw error;
+        _zone.handleUncaughtError(error);
       }
     });
   }
 
   void _addListener(_FutureListener listener) {
+    assert(listener._nextListener == null);
+    if (!listener._inSameErrorZone(_zone)) {
+      listener = new _ErrorZoneBoundaryListener(listener);
+    }
     if (_isChained) {
       _state = _CHAINED;  // In case it was _CHAINED_UNLISTENED.
       _FutureImpl resultSource = _chainSource;
@@ -298,7 +371,6 @@
       });
     } else {
       assert(!_isComplete);
-      assert(listener._nextListener == null);
       listener._nextListener = _resultOrListeners;
       _resultOrListeners = listener;
     }
@@ -434,13 +506,24 @@
   // _FutureListener implementation.
   _FutureListener _nextListener;
 
-  void _sendValue(S value);
+  _TransformFuture() {
+    _zone.expectCallback();
+  }
 
-  void _sendError(error);
+  void _sendValue(S value) {
+    _zone.executeCallback(() => _zonedSendValue(value));
+  }
+
+  void _sendError(error) {
+    _zone.executeCallback(() => _zonedSendError(error));
+  }
 
   void _subscribeTo(_FutureImpl future) {
     future._addListener(this);
   }
+
+  void _zonedSendValue(S value);
+  void _zonedSendError(error);
 }
 
 /** The onValue and onError handlers return either a value or a future */
@@ -459,7 +542,7 @@
 
   _ThenFuture(this._onValue);
 
-  _sendValue(S value) {
+  _zonedSendValue(S value) {
     assert(_onValue != null);
     var result;
     try {
@@ -471,7 +554,7 @@
     _setOrChainValue(result);
   }
 
-  void _sendError(error) {
+  void _zonedSendError(error) {
     _setError(error);
   }
 }
@@ -483,11 +566,11 @@
 
   _CatchErrorFuture(this._onError, this._test);
 
-  _sendValue(T value) {
+  _zonedSendValue(T value) {
     _setValue(value);
   }
 
-  _sendError(error) {
+  _zonedSendError(error) {
     assert(_onError != null);
     // if _test is supplied, check if it returns true, otherwise just
     // forward the error unmodified.
@@ -524,7 +607,7 @@
 
   // The _sendValue method is inherited from ThenFuture.
 
-  void _sendError(error) {
+  void _zonedSendError(error) {
     assert(_onError != null);
     var result;
     try {
@@ -543,7 +626,7 @@
 
   _WhenFuture(this._action);
 
-  void _sendValue(T value) {
+  void _zonedSendValue(T value) {
     try {
       var result = _action();
       if (result is Future) {
@@ -560,7 +643,7 @@
     _setValue(value);
   }
 
-  void _sendError(error) {
+  void _zonedSendError(error) {
     try {
       var result = _action();
       if (result is Future) {
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index abfd648..2cdbeaf 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -357,7 +357,7 @@
   try {
     notificationHandler();
   } catch (e, s) {
-    _throwDelayed(e, s);
+    _Zone.current.handleUncaughtError(_asyncError(e, s));
   }
 }
 
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index e46ba50..85aa083 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -4,20 +4,6 @@
 
 part of dart.async;
 
-/** Throws the given error in the next cycle. */
-_throwDelayed(var error, [Object stackTrace]) {
-  // We are going to reach the top-level here, but there might be a global
-  // exception handler. This means that we shouldn't print the stack trace.
-  // TODO(floitsch): Find better solution that doesn't print the stack trace
-  // if there is a global exception handler.
-  runAsync(() {
-    if (stackTrace != null) print(stackTrace);
-    var trace = getAttachedStackTrace(error);
-    if (trace != null && trace != stackTrace) print(trace);
-    throw error;
-  });
-}
-
 /** Abstract and private interface for a place to put events. */
 abstract class _EventSink<T> {
   void _add(T data);
@@ -96,6 +82,7 @@
   Function _onData;
   _ErrorHandler _onError;
   _DoneHandler _onDone;
+  final _Zone _zone = _Zone.current;
 
   /** Bit vector based on state-constants above. */
   int _state;
@@ -115,6 +102,7 @@
     assert(_onData != null);
     assert(_onError != null);
     assert(_onDone != null);
+    _zone.expectCallback();
   }
 
   /**
@@ -233,6 +221,7 @@
 
   void _cancel() {
     _state |= _STATE_CANCELED;
+    _zone.cancelCallbackExpectation();
     if (_hasPending) {
       _pending.cancelSchedule();
     }
@@ -293,7 +282,8 @@
 
   // Hooks called when the input is paused, unpaused or canceled.
   // These must not throw. If overwritten to call user code, include suitable
-  // try/catch wrapping and send any errors to [_throwDelayed].
+  // try/catch wrapping and send any errors to
+  // [_Zone.current.handleUncaughtError].
   void _onPause() {
     assert(_isInputPaused);
   }
@@ -334,11 +324,7 @@
     assert(!_inCallback);
     bool wasInputPaused = _isInputPaused;
     _state |= _STATE_IN_CALLBACK;
-    try {
-      _onData(data);
-    } catch (e, s) {
-      _throwDelayed(e, s);
-    }
+    _zone.executePeriodicCallbackGuarded(() => _onData(data));
     _state &= ~_STATE_IN_CALLBACK;
     _checkState(wasInputPaused);
   }
@@ -349,10 +335,11 @@
     assert(!_inCallback);
     bool wasInputPaused = _isInputPaused;
     _state |= _STATE_IN_CALLBACK;
-    try {
-      _onError(error);
-    } catch (e, s) {
-      _throwDelayed(e, s);
+    if (!_zone.inSameErrorZone(_Zone.current)) {
+      // Errors are not allowed to traverse zone boundaries.
+      _Zone.current.handleUncaughtError(error);
+    } else {
+      _zone.executePeriodicCallbackGuarded(() => _onError(error));
     }
     _state &= ~_STATE_IN_CALLBACK;
     if (_cancelOnError) {
@@ -366,11 +353,7 @@
     assert(!_isPaused);
     assert(!_inCallback);
     _state |= (_STATE_CANCELED | _STATE_CLOSED | _STATE_IN_CALLBACK);
-    try {
-      _onDone();
-    } catch (e, s) {
-      _throwDelayed(e, s);
-    }
+    _zone.executeCallbackGuarded(_onDone);
     _onCancel();  // No checkState after cancel, it is always the last event.
     _state &= ~_STATE_IN_CALLBACK;
   }
@@ -551,7 +534,7 @@
 
 /** Default error handler, reports the error to the global handler. */
 void _nullErrorHandler(error) {
-  _throwDelayed(error);
+  _Zone.current.handleUncaughtError(error);
 }
 
 /** Default done handler, does nothing. */
diff --git a/sdk/lib/async/timer.dart b/sdk/lib/async/timer.dart
index bfa7ced..3544728 100644
--- a/sdk/lib/async/timer.dart
+++ b/sdk/lib/async/timer.dart
@@ -29,7 +29,9 @@
    * Note: If Dart code using Timer is compiled to JavaScript, the finest
    * granularity available in the browser is 4 milliseconds.
    */
-  external factory Timer(Duration duration, void callback());
+  factory Timer(Duration duration, void callback()) {
+    return _Zone.current.createTimer(duration, callback);
+  }
 
   /**
    * Creates a new repeating timer.
@@ -37,8 +39,10 @@
    * The [callback] is invoked repeatedly with [duration] intervals until
    * canceled. A negative duration is treated similar to a duration of 0.
    */
-  external factory Timer.periodic(Duration duration,
-                                  void callback(Timer timer));
+  factory Timer.periodic(Duration duration,
+                                  void callback(Timer timer)) {
+    return _Zone.current.createPeriodicTimer(duration, callback);
+  }
 
   /**
    * Runs the given [callback] asynchronously as soon as possible.
@@ -54,3 +58,7 @@
    */
   void cancel();
 }
+
+external Timer _createTimer(Duration duration, void callback());
+external Timer _createPeriodicTimer(Duration duration,
+                                    void callback(Timer timer));
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
new file mode 100644
index 0000000..b92aa16
--- /dev/null
+++ b/sdk/lib/async/zone.dart
@@ -0,0 +1,504 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+/**
+ * A Zone represents the asynchronous version of a dynamic extent. Asynchronous
+ * callbacks are executed in the zone they have been queued in. For example,
+ * the callback of a `future.then` is executed in the same zone as the one where
+ * the `then` was invoked.
+ */
+abstract class _Zone {
+  /// The currently running zone.
+  static _Zone _current = new _DefaultZone();
+
+  static _Zone get current => _current;
+
+  void handleUncaughtError(error);
+
+  /**
+   * Returns true if `this` and [otherZone] are in the same error zone.
+   */
+  bool inSameErrorZone(_Zone otherZone);
+
+  /**
+   * Returns a zone for reentry in the zone.
+   *
+   * The returned zone is equivalent to `this` (and frequently is indeed
+   * `this`).
+   *
+   * The main purpose of this method is to allow `this` to attach debugging
+   * information to the returned zone.
+   */
+  _Zone fork();
+
+  /**
+   * Tells the zone that it needs to wait for one more callback before it is
+   * done.
+   *
+   * Use [executeCallback] or [cancelCallbackExpectation] when the callback is executed
+   * (or canceled).
+   */
+  void expectCallback();
+
+  /**
+   * Tells the zone not to wait for a callback anymore.
+   *
+   * Prefer calling [executeCallback], instead. This method is mostly useful
+   * for repeated callbacks (for example with [Timer.periodic]). In this case
+   * one should should call [expectCallback] when the repeated callback is
+   * initiated, and [cancelCallbackExpectation] when the [Timer] is canceled.
+   */
+  void cancelCallbackExpectation();
+
+  /**
+   * Executes the given callback in this zone.
+   *
+   * Decrements the number of callbacks this zone is waiting for (see
+   * [expectCallback]).
+   */
+  void executeCallback(void fun());
+
+  /**
+   * Same as [executeCallback] but catches uncaught errors and gives them to
+   * [handleUncaughtError].
+   */
+  void executeCallbackGuarded(void fun());
+
+  /**
+   * Same as [executeCallback] but does not decrement the number of
+   * callbacks this zone is waiting for (see [expectCallback]).
+   */
+  void executePeriodicCallback(void fun());
+
+  /**
+   * Same as [executePeriodicCallback] but catches uncaught errors and gives
+   * them to [handleUncaughtError].
+   */
+  void executePeriodicCallbackGuarded(void fun());
+
+  /**
+   * Runs [fun] asynchronously in this zone.
+   */
+  void runAsync(void fun());
+
+  /**
+   * Creates a Timer where the callback is executed in this zone.
+   */
+  Timer createTimer(Duration duration, void callback());
+
+  /**
+   * Creates a periodic Timer where the callback is executed in this zone.
+   */
+  Timer createPeriodicTimer(Duration duration, void callback(Timer timer));
+
+  /**
+   * The error zone is the one that is responsible for dealing with uncaught
+   * errors. Errors are not allowed to cross zones with different error-zones.
+   */
+  _Zone get _errorZone;
+
+  /**
+   * Adds [child] as a child of `this`.
+   *
+   * This usually means that the [child] is in the asynchronous dynamic extent
+   * of `this`.
+   */
+  void _addChild(_Zone child);
+
+  /**
+   * Removes [child] from `this`' children.
+   *
+   * This usually means that the [child] has finished executing and is done.
+   */
+  void _removeChild(_Zone child);
+}
+
+/**
+ * Basic implementation of a [_Zone]. This class is intended for subclassing.
+ */
+class _ZoneBase implements _Zone {
+  /// The parent zone. [null] if `this` is the default zone.
+  final _Zone _parentZone;
+
+  /// The children of this zone. A child's [_parentZone] is `this`.
+  // TODO(floitsch): this should be a double-linked list.
+  final List<_Zone> _children = <_Zone>[];
+
+  /// The number of outstanding (asynchronous) callbacks. As long as the
+  /// number is greater than 0 it means that the zone is not done yet.
+  int _openCallbacks = 0;
+
+  bool _isExecutingCallback = false;
+
+  _ZoneBase(this._parentZone) {
+    _parentZone._addChild(this);
+  }
+
+  _ZoneBase._defaultZone() : _parentZone = null {
+    assert(this is _DefaultZone);
+  }
+
+  _Zone get _errorZone => _parentZone._errorZone;
+
+  void handleUncaughtError(error) {
+    _parentZone.handleUncaughtError(error);
+  }
+
+  bool inSameErrorZone(_Zone otherZone) => _errorZone == otherZone._errorZone;
+
+  _Zone fork() => this;
+
+  expectCallback() => _openCallbacks++;
+
+  cancelCallbackExpectation() {
+    _openCallbacks--;
+    _checkIfDone();
+  }
+
+  /**
+   * Cleans up this zone when it is done.
+   *
+   * This releases internal memore structures that are no longer necessary.
+   *
+   * A zone is done when its dynamic extent has finished executing and
+   * there are no outstanding asynchronous callbacks.
+   */
+  _dispose() {
+    if (_parentZone != null) {
+      _parentZone._removeChild(this);
+    }
+  }
+
+  /**
+   * Checks if the zone is done and doesn't have any outstanding callbacks
+   * anymore.
+   *
+   * This method is called when an operation has decremented the
+   * outstanding-callback count, or when a child has been removed.
+   */
+  void _checkIfDone() {
+    if (!_isExecutingCallback && _openCallbacks == 0 && _children.isEmpty) {
+      _dispose();
+    }
+  }
+
+  /**
+   * Executes the given callback in this zone.
+   *
+   * Decrements the open-callback counter and checks (after the call) if the
+   * zone is done.
+   */
+  void executeCallback(void fun()) {
+    _openCallbacks--;
+    this._runUnguarded(fun);
+  }
+
+  /**
+   * Same as [executeCallback] but catches uncaught errors and gives them to
+   * [handleUncaughtError].
+   */
+  void executeCallbackGuarded(void fun()) {
+    _openCallbacks--;
+    this._runGuarded(fun);
+  }
+
+  /**
+   * Same as [executeCallback] but doesn't decrement the open-callback counter.
+   */
+  void executePeriodicCallback(void fun()) {
+    this._runUnguarded(fun);
+  }
+
+  /**
+   * Same as [executePeriodicCallback] but catches uncaught errors and gives
+   * them to [handleUncaughtError].
+   */
+  void executePeriodicCallbackGuarded(void fun()) {
+    this._runGuarded(fun);
+  }
+
+  _runInZone(fun(), bool handleUncaught) {
+    if (identical(_Zone._current, this)
+        && !handleUncaught
+        && _isExecutingCallback) {
+      // No need to go through a try/catch.
+      return fun();
+    }
+
+    _Zone oldZone = _Zone._current;
+    _Zone._current = this;
+    // While we are executing the function we don't want to have other
+    // synchronous calls to think that they closed the zone. By incrementing
+    // the _openCallbacks count we make sure that their test will fail.
+    // As a side effect it will make nested calls faster since they are
+    // (probably) in the same zone and have an _openCallbacks > 0.
+    bool oldIsExecuting = _isExecutingCallback;
+    _isExecutingCallback = true;
+    // TODO(430): remove second try when VM bug is fixed.
+    try {
+      try {
+        return fun();
+      } catch(e, s) {
+        if (handleUncaught) {
+          handleUncaughtError(_asyncError(e, s));
+        } else {
+          rethrow;
+        }
+      }
+    } finally {
+      _isExecutingCallback = oldIsExecuting;
+      _Zone._current = oldZone;
+      _checkIfDone();
+    }
+  }
+
+  /**
+   * Runs the function and catches uncaught errors.
+   *
+   * Uncaught errors are given to [handleUncaughtError].
+   */
+  _runGuarded(void fun()) {
+    return _runInZone(fun, true);
+  }
+
+  /**
+   * Runs the function but doesn't catch uncaught errors.
+   */
+  _runUnguarded(void fun()) {
+    return _runInZone(fun, false);
+  }
+
+  runAsync(void fun()) {
+    _openCallbacks++;
+    _scheduleAsyncCallback(() {
+      _openCallbacks--;
+      _runGuarded(fun);
+    });
+  }
+
+  Timer createTimer(Duration duration, void callback()) {
+    return new _ZoneTimer(this, duration, callback);
+  }
+
+  Timer createPeriodicTimer(Duration duration, void callback(Timer timer)) {
+    return new _PeriodicZoneTimer(this, duration, callback);
+  }
+
+  void _addChild(_Zone child) {
+    _children.add(child);
+  }
+
+  void _removeChild(_Zone child) {
+    assert(!_children.isEmpty);
+    // Children are usually added and removed fifo or filo.
+    if (identical(_children.last, child)) {
+      _children.length--;
+      _checkIfDone();
+      return;
+    }
+    for (int i = 0; i < _children.length; i++) {
+      if (identical(_children[i], child)) {
+        _children[i] = _children[_children.length - 1];
+        _children.length--;
+        // No need to check for done, as otherwise _children.last above would
+        // have triggered.
+        assert(!_children.isEmpty);
+        return;
+      }
+    }
+    throw new ArgumentError(child);
+  }
+}
+
+/**
+ * The default-zone that conceptually surrounds the `main` function.
+ */
+class _DefaultZone extends _ZoneBase {
+  _DefaultZone() : super._defaultZone();
+
+  _Zone get _errorZone => this;
+
+  handleUncaughtError(error) {
+    _scheduleAsyncCallback(() {
+      print("Uncaught Error: ${error}");
+      var trace = getAttachedStackTrace(error);
+      _attachStackTrace(error, null);
+      if (trace != null) {
+        print("Stack Trace:\n$trace\n");
+      }
+      throw error;
+    });
+  }
+}
+
+typedef void _CompletionCallback();
+
+/**
+ * A zone that executes a callback when the zone is dead.
+ */
+class _WaitForCompletionZone extends _ZoneBase {
+  final _CompletionCallback _onDone;
+
+  _WaitForCompletionZone(_Zone parentZone, this._onDone) : super(parentZone);
+
+  /**
+   * Runs the given function asynchronously. Executes the [_onDone] callback
+   * when the zone is done.
+   */
+  runWaitForCompletion(void fun()) {
+    return this._runUnguarded(fun);
+  }
+
+  _dispose() {
+    super._dispose();
+    _onDone();
+  }
+
+  String toString() => "WaitForCompletion ${super.toString()}";
+}
+
+typedef void _HandleErrorCallback(error);
+
+/**
+ * A zone that collects all uncaught errors and provides them in a stream.
+ * The stream is closed when the zone is done.
+ */
+class _CatchErrorsZone extends _WaitForCompletionZone {
+  final _HandleErrorCallback _handleError;
+
+  _CatchErrorsZone(_Zone parentZone, this._handleError, void onDone())
+    : super(parentZone, onDone);
+
+  _Zone get _errorZone => this;
+
+  handleUncaughtError(error) {
+    try {
+      _handleError(error);
+    } catch(e, s) {
+      if (identical(e, s)) {
+        _parentZone.handleUncaughtError(error);
+      } else {
+        _parentZone.handleUncaughtError(_asyncError(e, s));
+      }
+    }
+  }
+
+  /**
+   * Runs the given function asynchronously. Executes the [_onDone] callback
+   * when the zone is done.
+   */
+  runWaitForCompletion(void fun()) {
+    return this._runGuarded(fun);
+  }
+
+  String toString() => "WithErrors ${super.toString()}";
+}
+
+typedef void _TimerCallback();
+
+/**
+ * A [Timer] class that takes zones into account.
+ */
+class _ZoneTimer implements Timer {
+  final _Zone _zone;
+  final _TimerCallback _callback;
+  Timer _timer;
+  bool _isDone = false;
+
+  _ZoneTimer(this._zone, Duration duration, this._callback) {
+    _zone.expectCallback();
+    _timer = _createTimer(duration, this.run);
+  }
+
+  void run() {
+    _isDone = true;
+    _zone.executeCallbackGuarded(_callback);
+  }
+
+  void cancel() {
+    if (!_isDone) _zone.cancelCallbackExpectation();
+    _isDone = true;
+    _timer.cancel();
+  }
+}
+
+typedef void _PeriodicTimerCallback(Timer timer);
+
+/**
+ * A [Timer] class for periodic callbacks that takes zones into account.
+ */
+class _PeriodicZoneTimer implements Timer {
+  final _Zone _zone;
+  final _PeriodicTimerCallback _callback;
+  Timer _timer;
+  bool _isDone = false;
+
+  _PeriodicZoneTimer(this._zone, Duration duration, this._callback) {
+    _zone.expectCallback();
+    _timer = _createPeriodicTimer(duration, this.run);
+  }
+
+  void run(Timer timer) {
+    assert(identical(_timer, timer));
+    _zone.executePeriodicCallbackGuarded(() { _callback(this); });
+  }
+
+  void cancel() {
+    if (!_isDone) _zone.cancelCallbackExpectation();
+    _isDone = true;
+    _timer.cancel();
+  }
+}
+
+/**
+ * Runs [body] in its own zone.
+ *
+ * If [onError] is non-null the zone is considered an error zone. All uncaught
+ * errors, synchronous or asynchronous, in the zone are caught and handled
+ * by the callback.
+ *
+ * [onDone] (if non-null) is invoked when the zone has no more outstanding
+ * callbacks.
+ *
+ * Examples:
+ *
+ *     runZonedExperimental(() {
+ *       new Future(() { throw "asynchronous error"; });
+ *     }, onError: print);  // Will print "asynchronous error".
+ *
+ * The following example prints "1", "2", "3", "4" in this order.
+ *
+ *     runZonedExperimental(() {
+ *       print(1);
+ *       new Future.value(3).then(print);
+ *     }, onDone: () { print(4); });
+ *     print(2);
+ *
+ * Errors may never cross error-zone boundaries. This is intuitive for leaving
+ * a zone, but it also applies for errors that would enter an error-zone.
+ * Errors that try to cross error-zone boundaries are considered uncaught.
+ *
+ *     var future = new Future.value(499);
+ *     runZonedExperimental(() {
+ *       future = future.then((_) { throw "error in first error-zone"; });
+ *       runZonedExperimental(() {
+ *         future = future.catchError((e) { print("Never reached!"); });
+ *       }, onError: (e) { print("unused error handler"); });
+ *     }, onError: (e) { print("catches error of first error-zone."); });
+ *
+ */
+runZonedExperimental(body(), { void onError(error), void onDone() }) {
+  // TODO(floitsch): we probably still want to install a new Zone.
+  if (onError == null && onDone == null) return body();
+  if (onError == null) {
+    _WaitForCompletionZone zone =
+        new _WaitForCompletionZone(_Zone._current, onDone);
+    return zone.runWaitForCompletion(body);
+  }
+  if (onDone == null) onDone = _nullDoneHandler;
+  _CatchErrorsZone zone = new _CatchErrorsZone(_Zone._current, onError, onDone);
+  return zone.runWaitForCompletion(body);
+}
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index cdb6df4..f47ef4f 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -9,8 +9,10 @@
   static const DELETE_REQUEST = 1;
   static const EXISTS_REQUEST = 2;
   static const CREATE_TEMP_REQUEST = 3;
-  static const LIST_REQUEST = 4;
-  static const RENAME_REQUEST = 5;
+  static const LIST_START_REQUEST = 4;
+  static const LIST_NEXT_REQUEST = 5;
+  static const LIST_STOP_REQUEST = 6;
+  static const RENAME_REQUEST = 7;
 
   _Directory(String this._path);
   _Directory.fromPath(Path path) : this(path.toNativePath());
@@ -186,9 +188,6 @@
     return new Directory(result);
   }
 
-  Future<Directory> _deleteHelper(bool recursive, String errorMsg) {
-  }
-
   Future<Directory> delete({recursive: false}) {
     _ensureDirectoryService();
     List request = new List(3);
@@ -240,68 +239,7 @@
 
   Stream<FileSystemEntity> list({bool recursive: false,
                                  bool followLinks: true}) {
-    const int LIST_FILE = 0;
-    const int LIST_DIRECTORY = 1;
-    const int LIST_LINK = 2;
-    const int LIST_ERROR = 3;
-    const int LIST_DONE = 4;
-
-    const int RESPONSE_TYPE = 0;
-    const int RESPONSE_PATH = 1;
-    const int RESPONSE_COMPLETE = 1;
-    const int RESPONSE_ERROR = 2;
-
-    var controller = new StreamController<FileSystemEntity>(sync: true);
-
-    List request = [ _Directory.LIST_REQUEST, path, recursive, followLinks ];
-    ReceivePort responsePort = new ReceivePort();
-    // Use a separate directory service port for each listing as
-    // listing operations on the same directory can run in parallel.
-    _Directory._newServicePort().send(request, responsePort.toSendPort());
-    responsePort.receive((message, replyTo) {
-      if (message is !List || message[RESPONSE_TYPE] is !int) {
-        responsePort.close();
-        controller.addError(new DirectoryException("Internal error"));
-        return;
-      }
-      switch (message[RESPONSE_TYPE]) {
-        case LIST_FILE:
-          controller.add(new File(message[RESPONSE_PATH]));
-          break;
-        case LIST_DIRECTORY:
-          controller.add(new Directory(message[RESPONSE_PATH]));
-          break;
-        case LIST_LINK:
-          controller.add(new Link(message[RESPONSE_PATH]));
-          break;
-        case LIST_ERROR:
-          var errorType =
-              message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE];
-          if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) {
-            controller.addError(new ArgumentError());
-          } else if (errorType == _OSERROR_RESPONSE) {
-            var responseError = message[RESPONSE_ERROR];
-            var err = new OSError(
-                responseError[_OSERROR_RESPONSE_MESSAGE],
-                responseError[_OSERROR_RESPONSE_ERROR_CODE]);
-            var errorPath = message[RESPONSE_PATH];
-            if (errorPath == null) errorPath = path;
-            controller.addError(
-                new DirectoryException("Directory listing failed",
-                                         errorPath,
-                                         err));
-          } else {
-            controller.addError(new DirectoryException("Internal error"));
-          }
-          break;
-        case LIST_DONE:
-          responsePort.close();
-          controller.close();
-          break;
-      }
-    });
-
-    return controller.stream;
+    return new _AsyncDirectoryLister(path, recursive, followLinks).stream;
   }
 
   List listSync({bool recursive: false, bool followLinks: true}) {
@@ -342,3 +280,135 @@
   final String _path;
   SendPort _directoryService;
 }
+
+class _AsyncDirectoryLister {
+  static const int LIST_FILE = 0;
+  static const int LIST_DIRECTORY = 1;
+  static const int LIST_LINK = 2;
+  static const int LIST_ERROR = 3;
+  static const int LIST_DONE = 4;
+
+  static const int RESPONSE_TYPE = 0;
+  static const int RESPONSE_PATH = 1;
+  static const int RESPONSE_COMPLETE = 1;
+  static const int RESPONSE_ERROR = 2;
+
+  final String path;
+  final bool recursive;
+  final bool followLinks;
+
+  StreamController controller;
+  int id;
+  bool canceled = false;
+  bool nextRunning = false;
+  bool closed = false;
+
+  _AsyncDirectoryLister(String this.path,
+                        bool this.recursive,
+                        bool this.followLinks) {
+    controller = new StreamController(onListen: onListen,
+                                      onResume: onResume,
+                                      onCancel: onCancel);
+  }
+
+  Stream get stream => controller.stream;
+
+  void onListen() {
+    var request = [_Directory.LIST_START_REQUEST, path, recursive, followLinks];
+    _Directory._newServicePort().call(request)
+        .then((response) {
+          if (response is int) {
+            id = response;
+            next();
+          } else {
+            error(response);
+            controller.close();
+          }
+        });
+  }
+
+  void onResume() {
+    if (!nextRunning) next();
+  }
+
+  void onCancel() {
+    canceled = true;
+    // If we are active, but not requesting, close.
+    if (!nextRunning) {
+      close();
+    }
+  }
+
+  void next() {
+    if (canceled) {
+      close();
+      return;
+    }
+    if (id == null) return;
+    if (controller.isPaused) return;
+    assert(!nextRunning);
+    nextRunning = true;
+    _Directory._newServicePort().call([_Directory.LIST_NEXT_REQUEST, id])
+        .then((result) {
+          if (result is List) {
+            assert(result.length % 2 == 0);
+            for (int i = 0; i < result.length; i++) {
+              assert(i % 2 == 0);
+              switch (result[i++]) {
+                case LIST_FILE:
+                  controller.add(new File(result[i]));
+                  break;
+                case LIST_DIRECTORY:
+                  controller.add(new Directory(result[i]));
+                  break;
+                case LIST_LINK:
+                  controller.add(new Link(result[i]));
+                  break;
+                case LIST_ERROR:
+                  error(result[i]);
+                  break;
+                case LIST_DONE:
+                  close();
+                  return;
+              }
+            }
+          } else {
+            controller.addError(new DirectoryException("Internal error"));
+          }
+          nextRunning = false;
+          next();
+        });
+  }
+
+  void close() {
+    if (closed) return;
+    if (id == null) return;
+    closed = true;
+    _Directory._newServicePort().call([_Directory.LIST_STOP_REQUEST, id])
+        .then((_) {
+          controller.close();
+        });
+  }
+
+  void error(message) {
+    var errorType =
+        message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE];
+    if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) {
+      controller.addError(new ArgumentError());
+    } else if (errorType == _OSERROR_RESPONSE) {
+      var responseError = message[RESPONSE_ERROR];
+      var err = new OSError(
+          responseError[_OSERROR_RESPONSE_MESSAGE],
+          responseError[_OSERROR_RESPONSE_ERROR_CODE]);
+      var errorPath = message[RESPONSE_PATH];
+      if (errorPath == null) errorPath = path;
+      controller.addError(
+          new DirectoryException("Directory listing failed",
+                                 errorPath,
+                                 err));
+    } else {
+      controller.addError(
+          new DirectoryException("Internal error"));
+    }
+  }
+}
diff --git a/tests/compiler/dart2js/concrete_type_inference_test.dart b/tests/compiler/dart2js/concrete_type_inference_test.dart
index 581b26b..8284448 100644
--- a/tests/compiler/dart2js/concrete_type_inference_test.dart
+++ b/tests/compiler/dart2js/concrete_type_inference_test.dart
@@ -63,6 +63,7 @@
   });
   checkPrintType('[]', (compiler, type) {
     var inferrer = compiler.typesTask.typesInferrer;
+    if (type.isContainer) type = type.asFlat;
     Expect.identical(inferrer.growableListType, type);
   });
   checkPrintType('null', (compiler, type) {
diff --git a/tests/compiler/dart2js/list_tracer_test.dart b/tests/compiler/dart2js/list_tracer_test.dart
new file mode 100644
index 0000000..a82cac8
--- /dev/null
+++ b/tests/compiler/dart2js/list_tracer_test.dart
@@ -0,0 +1,220 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import
+    '../../../sdk/lib/_internal/compiler/implementation/types/types.dart'
+    show ContainerTypeMask, TypeMask;
+
+import 'compiler_helper.dart';
+import 'parser_helper.dart';
+
+
+String generateTest(String listAllocation) {
+  return """
+int anInt = 42;
+double aDouble = 42.5;
+
+class A {
+  final field;
+  var nonFinalField;
+
+  A(this.field);
+
+  A.bar(list) {
+    nonFinalField = list;
+  }
+
+  receiveIt(list) {
+    list[0] = aDouble;
+  }
+
+  returnIt() {
+    return listReturnedFromSelector;
+  }
+
+  useField() {
+    field[0] = aDouble;
+  }
+
+  set callSetter(list) {
+    list[0] = aDouble;
+  }
+
+  operator[](index) {
+    index[0] = aDouble;
+  }
+
+  operator[]=(index, value) {
+    index[0] = anInt;
+    if (value == listEscapingTwiceInIndexSet) {
+      value[0] = aDouble;
+    }
+  }
+}
+
+class B extends A {
+  B(list) : super.bar(list);
+
+  set nonFinalField(value) {
+    value[0] = aDouble;
+  }
+}
+
+var listInField = $listAllocation;
+var listPassedToClosure = $listAllocation;
+var listReturnedFromClosure = $listAllocation;
+var listPassedToMethod = $listAllocation;
+var listReturnedFromMethod = $listAllocation;
+var listUsedWithCascade = $listAllocation;
+var listUsedInClosure = $listAllocation;
+var listPassedToSelector = $listAllocation;
+var listReturnedFromSelector = $listAllocation;
+var listUsedWithAddAndInsert = $listAllocation;
+var listUsedWithNonOkSelector = $listAllocation;
+var listUsedWithConstraint = $listAllocation;
+var listEscapingFromSetter = $listAllocation;
+var listUsedInLocal = $listAllocation;
+var listUnset = $listAllocation;
+var listOnlySetWithConstraint = $listAllocation;
+var listEscapingInSetterValue = $listAllocation;
+var listEscapingInIndex = $listAllocation;
+var listEscapingInIndexSet = $listAllocation;
+var listEscapingTwiceInIndexSet = $listAllocation;
+var listPassedAsOptionalParameter = $listAllocation;
+var listPassedAsNamedParameter = $listAllocation;
+var listSetInNonFinalField = $listAllocation;
+
+foo(list) {
+  list[0] = aDouble;
+}
+
+bar() {
+  return listReturnedFromMethod;
+}
+
+takeOptional([list]) {
+  list[0] = aDouble;
+}
+
+takeNamed({list}) {
+  list[0] = aDouble;
+}
+
+main() {
+  listReturnedFromMethod[0] = anInt;
+  bar()[0] = aDouble;
+
+  listPassedToMethod[0] = anInt;
+  foo(listPassedToMethod);
+
+  listPassedToClosure[0] = anInt;
+  ((a) => a[0] = aDouble)(listPassedToClosure);
+
+  listReturnedFromClosure[0] = anInt;
+  (() => listReturnedFromClosure)[0] = aDouble;
+
+  listInField[0] = anInt;
+  new A(listInField).useField();
+
+  listUsedWithCascade[0] = anInt;
+  listUsedWithCascade..[0] = aDouble;
+
+  listUsedInClosure[0] = anInt;
+  (() => listUsedInClosure[0] = aDouble)();
+
+  listPassedToSelector[0] = anInt;
+  new A(null).receiveIt(listPassedToSelector);
+
+  listReturnedFromSelector[0] = anInt;
+  new A(null).returnIt()[0] = aDouble;
+
+  listUsedWithAddAndInsert.add(anInt);
+  listUsedWithAddAndInsert.insert(0, aDouble);
+
+  listUsedWithNonOkSelector[0] = anInt;
+  listUsedWithNonOkSelector.addAll(listPassedToClosure);
+
+  listUsedWithConstraint[0] = anInt;
+  listUsedWithConstraint[0]++;
+  listUsedWithConstraint[0] += anInt;
+
+  listEscapingFromSetter[0] = anInt;
+  foo(new A(null).field = listEscapingFromSetter);
+
+  listUsedInLocal[0] = anInt;
+  var a = listUsedInLocal;
+  listUsedInLocal[1] = aDouble;
+
+  // At least use [listUnused] in a local to pretend it's used.
+  var b = listUnset;
+
+  listOnlySetWithConstraint[0]++;
+
+  listEscapingInSetterValue[0] = anInt;
+  new A().callSetter = listEscapingInSetterValue;
+
+  listEscapingInIndex[0] = anInt;
+  new A()[listEscapingInIndex];
+
+  new A()[listEscapingInIndexSet] = 42;
+
+  new A()[listEscapingTwiceInIndexSet] = listEscapingTwiceInIndexSet;
+
+  listPassedAsOptionalParameter[0] = anInt;
+  takeOptional(listPassedAsOptionalParameter);
+
+  listPassedAsNamedParameter[0] = anInt;
+  takeNamed(list: listPassedAsNamedParameter);
+
+  listSetInNonFinalField[0] = anInt;
+  new B(listSetInNonFinalField);
+}
+""";
+}
+
+void main() {
+  doTest('[]'); // Test literal list.
+  doTest('new List()'); // Test growable list.
+  doTest('new List(1)'); // Test fixed list.
+}
+
+void doTest(String allocation) {
+  Uri uri = new Uri(scheme: 'source');
+  var compiler = compilerFor(generateTest(allocation), uri);
+  compiler.runCompiler(uri);
+  var typesInferrer = compiler.typesTask.typesInferrer;
+
+  checkType(String name, type) {
+    var element = findElement(compiler, name);
+    ContainerTypeMask mask = typesInferrer.internal.typeOf[element];
+    Expect.equals(type, mask.elementType.simplify(compiler), name);
+  }
+
+  checkType('listInField', typesInferrer.numType.nullable());
+  checkType('listPassedToMethod', typesInferrer.numType.nullable());
+  checkType('listReturnedFromMethod', typesInferrer.numType.nullable());
+  checkType('listUsedWithCascade', typesInferrer.numType.nullable());
+  checkType('listUsedInClosure', typesInferrer.numType.nullable());
+  checkType('listPassedToSelector', typesInferrer.numType.nullable());
+  checkType('listReturnedFromSelector', typesInferrer.numType.nullable());
+  checkType('listUsedWithAddAndInsert', typesInferrer.numType.nullable());
+  checkType('listUsedWithConstraint', typesInferrer.numType.nullable());
+  checkType('listEscapingFromSetter', typesInferrer.numType.nullable());
+  checkType('listUsedInLocal', typesInferrer.numType.nullable());
+  checkType('listEscapingInSetterValue', typesInferrer.numType.nullable());
+  checkType('listEscapingInIndex', typesInferrer.numType.nullable());
+  checkType('listEscapingInIndexSet', typesInferrer.intType.nullable());
+  checkType('listEscapingTwiceInIndexSet', typesInferrer.numType.nullable());
+  checkType('listSetInNonFinalField', typesInferrer.numType.nullable());
+
+  checkType('listPassedToClosure', typesInferrer.dynamicType);
+  checkType('listReturnedFromClosure', typesInferrer.dynamicType);
+  checkType('listUsedWithNonOkSelector', typesInferrer.dynamicType);
+  checkType('listPassedAsOptionalParameter', typesInferrer.dynamicType);
+  checkType('listPassedAsNamedParameter', typesInferrer.dynamicType);
+
+  checkType('listUnset', new TypeMask.empty());
+  checkType('listOnlySetWithConstraint', new TypeMask.empty());
+}
diff --git a/tests/compiler/dart2js/mirror_tree_shaking_test.dart b/tests/compiler/dart2js/mirror_tree_shaking_test.dart
index 7025c41..4869c70 100644
--- a/tests/compiler/dart2js/mirror_tree_shaking_test.dart
+++ b/tests/compiler/dart2js/mirror_tree_shaking_test.dart
@@ -44,6 +44,7 @@
   Expect.isFalse(compiler.compilationFailed);
   Expect.isFalse(compiler.enqueuer.resolution.hasEnqueuedEverything);
   Expect.isFalse(compiler.enqueuer.codegen.hasEnqueuedEverything);
+  Expect.isFalse(compiler.disableTypeInference);
 }
 
 const Map MEMORY_SOURCE_FILES = const {
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 4d80094..9fde6d6 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -65,6 +65,7 @@
   class ConstantMap {}
   class TypeImpl {}
   S() {}
+  throwCyclicInit() {}
   throwExpression(e) {}
   unwrapException(e) {}
   assertHelper(a) {}
@@ -167,7 +168,7 @@
   abstract class StackTrace {}
   class Type {}
   class Function {}
-  class List<E> {}
+  class List<E> { List([length]); }
   abstract class Map<K,V> {}
   class DateTime {
     DateTime(year);
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 6e91831..6bd2384 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -105,7 +105,7 @@
 list_removeat_test: fail
 
 [ $arch == simarm && $mode == debug ]
-collection_to_string_test: Crash # Issue: 11207
+collection_to_string_test: Pass, Crash # Issue: 11207
 
 [ $arch == mips ]
 *: Skip
diff --git a/tests/language/language.status b/tests/language/language.status
index 7554f25..e55fc34 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -553,4 +553,17 @@
 *: Skip
 
 [ $arch == simmips ]
-*: Skip
+arithmetic_test: Fail, Crash
+bit_operations_test: Crash, Fail
+char_escape_test: Pass, Crash
+deopt_smi_op_test: Fail
+div_with_power_of_two_test: Fail
+gc_test: Crash
+invocation_mirror_test: Fail
+load_to_load_forwarding_vm_test: Fail
+named_parameters_with_conversions_test: Pass, Crash
+positive_bit_operations_test: Pass, Fail, Crash
+left_shift_test: Pass, Fail
+large_implicit_getter_test: Crash, Pass
+stack_overflow_test: Crash, Pass
+stack_overflow_stacktrace_test: Crash, Pass
diff --git a/tests/lib/async/catch_errors.dart b/tests/lib/async/catch_errors.dart
new file mode 100644
index 0000000..c289690
--- /dev/null
+++ b/tests/lib/async/catch_errors.dart
@@ -0,0 +1,29 @@
+library catch_errors;
+
+import 'dart:async';
+
+Stream catchErrors(void body()) {
+  StreamController controller;
+
+  bool onError(e) {
+    controller.add(e);
+    return true;
+  }
+
+  void onDone() {
+    controller.close();
+  }
+
+  void onListen() {
+    runZonedExperimental(body, onError: onError, onDone: onDone);
+  }
+
+  controller = new StreamController(onListen: onListen);
+  return controller.stream;
+}
+
+Future waitForCompletion(void body()) {
+  Completer completer = new Completer.sync();
+  runZonedExperimental(body, onDone: completer.complete);
+  return completer.future;
+}
diff --git a/tests/lib/async/catch_errors10_test.dart b/tests/lib/async/catch_errors10_test.dart
new file mode 100644
index 0000000..b554dbd
--- /dev/null
+++ b/tests/lib/async/catch_errors10_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 "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  bool futureWasExecuted = false;
+  // Test that `catchErrors` waits for a future that has been delayed by
+  // `Timer.run`.
+  catchErrors(() {
+    Timer.run(() {
+      new Future.value(499).then((x) {
+        futureWasExecuted = true;
+      });
+    });
+    return 'allDone';
+  }).listen((x) {
+      Expect.fail("Unexpected callback");
+    },
+    onDone: () {
+      Expect.isTrue(futureWasExecuted);
+      port.close();
+    });
+}
diff --git a/tests/lib/async/catch_errors11_test.dart b/tests/lib/async/catch_errors11_test.dart
new file mode 100644
index 0000000..53755261
--- /dev/null
+++ b/tests/lib/async/catch_errors11_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test that `catchErrors` catches errors that are delayed by `Timer.run`.
+  catchErrors(() {
+    events.add("catch error entry");
+    new Future.error("future error");
+    Timer.run(() { throw "timer error"; });
+  }).listen((x) {
+      events.add(x);
+    },
+    onDone: () {
+      Expect.listEquals([
+                         "catch error entry",
+                         "main exit",
+                         "future error",
+                         "timer error",
+                         ],
+                         events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/catch_errors12_test.dart b/tests/lib/async/catch_errors12_test.dart
new file mode 100644
index 0000000..deb7cb4
--- /dev/null
+++ b/tests/lib/async/catch_errors12_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 "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Tests that errors that have been delayed by several milliseconds with
+  // Timers are still caught by `catchErrors`.
+  catchErrors(() {
+    events.add("catch error entry");
+    Timer.run(() { throw "timer error"; });
+    new Timer(const Duration(milliseconds: 100), () { throw "timer2 error"; });
+    new Future.value(499).then((x) {
+      new Timer(const Duration(milliseconds: 200), () { throw x; });
+    });
+    throw "catch error";
+  }).listen((x) {
+      events.add(x);
+    },
+    onDone: () {
+      Expect.listEquals([
+            "catch error entry",
+            "main exit",
+            "catch error",
+            "timer error",
+            "timer2 error",
+            499,
+          ],
+          events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/catch_errors13_test.dart b/tests/lib/async/catch_errors13_test.dart
new file mode 100644
index 0000000..7c6752a
--- /dev/null
+++ b/tests/lib/async/catch_errors13_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Work around bug that makes runAsync use Timers. By invoking `runAsync` here
+  // we make sure that asynchronous non-timer events are executed before any
+  // Timer events.
+  runAsync(() { });
+
+  // Test that errors are caught by nested `catchErrors`. Also uses `runAsync`
+  // in the body of a Timer.
+  catchErrors(() {
+    events.add("catch error entry");
+    catchErrors(() {
+      events.add("catch error entry2");
+      Timer.run(() { throw "timer error"; });
+      new Timer(const Duration(milliseconds: 50),
+                () {
+                     runAsync(() { throw "runAsync"; });
+                     throw "delayed error";
+                   });
+    }).listen((x) { events.add(x); })
+      .asFuture()
+      .then((_) => events.add("inner done"))
+      .then((_) { throw "inner done throw"; });
+    events.add("after inner");
+    Timer.run(() { throw "timer outer"; });
+    throw "inner throw";
+  }).listen((x) {
+      events.add(x);
+    },
+    onDone: () {
+      Expect.listEquals([
+                         "catch error entry",
+                         "catch error entry2",
+                         "after inner",
+                         "main exit",
+                         "inner throw",
+                         "timer error",
+                         "timer outer",
+                         "delayed error",
+                         "runAsync",
+                         "inner done",
+                         "inner done throw"
+                         ],
+                         events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/catch_errors14_test.dart b/tests/lib/async/catch_errors14_test.dart
new file mode 100644
index 0000000..ebf34a1
--- /dev/null
+++ b/tests/lib/async/catch_errors14_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test that periodic Timers are handled correctly by `catchErrors`.
+  catchErrors(() {
+    int counter = 0;
+    new Timer.periodic(const Duration(milliseconds: 50), (timer) {
+      if (counter++ == 5) timer.cancel();
+      throw "error $counter";
+    });
+  }).listen((x) {
+      events.add(x);
+    },
+    onDone: () {
+      Expect.listEquals([
+                         "main exit",
+                         "error 1",
+                         "error 2",
+                         "error 3",
+                         "error 4",
+                         "error 5",
+                         "error 6",
+                         ],
+                         events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/catch_errors15_test.dart b/tests/lib/async/catch_errors15_test.dart
new file mode 100644
index 0000000..2cea6fe
--- /dev/null
+++ b/tests/lib/async/catch_errors15_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test that the outer `catchErrors` waits for the nested `catchErrors` stream
+  // to be done.
+  catchErrors(() {
+    events.add("catch error entry");
+    catchErrors(() {
+      events.add("catch error entry2");
+      new Future.error("future error");
+      new Future.error("future error2");
+      new Future.value(499).then((x) => throw x);
+      new Future.delayed(const Duration(milliseconds: 50), () {
+        throw "delayed error";
+      });
+      throw "catch error";
+    }).listen((x) { events.add("i $x"); },
+              onDone: () => events.add("inner done"));
+    events.add("after inner");
+    throw "inner throw";
+  }).listen((x) {
+      events.add("o $x");
+    },
+    onDone: () {
+      Expect.listEquals(["catch error entry",
+                         "catch error entry2",
+                         "after inner",
+                         "main exit",
+                         "i catch error",
+                         "o inner throw",
+                         "i future error",
+                         "i future error2",
+                         "i 499",
+                         "i delayed error",
+                         "inner done",
+                         ],
+                         events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/catch_errors16_test.dart b/tests/lib/async/catch_errors16_test.dart
new file mode 100644
index 0000000..cb3621d
--- /dev/null
+++ b/tests/lib/async/catch_errors16_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 "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  StreamController controller = new StreamController();
+  Stream stream = controller.stream;
+  // Test that the subscription of a stream is what counts. The error (2) runs
+  // through the map-stream which goes through the nested `catchError` but
+  // the nested `catchError` won't see the error.
+  catchErrors(() {
+    stream = stream.map((x) => x + 100);
+  }).listen((x) { events.add(x); });
+  stream
+    .transform(new StreamTransformer(
+        handleError: (e, sink) => sink.add("error $e")))
+    .listen((x) { events.add("stream $x"); },
+            onDone: () {
+              Expect.listEquals(["stream 101",
+                                "stream error 2",
+                                ],
+                                events);
+              port.close();
+            });
+  controller.add(1);
+  controller.addError(2);
+  controller.close();
+}
diff --git a/tests/lib/async/catch_errors17_test.dart b/tests/lib/async/catch_errors17_test.dart
new file mode 100644
index 0000000..bf19b09
--- /dev/null
+++ b/tests/lib/async/catch_errors17_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  StreamController controller;
+  // Test that errors do not cross zone boundaries.
+  catchErrors(() {
+    catchErrors(() {
+      controller = new StreamController();
+      controller.stream
+        .map((x) {
+          events.add("map $x");
+          return x + 100;
+        })
+        .transform(new StreamTransformer(
+            handleError: (e, sink) => sink.add("error $e")))
+        .listen((x) { events.add("stream $x"); });
+    }).listen((x) { events.add(x); })
+      .asFuture().then((_) { events.add("inner done"); });
+    controller.add(1);
+    // Errors are not allowed to traverse boundaries. This error should be
+    // caught by the outer catchErrors.
+    controller.addError(2);
+    controller.close();
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () {
+              Expect.listEquals(["map 1",
+                                 "stream 101",
+                                 "outer: 2",
+                                 "inner done",
+                                ],
+                                events);
+              port.close();
+            });
+}
diff --git a/tests/lib/async/catch_errors18_test.dart b/tests/lib/async/catch_errors18_test.dart
new file mode 100644
index 0000000..33e60ab
--- /dev/null
+++ b/tests/lib/async/catch_errors18_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  Stream stream = new Stream.periodic(const Duration(milliseconds: 20),
+                                      (x) => x);
+  // Test that errors of periodic streams are caught.
+  catchErrors(() {
+    var subscription;
+    subscription = stream.listen((x) {
+      if (x == 5) {
+        events.add("cancel");
+        subscription.cancel();
+        return;
+      }
+      events.add(x);
+    });
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () {
+              Expect.listEquals([0, 1, 2, 3, 4, "cancel"], events);
+              port.close();
+            });
+}
diff --git a/tests/lib/async/catch_errors19_test.dart b/tests/lib/async/catch_errors19_test.dart
new file mode 100644
index 0000000..dec100a
--- /dev/null
+++ b/tests/lib/async/catch_errors19_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  Stream stream = new Stream.periodic(const Duration(milliseconds: 20),
+                                      (x) => x);
+  // Test that asynchronous callbacks in the done-handler of streams (here
+  // the `catchErrors`-stream) keep a zone alive.
+  catchErrors(() {
+    var subscription;
+    subscription = stream.take(5).listen((x) {
+      events.add(x);
+    }, onDone: () {
+      new Future.delayed(const Duration(milliseconds: 30), () {
+        events.add(499);
+      });
+    });
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () {
+              Expect.listEquals([0, 1, 2, 3, 4, 499], events);
+              port.close();
+            });
+}
diff --git a/tests/lib/async/catch_errors20_test.dart b/tests/lib/async/catch_errors20_test.dart
new file mode 100644
index 0000000..b0f0673
--- /dev/null
+++ b/tests/lib/async/catch_errors20_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test that nested stream (from `catchErrors`) that is delayed by a future
+  // is waited for.
+  catchErrors(() {
+    catchErrors(() {
+      new Future.error(499);
+      new Future.delayed(const Duration(milliseconds: 20), () {
+        events.add(42);
+      });
+    }).listen(events.add,
+              onDone: () { events.add("done"); });
+    throw "foo";
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () {
+              Expect.listEquals(["outer: foo",
+                                 499,
+                                 42,
+                                 "done",
+                                ],
+                                events);
+              port.close();
+            });
+}
diff --git a/tests/lib/async/catch_errors21_test.dart b/tests/lib/async/catch_errors21_test.dart
new file mode 100644
index 0000000..28dec7f
--- /dev/null
+++ b/tests/lib/async/catch_errors21_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 "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  var controller = new StreamController();
+  // Test that stream errors, as a result of bad user-code (`map`) are correctly
+  // caught by `catchErrors`. Note that the values are added outside both
+  // `catchErrors`, but since the `listen` happens in the most nested
+  // `catchErrors` it is caught there.
+  catchErrors(() {
+    catchErrors(() {
+      controller.stream.map((x) { throw x; }).listen((x) {
+        // Should not happen.
+        events.add("bad: $x");
+      });
+    }).listen((x) { events.add("caught: $x"); },
+              onDone: () { events.add("done"); });
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () {
+              Expect.listEquals(["caught: 1",
+                                 "caught: 2",
+                                 "caught: 3",
+                                 "caught: 4",
+                                 "done",
+                                ],
+                                events);
+              port.close();
+            });
+  [1, 2, 3, 4].forEach(controller.add);
+  controller.close();
+}
diff --git a/tests/lib/async/catch_errors22_test.dart b/tests/lib/async/catch_errors22_test.dart
new file mode 100644
index 0000000..c47b3a3
--- /dev/null
+++ b/tests/lib/async/catch_errors22_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 "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  bool onDoneWasCalled = false;
+  var controller = new StreamController();
+  // Test that streams that are never closed keep the `catchError` alive.
+  catchErrors(() {
+    catchErrors(() {
+      controller.stream.map((x) { throw x; }).listen((x) {
+        // Should not happen.
+        events.add("bad: $x");
+      });
+    }).listen((x) { events.add("caught: $x"); },
+              onDone: () { events.add("done"); });
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () { onDoneWasCalled = true; });
+
+  [1, 2, 3, 4].forEach(controller.add);
+
+  new Timer(const Duration(milliseconds: 20), () {
+    Expect.isFalse(onDoneWasCalled);
+    Expect.listEquals(["caught: 1",
+                       "caught: 2",
+                       "caught: 3",
+                       "caught: 4",
+                      ],
+                      events);
+    port.close();
+  });
+}
diff --git a/tests/lib/async/catch_errors23_test.dart b/tests/lib/async/catch_errors23_test.dart
new file mode 100644
index 0000000..2d2ff72
--- /dev/null
+++ b/tests/lib/async/catch_errors23_test.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  StreamController controller;
+  Stream stream;
+  // Test that errors are not traversing zone boundaries.
+  // Note that the first listener of `asBroadcastStream` determines in which
+  // zone the subscription lives.
+  catchErrors(() {
+    catchErrors(() {
+      controller = new StreamController();
+      stream = controller.stream
+        .map((x) {
+          events.add("map $x");
+          return x + 100;
+        })
+        .transform(new StreamTransformer(
+            handleError: (e, sink) => sink.add("error $e")))
+        .asBroadcastStream();
+      stream.listen((x) { events.add("stream $x"); });
+    }).listen((x) { events.add(x); })
+      .asFuture().then((_) { events.add("inner done"); });
+    stream.listen((x) { events.add("stream2 $x"); });
+    controller.add(1);
+    // Errors are not allowed to traverse boundaries. This error should be
+    // caught by the outer catchErrors.
+    controller.addError(2);
+    controller.close();
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () {
+              Expect.listEquals(["map 1",
+                                "stream 101",
+                                "stream2 101",
+                                "outer: 2",
+                                "inner done",
+                                ],
+                                events);
+              port.close();
+            });
+}
diff --git a/tests/lib/async/catch_errors24_test.dart b/tests/lib/async/catch_errors24_test.dart
new file mode 100644
index 0000000..4a5508f
--- /dev/null
+++ b/tests/lib/async/catch_errors24_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  StreamController controller;
+  Stream stream;
+  // Test that the first listen on a `asBroadcastStream` determines the
+  // zone the subscription lives in. In this case the outer listen happens first
+  // and the error reaches `handleError`.
+  catchErrors(() {
+    catchErrors(() {
+      controller = new StreamController();
+      stream = controller.stream
+        .map((x) {
+          events.add("map $x");
+          return x + 100;
+        })
+        .transform(new StreamTransformer(
+            handleError: (e, sink) => sink.add("error $e")))
+        .asBroadcastStream();
+      runAsync(() { stream.listen((x) { events.add("stream $x"); }); });
+    }).listen((x) { events.add(x); })
+      .asFuture().then((_) { events.add("inner done"); });
+    stream.listen((x) { events.add("stream2 $x"); });
+    runAsync(() {
+      controller.add(1);
+      // Errors are not allowed to traverse boundaries, but in this case the
+      // first listener of the broadcast stream is in the same error-zone. So
+      // this should work.
+      controller.addError(2);
+      controller.close();
+    });
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () {
+              Expect.listEquals(["map 1",
+                                 "stream2 101",
+                                 "stream 101",
+                                 "stream2 error 2",
+                                 "stream error 2",
+                                 "inner done",
+                                ],
+                                events);
+              port.close();
+            });
+}
diff --git a/tests/lib/async/catch_errors25_test.dart b/tests/lib/async/catch_errors25_test.dart
new file mode 100644
index 0000000..162a4a3
--- /dev/null
+++ b/tests/lib/async/catch_errors25_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  StreamController controller;
+  // Test multiple subscribers of an asBroadcastStream inside the same
+  // `catchErrors`.
+  catchErrors(() {
+    var stream = new Stream.fromIterable([1, 2]).asBroadcastStream();
+    stream.listen(events.add);
+    stream.listen(events.add);
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () {
+              Expect.listEquals([1, 1, 2, 2], events);
+              port.close();
+            });
+}
diff --git a/tests/lib/async/catch_errors26_test.dart b/tests/lib/async/catch_errors26_test.dart
new file mode 100644
index 0000000..d14e1dd
--- /dev/null
+++ b/tests/lib/async/catch_errors26_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  StreamController controller;
+  Stream stream;
+  // Test `StreamController.broadcast` streams. Note that the nested listener
+  // doesn't see the error, but the outer one does.
+  catchErrors(() {
+    catchErrors(() {
+      controller = new StreamController.broadcast();
+      controller.stream
+        .map((x) {
+          events.add("map $x");
+          return x + 100;
+        })
+        .transform(new StreamTransformer(
+            handleError: (e, sink) => sink.add("error $e")))
+        .listen((x) { events.add("stream $x"); });
+    }).listen((x) { events.add(x); })
+      .asFuture().then((_) { events.add("inner done"); });
+    controller.stream.listen((x) { events.add("stream2 $x"); },
+                             onError: (x) { events.add("stream2 error $x"); });
+    controller.add(1);
+    // Errors are not allowed to traverse boundaries, but in this case the
+    // first listener of the broadcast stream is in the same error-zone. So
+    // this should work.
+    controller.addError(2);
+    controller.close();
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () {
+              Expect.listEquals(["map 1",
+                                 "stream 101",
+                                 "stream2 1",
+                                 "stream2 error 2",
+                                 "outer: 2",
+                                 "inner done",
+                                ],
+                                events);
+              port.close();
+            });
+}
diff --git a/tests/lib/async/catch_errors27_test.dart b/tests/lib/async/catch_errors27_test.dart
new file mode 100644
index 0000000..a73c51d
--- /dev/null
+++ b/tests/lib/async/catch_errors27_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  StreamController controller;
+  Stream stream;
+  // Test that the first listen on a `asBroadcastStream` determines the
+  // zone the subscription lives in. The inner listen happens first, and
+  // the outer listener must not see the error since it would cross a
+  // zone boundary. It is therefore given to the inner `catchErrors`.
+  catchErrors(() {
+    catchErrors(() {
+      controller = new StreamController();
+      stream = controller.stream
+        .map((x) {
+          events.add("map $x");
+          return x + 100;
+        })
+        .asBroadcastStream();
+      stream
+        .transform(new StreamTransformer(
+            handleError: (e, sink) => sink.add("error $e")))
+        .listen((x) { events.add("stream $x"); });
+      runAsync(() {
+        controller.add(1);
+        // Errors are not allowed to traverse boundaries, but in this case the
+        // first listener of the broadcast stream is in the same error-zone. So
+        // this should work.
+        controller.addError(2);
+        controller.close();
+      });
+    }).listen((x) { events.add(x); })
+      .asFuture().then((_) { events.add("inner done"); });
+    stream.listen((x) { events.add("stream2 $x"); });
+  }).listen((x) { events.add("outer: $x"); },
+            onDone: () {
+              Expect.listEquals(["map 1",
+                                 "stream 101",
+                                 "stream2 101",
+                                 "stream error 2",
+                                 2, // Caught by the inner `catchErrors`.
+                                 "inner done",
+                                ],
+                                events);
+              port.close();
+            });
+}
diff --git a/tests/lib/async/catch_errors28_test.dart b/tests/lib/async/catch_errors28_test.dart
new file mode 100644
index 0000000..09a208f
--- /dev/null
+++ b/tests/lib/async/catch_errors28_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test that periodic Timers are handled correctly by `catchErrors`.
+  catchErrors(() {
+    int counter = 0;
+    new Timer.periodic(const Duration(milliseconds: 50), (timer) {
+      if (counter == 5) timer.cancel();
+      counter++;
+      events.add(counter);
+    });
+  }).listen((x) {
+      events.add(x);
+    },
+    onDone: () {
+      Expect.listEquals([
+                         "main exit",
+                         1, 2, 3, 4, 5, 6,
+                         ],
+                         events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/catch_errors2_test.dart b/tests/lib/async/catch_errors2_test.dart
new file mode 100644
index 0000000..18fefaf
--- /dev/null
+++ b/tests/lib/async/catch_errors2_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  bool futureWasExecuted = false;
+  // Make sure that `catchErrors` only closes the error stream when the inner
+  // futures are done.
+  catchErrors(() {
+    new Future(() {
+      futureWasExecuted = true;
+    });
+    return 'allDone';
+  }).listen((x) {
+      Expect.fail("Unexpected callback");
+    },
+    onDone: () {
+      Expect.isTrue(futureWasExecuted);
+      port.close();
+    });
+}
diff --git a/tests/lib/async/catch_errors3_test.dart b/tests/lib/async/catch_errors3_test.dart
new file mode 100644
index 0000000..2edcfb2
--- /dev/null
+++ b/tests/lib/async/catch_errors3_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 "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  bool futureWasExecuted = false;
+  bool future2WasExecuted = false;
+
+  // Make sure `catchErrors` doesn't close its error stream before all
+  // asynchronous operations are done.
+  catchErrors(() {
+    new Future(() => 499).then((x) {
+      futureWasExecuted = true;
+    });
+    runAsync(() {
+      new Future(() => 42).then((x) {
+        future2WasExecuted = true;
+      });
+    });
+    return 'allDone';
+  }).listen((x) {
+      Expect.fail("Unexpected callback");
+    },
+    onDone: () {
+      Expect.isTrue(futureWasExecuted);
+      Expect.isTrue(future2WasExecuted);
+      port.close();
+    });
+}
diff --git a/tests/lib/async/catch_errors4_test.dart b/tests/lib/async/catch_errors4_test.dart
new file mode 100644
index 0000000..5c1900b
--- /dev/null
+++ b/tests/lib/async/catch_errors4_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 "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test that synchronous errors inside a `catchErrors` are caught.
+  catchErrors(() {
+    events.add("catch error entry");
+    throw "catch error";
+  }).listen((x) {
+      events.add(x);
+    },
+    onDone: () {
+      Expect.listEquals(["catch error entry",
+                         "main exit",
+                         "catch error",
+                         ],
+                         events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/catch_errors5_test.dart b/tests/lib/async/catch_errors5_test.dart
new file mode 100644
index 0000000..1d98f11
--- /dev/null
+++ b/tests/lib/async/catch_errors5_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test that synchronous *and* asynchronous errors are caught by
+  // `catchErrors`.
+  catchErrors(() {
+    events.add("catch error entry");
+    new Future.error("future error");
+    throw "catch error";
+  }).listen((x) {
+      events.add(x);
+    },
+    onDone: () {
+      Expect.listEquals(["catch error entry",
+                         "main exit",
+                         "catch error",
+                         "future error",
+                         ],
+                         events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/catch_errors6_test.dart b/tests/lib/async/catch_errors6_test.dart
new file mode 100644
index 0000000..f9b5261
--- /dev/null
+++ b/tests/lib/async/catch_errors6_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 "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var completer = new Completer();
+  var errorHandlerOrDoneHasBeenExecuted = false;
+  // Test that `catchErrors` doesn't shut down if a future is never completed.
+  catchErrors(() {
+    completer.future.then((x) { Expect.fail("should not be executed"); });
+  }).listen((x) {
+      errorHandlerOrDoneHasBeenExecuted = true;
+      Expect.fail("should not be executed (listen)");
+    },
+    onDone: () {
+      errorHandlerOrDoneHasBeenExecuted = true;
+      Expect.fail("should not be executed (onDone)");
+    });
+  Timer.run(() {
+    Expect.isFalse(errorHandlerOrDoneHasBeenExecuted);
+    port.close();
+  });
+}
diff --git a/tests/lib/async/catch_errors7_test.dart b/tests/lib/async/catch_errors7_test.dart
new file mode 100644
index 0000000..1d6310d
--- /dev/null
+++ b/tests/lib/async/catch_errors7_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test that asynchronous errors are caught.
+  catchErrors(() {
+    events.add("catch error entry");
+    new Future.error("future error");
+    new Future.error("future error2");
+    new Future.value(499).then((x) => throw x);
+    throw "catch error";
+  }).listen((x) {
+      events.add(x);
+    },
+    onDone: () {
+      Expect.listEquals(
+          ["catch error entry",
+           "main exit",
+           "catch error",
+           "future error",
+           "future error2",
+           499,
+          ],
+          events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/catch_errors8_test.dart b/tests/lib/async/catch_errors8_test.dart
new file mode 100644
index 0000000..f4ce992
--- /dev/null
+++ b/tests/lib/async/catch_errors8_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test nested `catchErrors`.
+  // The nested `catchErrors` throws all kinds of different errors (synchronous
+  // and asynchronous). The body of the outer `catchErrors` furthermore has a
+  // synchronous `throw`.
+  catchErrors(() {
+    events.add("catch error entry");
+    catchErrors(() {
+      events.add("catch error entry2");
+      new Future.error("future error");
+      new Future.error("future error2");
+      new Future.value(499).then((x) => throw x);
+      new Future.delayed(const Duration(milliseconds: 50), () {
+        throw "delayed error";
+      });
+      throw "catch error";
+    }).listen((x) { events.add(x); })
+      .asFuture()
+      .then((_) => events.add("inner done"))
+      .then((_) { throw "inner done throw"; });
+    events.add("after inner");
+    throw "inner throw";
+  }).listen((x) {
+      events.add(x);
+    },
+    onDone: () {
+      Expect.listEquals(["catch error entry",
+                         "catch error entry2",
+                         "after inner",
+                         "main exit",
+                         "catch error",
+                         "inner throw",
+                         "future error",
+                         "future error2",
+                         499,
+                         "delayed error",
+                         "inner done",
+                         "inner done throw"
+                         ],
+                         events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/catch_errors9_test.dart b/tests/lib/async/catch_errors9_test.dart
new file mode 100644
index 0000000..5912bf1
--- /dev/null
+++ b/tests/lib/async/catch_errors9_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  bool futureWasExecuted = false;
+  // Test that `catchErrors` waits for `Timer.run` before closing its error
+  // stream.
+  catchErrors(() {
+    Timer.run(() {
+      futureWasExecuted = true;
+    });
+    return 'allDone';
+  }).listen((x) {
+      Expect.fail("Unexpected callback");
+    },
+    onDone: () {
+      Expect.isTrue(futureWasExecuted);
+      port.close();
+    });
+}
diff --git a/tests/lib/async/catch_errors_test.dart b/tests/lib/async/catch_errors_test.dart
new file mode 100644
index 0000000..c981966
--- /dev/null
+++ b/tests/lib/async/catch_errors_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  // Make sure `catchErrors` shuts down the error stream when the synchronous
+  // operation is done and there isn't any asynchronous pending callback.
+  catchErrors(() {
+    return 'allDone';
+  }).listen((x) {
+      Expect.fail("Unexpected callback");
+    },
+    onDone: () {
+      port.close();
+    });
+}
diff --git a/tests/lib/async/run_zoned1_test.dart b/tests/lib/async/run_zoned1_test.dart
new file mode 100644
index 0000000..71af234
--- /dev/null
+++ b/tests/lib/async/run_zoned1_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+
+main() {
+  // Make sure `runZoned` returns the result of a synchronous call.
+  Expect.equals(499, runZonedExperimental(() => 499));
+}
diff --git a/tests/lib/async/run_zoned2_test.dart b/tests/lib/async/run_zoned2_test.dart
new file mode 100644
index 0000000..39e28a0
--- /dev/null
+++ b/tests/lib/async/run_zoned2_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.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  // Ensure that `runZoned` is done when a synchronous call finishes.
+  runZonedExperimental(() => 499,
+                       onDone: port.close);
+}
diff --git a/tests/lib/async/run_zoned3_test.dart b/tests/lib/async/run_zoned3_test.dart
new file mode 100644
index 0000000..f880208
--- /dev/null
+++ b/tests/lib/async/run_zoned3_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  // Ensure that `runZoned` is done when a synchronous call throws.
+  bool sawException = false;
+  try {
+    runZonedExperimental(() { throw 0; },
+                         onDone: () {
+                           // onDone is executed synchronously.
+                           Expect.isFalse(sawException);
+                           port.close();
+                         });
+  } catch (e) {
+    sawException = true;
+  }
+  Expect.isTrue(sawException);
+}
diff --git a/tests/lib/async/run_zoned4_test.dart b/tests/lib/async/run_zoned4_test.dart
new file mode 100644
index 0000000..ac96b65
--- /dev/null
+++ b/tests/lib/async/run_zoned4_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+
+main() {
+  // Make sure `runZoned` returns the result of a synchronous call when an
+  // error handler is defined.
+  Expect.equals(499,
+                runZonedExperimental(() => 499,
+                                     onError: (e) { throw "Unexpected"; }));
+}
diff --git a/tests/lib/async/run_zoned5_test.dart b/tests/lib/async/run_zoned5_test.dart
new file mode 100644
index 0000000..bfe7c8b
--- /dev/null
+++ b/tests/lib/async/run_zoned5_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  // Ensure that `runZoned`'s onError handles synchronous errors.
+  runZonedExperimental(() { throw 0; },
+                       onError: (e) {
+                         Expect.equals(0, e);
+                         port.close();
+                       });
+}
diff --git a/tests/lib/async/run_zoned6_test.dart b/tests/lib/async/run_zoned6_test.dart
new file mode 100644
index 0000000..2de6ca9
--- /dev/null
+++ b/tests/lib/async/run_zoned6_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  // Ensure that `runZoned`'s onError handles synchronous errors but delegates
+  // to the top-level when the handler returns false.
+  try {
+    runZonedExperimental(() { throw 0; },
+                        onError: (e) {
+                          Expect.equals(0, e);
+                          port.close();
+                          throw e;  /// 01: runtime error
+                        });
+  } catch (e) {
+    // We should never see an error here.
+    if (true)  /// 01: continued
+      rethrow;
+  }
+}
diff --git a/tests/lib/async/run_zoned7_test.dart b/tests/lib/async/run_zoned7_test.dart
new file mode 100644
index 0000000..3bd3dbb
--- /dev/null
+++ b/tests/lib/async/run_zoned7_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test runZoned with periodic Timers.
+  runZonedExperimental(() {
+    int counter = 0;
+    new Timer.periodic(const Duration(milliseconds: 50), (timer) {
+      if (counter == 5) timer.cancel();
+      counter++;
+      events.add(counter);
+    });
+  }, onDone: () {
+      Expect.listEquals([
+                         "main exit",
+                         1, 2, 3, 4, 5, 6,
+                         ],
+                         events);
+      port.close();
+    });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/run_zoned8_test.dart b/tests/lib/async/run_zoned8_test.dart
new file mode 100644
index 0000000..c8ce77d
--- /dev/null
+++ b/tests/lib/async/run_zoned8_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+import 'catch_errors.dart';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  var events = [];
+  // Test runZoned with periodic Timers.
+  runZonedExperimental(() {
+    int counter = 0;
+    new Timer.periodic(const Duration(milliseconds: 50), (timer) {
+      if (counter == 1) timer.cancel();
+      counter++;
+      events.add(counter);
+      throw counter;
+    });
+  }, onError: (e) {
+       events.add("error: $e");
+     },
+     onDone: () {
+         Expect.listEquals([
+                           "main exit",
+                           1, "error: 1", 2, "error: 2",
+                           ],
+                           events);
+         port.close();
+       });
+  events.add("main exit");
+}
diff --git a/tests/lib/async/run_zoned9_test.dart b/tests/lib/async/run_zoned9_test.dart
new file mode 100644
index 0000000..aeaee5d
--- /dev/null
+++ b/tests/lib/async/run_zoned9_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:async';
+import 'dart:isolate';
+
+main() {
+  // We keep a ReceivePort open until all tests are done. This way the VM will
+  // hang if the callbacks are not invoked and the test will time out.
+  var port = new ReceivePort();
+  // Ensure that `runZoned`'s onError handles synchronous errors but delegates
+  // to the next runZonedExperimental when the handler returns false.
+  bool sawInnerHandler = false;
+  try {
+    runZonedExperimental(() {
+      runZonedExperimental(() { throw 0; },
+                          onError: (e) {
+                            Expect.equals(0, e);
+                            sawInnerHandler = true;
+                            throw e;
+                          });
+    }, onError: (e) {
+      Expect.equals(0, e);
+      Expect.isTrue(sawInnerHandler);
+      port.close();
+      throw e;  /// 01: runtime error
+    });
+  } catch (e) {
+    // We should never see an error here.
+    if (true)  /// 01: continued
+      rethrow;
+  }
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index ed775e2..e26f707 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -20,19 +20,20 @@
 typed_data/byte_data_test: Fail, OK # d8/ie9 doesn't support DataView
 
 [ $compiler == dart2js && $minified ]
+mirrors/disable_tree_shaking_test: Fail # Issue 6490
 mirrors/metadata_test: Fail
 mirrors/mirrors_resolve_fields_test: Fail # Issue 6490
-mirrors/reflectively_instantiate_uninstantiated_class_test: Fail # Issue 6490
-mirrors/disable_tree_shaking_test: Fail # Issue 6490
 mirrors/reflect_model_test: Fail # Issue 6490
+mirrors/reflectively_instantiate_uninstantiated_class_test: Fail # Issue 6490
+mirrors/to_string_test: Fail # Issue 6490
 
 [ $csp ]
-mirrors/library_metadata_test: Fail # Issue 10906
-mirrors/metadata_test: Fail # Issue 10906
+mirrors/metadata_test: Fail # Issue 6490
+mirrors/reflect_model_test: Fail # Issue 6490
 mirrors/reflect_runtime_type_test: Fail # Issue 6490
 mirrors/reflect_uninstantiated_class_test: Fail # Issue 6490
 mirrors/superclass_test: Fail # Issue 6490
-mirrors/reflect_model_test: Fail # Issue 6490
+mirrors/to_string_test: Fail # Issue 6490
 
 [ $compiler == dart2js && $checked ]
 async/stream_event_transform_test: Fail # Issue 7733.
@@ -58,6 +59,8 @@
 async/stream_periodic3_test: Fail # Timer interface not supported; dartbug.com/7728.
 async/stream_periodic4_test: Fail # Timer interface not supported; dartbug.com/7728.
 async/stream_periodic5_test: Fail # Timer interface not supported; dartbug.com/7728.
+async/run_zoned7_test: Fail # Timer interface not supported: dartbug.com/7728.
+async/catch_errors22_test: Fail # Timer interface not supported: dartbug.com/7728.
 
 [ $compiler == dart2js && $browser ]
 async/timer_not_available_test: Fail, OK # only meant to test when there is no way to
@@ -70,6 +73,7 @@
 async/run_async6_test: Fail             # Issue 10957 - may be related to issue 10910
 mirrors/reflect_model_test: Fail # http://dartbug.com/11219
 mirrors/disable_tree_shaking_test: Fail
+mirrors/to_string_test: Fail
 
 [ $compiler == dart2dart && $minified ]
 json/json_test: Fail                           # Issue 10961
diff --git a/tests/lib/mirrors/library_metadata_test.dart b/tests/lib/mirrors/library_metadata_test.dart
index 3ae8b11..259e398 100644
--- a/tests/lib/mirrors/library_metadata_test.dart
+++ b/tests/lib/mirrors/library_metadata_test.dart
@@ -7,39 +7,10 @@
 
 import 'dart:mirrors';
 
-const string = 'a metadata string';
-
-const symbol = const Symbol('symbol');
-
-const hest = 'hest';
-
-checkMetadata(DeclarationMirror mirror, List expectedMetadata) {
-  List metadata = mirror.metadata.map((m) => m.reflectee).toList();
-  if (metadata == null) {
-    throw 'Null metadata on $mirror';
-  }
-  int expectedLength = expectedMetadata.length;
-  int actualLength = metadata.length;
-  if (expectedLength != actualLength) {
-    throw 'Expected length = $expectedLength, but got length = $actualLength.';
-  }
-  for (int i = 0; i < expectedLength; i++) {
-    if (metadata[i] != expectedMetadata[i]) {
-      throw '${metadata[i]} is not "${expectedMetadata[i]}"'
-          ' in $mirror at index $i';
-    }
-  }
-  print(metadata);
-}
+import 'metadata_test.dart';
 
 main() {
-  if (MirrorSystem.getName(symbol) != 'symbol') {
-    // This happened in dart2js due to how early library metadata is
-    // computed.
-    throw 'Bad constant: $symbol';
-  }
-
   MirrorSystem mirrors = currentMirrorSystem();
   checkMetadata(mirrors.findLibrary(const Symbol('test.library_metadata_test')).first,
-                [string, symbol]); 
+                [string, symbol]);
 }
diff --git a/tests/lib/mirrors/to_string_test.dart b/tests/lib/mirrors/to_string_test.dart
new file mode 100644
index 0000000..ac58b2a
--- /dev/null
+++ b/tests/lib/mirrors/to_string_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.
+
+library test.to_string_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+expect(expected, actual) => Expect.stringEquals(expected, '$actual');
+
+class Foo {
+  var field;
+  method() {}
+}
+
+main() {
+  var mirrors = currentMirrorSystem();
+  expect("TypeMirror on 'dynamic'", mirrors.dynamicType);
+  expect("TypeMirror on 'void'", mirrors.voidType);
+  expect("LibraryMirror on 'test.to_string_test'",
+         mirrors.findLibrary(const Symbol('test.to_string_test')).single);
+  expect("InstanceMirror on 1", reflect(1));
+  expect("ClassMirror on 'Foo'", reflectClass(Foo));
+  expect("VariableMirror on 'field'",
+         reflectClass(Foo).variables.values.single);
+  expect("MethodMirror on 'method'", reflectClass(Foo).methods.values.single);
+  String s = reflect(main).toString();
+  Expect.isTrue(s.startsWith("ClosureMirror on '"), s);
+}
diff --git a/tests/standalone/io/directory_list_pause_test.dart b/tests/standalone/io/directory_list_pause_test.dart
new file mode 100644
index 0000000..178f59f
--- /dev/null
+++ b/tests/standalone/io/directory_list_pause_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "dart:async";
+import "dart:io";
+import "dart:isolate";
+
+
+void testPauseList() {
+  var keepAlive = new ReceivePort();
+  new Directory("").createTemp().then((d) {
+    // Linux reads 2K at a time, so be sure to be >>.
+    int total = 4 * 1024 + 1;
+    for (int i = 0; i < total; i++) {
+      new File("${d.path}/$i").createSync();
+    }
+    bool first = true;
+    var subscription;
+    int count = 0;
+    subscription = d.list().listen((file) {
+      if (first) {
+        first = false;
+        subscription.pause();
+        Timer.run(() {
+          for (int i = 0; i < total; i++) {
+            new File("${d.path}/$i").deleteSync();
+          }
+          subscription.resume();
+        });
+      }
+      count++;
+    }, onDone: () {
+      Expect.notEquals(total, count);
+      keepAlive.close();
+      d.delete().then((ignore) => keepAlive.close());
+    });
+  });
+}
+
+void main() {
+  testPauseList();
+}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 9f81106..e08da8e 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -50,11 +50,6 @@
 io/directory_non_ascii_test: Pass, Fail
 io/process_non_ascii_test: Pass, Fail
 
-[ $runtime == vm && $mode == debug && $checked ]
-io/http_client_request_test: Pass, Crash  # Issue 11278
-io/http_server_response_test: Pass, Crash  # Issue 11278
-io/http_content_length_test: Pass, Crash  # Issue 11278
-
 [ $compiler == none && $runtime == drt ]
 typed_data_isolate_test: Skip # This test uses dart:io
 io/*: Skip # Don't run tests using dart:io in the browser
@@ -116,6 +111,7 @@
 
 
 [ $compiler == dart2js ]
+io/test_runner_test: Fail # Import Uri does not work
 number_identity_test: Skip # Bigints and int/double diff. not supported.
 typed_data_test: Skip # dart:typed_data support needed.
 bytedata_test: Skip # dart:typed_data support needed.
@@ -134,12 +130,12 @@
 debugger/*: Skip # Do not run standalone vm debugger tests with dart2js.
 left_shift_bit_and_op_test: Skip # Integers exceed dart2js precision.
 pow_test: Skip # Precision > 53 bits.
-io/test_runner_test: Fail # Library dart:uri removed.
 io/skipping_dart2js_compilations_test: Skip # Library dart:uri removed.
 http_launch_test: Skip
 53bit_overflow_test: Skip
 53bit_overflow_literal_test: Skip
 
+
 [ $compiler == dart2js && $jscl ]
 assert_test: Fail, OK # Assumes unspecified fields on the AssertionError.
 byte_array_test: Fail, OK # ByteArray
@@ -166,11 +162,12 @@
 coverage_test: Crash # Issue: 11207
 debugger/basic_debugger_test: Crash # Issue: 11207
 debugger/closure_debugger_test: Crash # Issue: 11207
-http_launch_test: Crash # Issue: 11207
+http_launch_test: Fail, Crash # Issue: 11207
 left_shift_bit_and_op_test: Fail # Issue: 11207
 package/package_isolate_test: Pass, Crash # Issue: 11207
 out_of_memory_test: Pass, Crash # Issue: 11207 (Pass on Mac)
 typed_data_test: Timeout, Crash # Issue: 11207
+typed_data_isolate_test: Pass, Crash # Issue: 11207
 io/*: Skip # Skip IO tests for now as they are still quite flaky.
 
 [ $arch == mips ]
diff --git a/tools/VERSION b/tools/VERSION
index 28542e6..9715532 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 5
-BUILD 19
+BUILD 20
 PATCH 0
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 59e9795..1ae2fd1 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -24,6 +24,8 @@
 # ....include/
 # ......dart_api.h
 # ......dart_debugger_api.h
+# ......dart_mirrors_api.h
+# ......dart_native_api.h
 # ....lib/
 # ......_internal/
 # ......async/
@@ -174,6 +176,10 @@
            join(INCLUDE, 'dart_api.h'))
   copyfile(join(HOME, 'runtime', 'include', 'dart_debugger_api.h'),
            join(INCLUDE, 'dart_debugger_api.h'))
+  copyfile(join(HOME, 'runtime', 'include', 'dart_mirrors_api.h'),
+           join(INCLUDE, 'dart_mirrors_api.h'))
+  copyfile(join(HOME, 'runtime', 'include', 'dart_native_api.h'),
+           join(INCLUDE, 'dart_native_api.h'))
 
   #
   # Create and populate sdk/lib.
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index ba2445a..eec4dc5 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -90,7 +90,9 @@
       },
 
       'Dart_Release': {
-        'cflags': [ '-O3', ],
+        'cflags': [ '-O3',
+                    '-fno-omit-frame-pointer',
+        ],
       },
     },
   },
diff --git a/tools/test.dart b/tools/test.dart
index b1c587a..c2da69a 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -26,6 +26,7 @@
 
 import "dart:async";
 import "dart:io";
+import "dart:math" as math;
 import "testing/dart/http_server.dart";
 import "testing/dart/record_and_replay.dart";
 import "testing/dart/test_options.dart";
@@ -161,6 +162,12 @@
     // http://code.google.com/p/selenium/wiki/InternetExplorerDriver.
     if (conf['runtime'].startsWith('ie')) {
       maxBrowserProcesses = 1;
+    } else if (conf['runtime'].startsWith('safari') &&
+               conf['use_browser_controller']) {
+      // FIXME(kustermann/ricow): Remove this once the new browser_controller is
+      // stable.
+      maxBrowserProcesses = math.max(maxProcesses - 3, 1);
+      maxProcesses = math.max(maxProcesses -1, 1);
     }
 
     for (String key in selectors.keys) {
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index e632359..63c8164 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -1649,7 +1649,7 @@
   Future<BrowserTestRunner> _getBrowserTestRunner(TestCase test) {
     var local_ip = test.configuration['local_ip'];
     var runtime = test.configuration['runtime'];
-    var num_browsers = test.configuration['tasks'];
+    var num_browsers = _maxBrowserProcesses;
     if (_browserTestRunners[runtime] == null) {
       var testRunner =
         new BrowserTestRunner(local_ip, runtime, num_browsers);
diff --git a/tools/utils.py b/tools/utils.py
index 9ef6c2f..da42666 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -240,7 +240,8 @@
 
 def GetSVNRevision():
   p = subprocess.Popen(['svn', 'info'], stdout = subprocess.PIPE,
-      stderr = subprocess.STDOUT, shell=IsWindows())
+                       stderr = subprocess.STDOUT, shell=IsWindows(),
+                       env = {'LC_MESSAGES' : 'en_GB'})
   output, not_used = p.communicate()
   revision = ParseSvnInfoOutput(output)
   if revision: